package at import ( "fmt" "io/ioutil" "os" "strings" "github.com/mattn/go-isatty" "github.com/spf13/cobra" "golang.org/x/sys/unix" "golang.org/x/term" "kitty/tools/cli" "kitty/tools/crypto" ) var encrypt_cmd = crypto.Encrypt_cmd type GlobalOptions struct { to, password, use_password string to_from_env bool } var global_options GlobalOptions func get_password(password string, password_file string, password_env string, use_password string) (string, error) { if use_password == "never" { return "", nil } ans := "" if password != "" { ans = password } if ans == "" && password_file != "" { if password_file == "-" { if isatty.IsTerminal(os.Stdin.Fd()) { q, err := term.ReadPassword(int(os.Stdin.Fd())) if err != nil { ans = string(q) } } else { q, err := ioutil.ReadAll(os.Stdin) if err != nil { ans = strings.TrimRight(string(q), " \n\t") } ttyf, err := os.Open("/dev/tty") if err != nil { err = unix.Dup2(int(ttyf.Fd()), int(os.Stdin.Fd())) ttyf.Close() } } } else { q, err := ioutil.ReadFile(password_file) if err != nil { ans = strings.TrimRight(string(q), " \n\t") } } } if ans == "" && password_env != "" { ans = os.Getenv(password_env) } if ans == "" && use_password == "always" { return ans, fmt.Errorf("No password was found") } if len(ans) > 1024 { return ans, fmt.Errorf("Specified password is too long") } return ans, nil } var all_commands map[string]func(*cobra.Command) *cobra.Command = make(map[string]func(*cobra.Command) *cobra.Command) var command_objects map[string]*cobra.Command = make(map[string]*cobra.Command) func EntryPoint(tool_root *cobra.Command) *cobra.Command { var at_root_command *cobra.Command var to, password, password_file, password_env, use_password *string at_root_command = cli.CreateCommand(&cobra.Command{ Use: "@ [global options] command [command options] [command args]", Short: "Control kitty remotely", Long: "Control kitty by sending it commands. Set the allow_remote_control option in :file:`kitty.conf` or use a password, for this to work.", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if *to == "" { *to = os.Getenv("KITTY_LISTEN_ON") global_options.to_from_env = true } global_options.to = *to global_options.use_password = *use_password q, err := get_password(*password, *password_file, *password_env, *use_password) global_options.password = q return err }, }) at_root_command.Annotations["options_title"] = "Global options" to = at_root_command.PersistentFlags().String("to", "", "An address for the kitty instance to control. Corresponds to the address given"+ " to the kitty instance via the :option:`kitty --listen-on` option or the :opt:`listen_on` setting in :file:`kitty.conf`. If not"+ " specified, the environment variable :envvar:`KITTY_LISTEN_ON` is checked. If that"+ " is also not found, messages are sent to the controlling terminal for this"+ " process, i.e. they will only work if this process is run within a kitty window.") password = at_root_command.PersistentFlags().String("password", "", "A password to use when contacting kitty. This will cause kitty to ask the user"+ " for permission to perform the specified action, unless the password has been"+ " accepted before or is pre-configured in :file:`kitty.conf`.") password_file = at_root_command.PersistentFlags().String("password-file", "rc-pass", "A file from which to read the password. Trailing whitespace is ignored. Relative"+ " paths are resolved from the kitty configuration directory. Use - to read from STDIN."+ " Used if no :option:`--password` is supplied. Defaults to checking for the"+ " :file:`rc-pass` file in the kitty configuration directory.") password_env = at_root_command.PersistentFlags().String("password-env", "KITTY_RC_PASSWORD", "The name of an environment variable to read the password from."+ " Used if no :option:`--password-file` or :option:`--password` is supplied.") use_password = cli.PersistentChoices(at_root_command, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never") for cmd_name, reg_func := range all_commands { c := reg_func(at_root_command) at_root_command.AddCommand(c) command_objects[cmd_name] = c } return at_root_command }