From 938715336dcd9c69d706526b28fbabe49ff70fb6 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Sun, 17 Mar 2024 17:57:25 +0000 Subject: [PATCH 1/2] Add an auth command --- cmd/gh-slack/cmd/auth.go | 79 ++++++++++++++++++++++++++++++++++++++++ cmd/gh-slack/cmd/root.go | 20 +++++++++- cmd/gh-slack/cmd/send.go | 16 +------- 3 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 cmd/gh-slack/cmd/auth.go diff --git a/cmd/gh-slack/cmd/auth.go b/cmd/gh-slack/cmd/auth.go new file mode 100644 index 0000000..ed5d634 --- /dev/null +++ b/cmd/gh-slack/cmd/auth.go @@ -0,0 +1,79 @@ +package cmd + +import ( + "fmt" + "net/url" + + "github.com/cli/go-gh/pkg/config" + "github.com/rneatherway/slack" + "github.com/spf13/cobra" +) + +var authCmd = &cobra.Command{ + Use: "auth [flags]", + Short: "Prints authentication information for the Slack API", + Long: `Prints authentication information for the Slack API.`, + RunE: func(cmd *cobra.Command, args []string) error { + cfg, err := config.Read() + if err != nil { + return err + } + + team, err := getFlagOrElseConfig(cfg, cmd.Flags(), "team") + if err != nil { + return err + } + + auth, err := slack.GetCookieAuth(team) + if err != nil { + return err + } + + vals := url.Values{} + for k, v := range auth.Cookies { + vals.Add(k, v) + } + + fmt.Printf("export SLACK_TOKEN=%s\n", auth.Token) + fmt.Printf("export SLACK_COOKIES=%s\n", vals.Encode()) + return nil + }, + Example: ` gh-slack auth [-t ] + ` + configExample, +} + +func init() { + authCmd.Flags().StringP("team", "t", "", "Slack team name (required here or in config)") + authCmd.SetUsageTemplate(authCmdUsage) + authCmd.SetHelpTemplate(authCmdUsage) +} + +const authCmdUsage string = `Usage:{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}}{{end}}{{if gt (len .Aliases) 0}} +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} + +Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} + +{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} + +Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` diff --git a/cmd/gh-slack/cmd/root.go b/cmd/gh-slack/cmd/root.go index b417f36..6f8b95c 100644 --- a/cmd/gh-slack/cmd/root.go +++ b/cmd/gh-slack/cmd/root.go @@ -3,10 +3,25 @@ package cmd import ( "os" + "github.com/cli/go-gh/pkg/config" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) -const sendConfigExample = ` +func getFlagOrElseConfig(cfg *config.Config, flags *pflag.FlagSet, key string) (string, error) { + value, err := flags.GetString(key) + if err != nil { + return "", err + } + + if value != "" { + return value, nil + + } + return cfg.Get([]string{"extensions", "slack", key}) +} + +const configExample = ` # Example configuration (add to gh's configuration file at $HOME/.config/gh/config.yml): extensions: slack: @@ -25,7 +40,7 @@ var rootCmd = &cobra.Command{ gh-slack read -i gh-slack send -m -c -t gh-slack api post chat.postMessage -b '{"channel":"123","blocks":[...]} - ` + sendConfigExample, + ` + configExample, } func Execute() error { @@ -43,6 +58,7 @@ func init() { rootCmd.AddCommand(readCmd) rootCmd.AddCommand(sendCmd) rootCmd.AddCommand(apiCmd) + rootCmd.AddCommand(authCmd) rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Show verbose debug information") rootCmd.SetHelpTemplate(rootCmdUsageTemplate) rootCmd.SetUsageTemplate(rootCmdUsageTemplate) diff --git a/cmd/gh-slack/cmd/send.go b/cmd/gh-slack/cmd/send.go index 102e8b3..f5d0da4 100644 --- a/cmd/gh-slack/cmd/send.go +++ b/cmd/gh-slack/cmd/send.go @@ -8,22 +8,8 @@ import ( "github.com/cli/go-gh/pkg/config" "github.com/rneatherway/gh-slack/internal/slackclient" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) -func getFlagOrElseConfig(cfg *config.Config, flags *pflag.FlagSet, key string) (string, error) { - value, err := flags.GetString(key) - if err != nil { - return "", err - } - - if value != "" { - return value, nil - - } - return cfg.Get([]string{"extensions", "slack", key}) -} - var sendCmd = &cobra.Command{ Use: "send [flags]", Short: "Sends a message to a Slack channel", @@ -74,7 +60,7 @@ var sendCmd = &cobra.Command{ }, Example: ` gh-slack send -t -c -m -b gh-slack send -m -w # If bot is specified in config -` + sendConfigExample, +` + configExample, } // sendMessage sends a message to a Slack channel. From 4be4b987b4161b61bbd939f26614c43e1e5979d8 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Tue, 19 Mar 2024 19:03:27 +0000 Subject: [PATCH 2/2] Improve help output --- cmd/gh-slack/cmd/auth.go | 39 ++++++++++++++++++++++++--------------- cmd/gh-slack/cmd/root.go | 5 +++-- cmd/gh-slack/cmd/send.go | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/cmd/gh-slack/cmd/auth.go b/cmd/gh-slack/cmd/auth.go index ed5d634..9803456 100644 --- a/cmd/gh-slack/cmd/auth.go +++ b/cmd/gh-slack/cmd/auth.go @@ -11,8 +11,8 @@ import ( var authCmd = &cobra.Command{ Use: "auth [flags]", - Short: "Prints authentication information for the Slack API", - Long: `Prints authentication information for the Slack API.`, + Short: "Prints authentication information for the Slack API (treat output as secret)", + Long: "Prints authentication information for the Slack API (treat output as secret).", RunE: func(cmd *cobra.Command, args []string) error { cfg, err := config.Read() if err != nil { @@ -38,33 +38,42 @@ var authCmd = &cobra.Command{ fmt.Printf("export SLACK_COOKIES=%s\n", vals.Encode()) return nil }, - Example: ` gh-slack auth [-t ] - ` + configExample, + Example: ` eval $(gh-slack auth [-t ]) + + # Example configuration (add to gh's configuration file at $HOME/.config/gh/config.yml): + extensions: + slack: + team: foo`, } func init() { authCmd.Flags().StringP("team", "t", "", "Slack team name (required here or in config)") - authCmd.SetUsageTemplate(authCmdUsage) - authCmd.SetHelpTemplate(authCmdUsage) + authCmd.SetHelpTemplate(authCmdUsageTemplate) + authCmd.SetUsageTemplate(authCmdUsageTemplate) } -const authCmdUsage string = `Usage:{{if .Runnable}} - {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} - {{.CommandPath}}{{end}}{{if gt (len .Aliases) 0}} +const authCmdUsageTemplate string = `Usage:{{if .Runnable}} +{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} +{{.CommandPath}}{{end}}{{if gt (len .Aliases) 0}} Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} +{{.NameAndAliases}}{{end}}{{if .HasExample}} + +Security: + Treat the output of this command as secret and do not share it with anyone! + It can be used to impersonate you. If you suspect it has been compromised, + log out of the Slack app to revoke the token and cookies. Examples: {{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} -Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} +Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand)}} +{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} {{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} +{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} +{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} @@ -73,7 +82,7 @@ Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} +{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} ` diff --git a/cmd/gh-slack/cmd/root.go b/cmd/gh-slack/cmd/root.go index 6f8b95c..2590895 100644 --- a/cmd/gh-slack/cmd/root.go +++ b/cmd/gh-slack/cmd/root.go @@ -21,7 +21,7 @@ func getFlagOrElseConfig(cfg *config.Config, flags *pflag.FlagSet, key string) ( return cfg.Get([]string{"extensions", "slack", key}) } -const configExample = ` +const sendConfigEample = ` # Example configuration (add to gh's configuration file at $HOME/.config/gh/config.yml): extensions: slack: @@ -40,7 +40,8 @@ var rootCmd = &cobra.Command{ gh-slack read -i gh-slack send -m -c -t gh-slack api post chat.postMessage -b '{"channel":"123","blocks":[...]} - ` + configExample, + eval $(gh-slack auth -t ) + ` + sendConfigEample, } func Execute() error { diff --git a/cmd/gh-slack/cmd/send.go b/cmd/gh-slack/cmd/send.go index f5d0da4..964ab91 100644 --- a/cmd/gh-slack/cmd/send.go +++ b/cmd/gh-slack/cmd/send.go @@ -60,7 +60,7 @@ var sendCmd = &cobra.Command{ }, Example: ` gh-slack send -t -c -m -b gh-slack send -m -w # If bot is specified in config -` + configExample, +` + sendConfigEample, } // sendMessage sends a message to a Slack channel.