diff --git a/cmd/lscp/args.go b/cmd/lscp/args.go index 2e09c9a8..d218cf37 100644 --- a/cmd/lscp/args.go +++ b/cmd/lscp/args.go @@ -58,7 +58,7 @@ USAGE: app.Name = "lscp" app.Usage = "TUI list select and parallel scp client command." app.Copyright = "blacknon(blacknon@orebibou.com)" - app.Version = "0.6.12" + app.Version = "0.6.13" // options // TODO(blacknon): オプションの追加(0.7.0) diff --git a/cmd/lsftp/args.go b/cmd/lsftp/args.go index 2c8af55a..8467c2bd 100644 --- a/cmd/lsftp/args.go +++ b/cmd/lsftp/args.go @@ -50,7 +50,7 @@ USAGE: app.Name = "lsftp" app.Usage = "TUI list select and parallel sftp client command." app.Copyright = "blacknon(blacknon@orebibou.com)" - app.Version = "0.6.12" + app.Version = "0.6.13" app.Flags = []cli.Flag{ cli.StringFlag{Name: "file,F", Value: defConf, Usage: "config file path"}, diff --git a/cmd/lssh/args.go b/cmd/lssh/args.go index d17562ba..9b7a58f6 100644 --- a/cmd/lssh/args.go +++ b/cmd/lssh/args.go @@ -59,7 +59,7 @@ USAGE: app.Name = "lssh" app.Usage = "TUI list select and parallel ssh client command." app.Copyright = "blacknon(blacknon@orebibou.com)" - app.Version = "0.6.12" + app.Version = "0.6.13" // TODO(blacknon): オプションの追加 // -T ... マウント・リバースマウントのTypeを指定できるようにする(v0.7.0) diff --git a/go.mod b/go.mod index abd029e2..15c0c9ea 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect github.com/blacknon/crypto11 v1.2.7 // indirect - github.com/blacknon/go-sshlib v0.1.16 + github.com/blacknon/go-sshlib v0.1.18 github.com/blacknon/go-x11auth v0.1.0 // indirect github.com/blacknon/textcol v0.0.1 github.com/c-bata/go-prompt v0.2.6 diff --git a/go.sum b/go.sum index 88d4ef5a..e75b0a79 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/blacknon/go-nfs-sshlib v0.0.3 h1:tq83kTZibrr99/GCn0pqkJhmBTDMupL/eMI3 github.com/blacknon/go-nfs-sshlib v0.0.3/go.mod h1:jaCmHgFoj8j08rGrBnhJ4nFO7nUWs4xFrUd2vEPwyx8= github.com/blacknon/go-prompt v0.2.7 h1:dVdTqVplKvpT/k4bB9BlbcBYl/k6amYX5tvjYBmuKkI= github.com/blacknon/go-prompt v0.2.7/go.mod h1:zNBmC/BPAyr+3ey1oRhPxuXJS9zz1lEmJpwaoQroe3w= -github.com/blacknon/go-sshlib v0.1.16 h1:de5KXEYalMzknPWwSbKEr/Z3CxgOfMyiQC5+sfzYwLg= -github.com/blacknon/go-sshlib v0.1.16/go.mod h1:upfnjVHf/Lh7ysT3dU1ziHKtzRQ1J62JyrShZ7FlNSI= +github.com/blacknon/go-sshlib v0.1.18 h1:gzkplZuAH2aHARng2YbiEjzGufZomPdGoMQuqmdA2R0= +github.com/blacknon/go-sshlib v0.1.18/go.mod h1:DN5Vkl/FpEzVxGoS0p8uBsBoHpVywiHbALr9UxcfJxw= github.com/blacknon/go-x11auth v0.1.0 h1:SnljCPWcvglWeGAlKc1RAPMHnOfMpM9+GrTGEUQ1lqQ= github.com/blacknon/go-x11auth v0.1.0/go.mod h1:SKOCa19LluXHyB+OaLYobquzceE0SWxVW7e/qU5xGBM= github.com/blacknon/textcol v0.0.1 h1:x9h7yLPGyr8Pdz12XJ30h7Iz5mJlKd0CzfGYxhrmnk8= diff --git a/list/event.go b/list/event.go index 929fc98d..4e6a718c 100644 --- a/list/event.go +++ b/list/event.go @@ -150,8 +150,9 @@ func (l *ListInfo) keyEvent() (lineData []string) { // mouse select line is (ev.MouseY - headLine) line. mouseSelectLine := ev.MouseY - headLine - if mouseSelectLine <= len(l.ViewText)-headLine { - l.CursorLine = mouseSelectLine + pageOffset := (l.CursorLine / height) * height + if mouseSelectLine >= 0 && mouseSelectLine < height && pageOffset+mouseSelectLine < len(l.ViewText) { + l.CursorLine = pageOffset + mouseSelectLine } l.draw() } diff --git a/ssh/connect.go b/ssh/connect.go index f55a2f8b..70a23371 100644 --- a/ssh/connect.go +++ b/ssh/connect.go @@ -10,6 +10,7 @@ import ( "github.com/blacknon/go-sshlib" "github.com/blacknon/lssh/conf" + "golang.org/x/crypto/ssh" "golang.org/x/net/proxy" ) @@ -98,7 +99,15 @@ func (r *Run) CreateSshConnect(server string) (connect *sshlib.Connect, err erro err = connect.CreateClient(s.Addr, s.Port, s.User, r.serverAuthMethodMap[server]) - return + if err != nil { + if client, ok := dialer.(*ssh.Client); ok { + client.Close() + } + + return nil, err + } + + return connect, nil } // proxy struct diff --git a/vendor/github.com/blacknon/go-sshlib/cmd.go b/vendor/github.com/blacknon/go-sshlib/cmd.go index 89e5a681..7018ca6a 100644 --- a/vendor/github.com/blacknon/go-sshlib/cmd.go +++ b/vendor/github.com/blacknon/go-sshlib/cmd.go @@ -24,35 +24,52 @@ func (c *Connect) Command(command string) (err error) { } defer func() { c.Session = nil }() - // setup options - err = c.setOption(c.Session) - if err != nil { - return - } - - // Set Stdin, Stdout, Stderr... - if c.Stdin != nil { + // Set Stdin + switch { + case c.Stdin != nil: w, _ := c.Session.StdinPipe() go io.Copy(w, c.Stdin) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stdin = c.PtyRelayTty + + default: stdin := GetStdin() c.Session.Stdin = stdin } - if c.Stdout != nil { + // Set Stdout + switch { + case c.Stdout != nil: or, _ := c.Session.StdoutPipe() go io.Copy(c.Stdout, or) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stdout = c.PtyRelayTty + + default: c.Session.Stdout = os.Stdout } - if c.Stderr != nil { + // Set Stderr + switch { + case c.Stderr != nil: er, _ := c.Session.StderrPipe() go io.Copy(c.Stderr, er) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stderr = c.PtyRelayTty + + default: c.Session.Stderr = os.Stderr } + // setup options + err = c.setOption(c.Session) + if err != nil { + return + } + // Run Command c.Session.Run(command) diff --git a/vendor/github.com/blacknon/go-sshlib/connect.go b/vendor/github.com/blacknon/go-sshlib/connect.go index 2d6d2e51..d55b211f 100644 --- a/vendor/github.com/blacknon/go-sshlib/connect.go +++ b/vendor/github.com/blacknon/go-sshlib/connect.go @@ -50,6 +50,9 @@ type Connect struct { // Set it before CraeteClient. ForwardAgent bool + // Set the TTY to be used as the input and output for the Session/Cmd. + PtyRelayTty *os.File + // CheckKnownHosts if true, check knownhosts. // Ignored if HostKeyCallback is set. // Set it before CraeteClient. @@ -190,36 +193,37 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { interval = c.SendKeepAliveInterval } + max := 3 + if c.SendKeepAliveMax > 0 { + max = c.SendKeepAliveMax + } + + t := time.NewTicker(time.Duration(c.ConnectTimeout) * time.Second) + defer t.Stop() + + count := 0 for { - // timeout channel - tc := make(chan bool, 1) - - go func() { - // Send keep alive packet - _, err := session.SendRequest("keepalive", true, nil) - if err == nil { - tc <- true + select { + case <-t.C: + if _, err := session.SendRequest("keepalive@openssh.com", true, nil); err != nil { + log.Println("Failed to send keepalive packet:", err) + count += 1 + } else { + // err is nil. + time.Sleep(time.Duration(interval) * time.Second) } - }() + } - select { - case <-tc: - case <-time.After(time.Duration(c.ConnectTimeout) * time.Second): - session.Close() - c.Client.Close() - log.Println("keepalive timeout") + if count > max { return } - - // sleep - time.Sleep(time.Duration(interval) * time.Second) } } // CheckClientAlive check alive ssh.Client. func (c *Connect) CheckClientAlive() error { _, _, err := c.Client.SendRequest("keepalive", true, nil) - if err == nil || err.Error() == "request failed" { + if err == nil { return nil } return err diff --git a/vendor/github.com/blacknon/go-sshlib/nfs_forward.go b/vendor/github.com/blacknon/go-sshlib/nfs_forward.go index 54e4fd55..5653817d 100644 --- a/vendor/github.com/blacknon/go-sshlib/nfs_forward.go +++ b/vendor/github.com/blacknon/go-sshlib/nfs_forward.go @@ -5,7 +5,9 @@ package sshlib import ( + "fmt" "net" + "strings" nfs "github.com/blacknon/go-nfs-sshlib" nfshelper "github.com/blacknon/go-nfs-sshlib/helpers" @@ -26,6 +28,14 @@ func (c *Connect) NFSForward(address, port, basepoint string) (err error) { return } + // create abs path + homepoint, err := client.RealPath(".") + if err != nil { + return + } + basepoint = getRemoteAbsPath(homepoint, basepoint) + fmt.Println(basepoint) + sftpfsPlusChange := NewChangeSFTPFS(client, basepoint) handler := nfshelper.NewNullAuthHandler(sftpfsPlusChange) @@ -58,3 +68,12 @@ func (c *Connect) NFSReverseForward(address, port, sharepoint string) (err error return } + +func getRemoteAbsPath(wdpath, path string) (result string) { + result = strings.Replace(path, "~", wdpath, 1) + if !strings.HasPrefix(result, "/") { + result = wdpath + "/" + result + } + + return result +} diff --git a/vendor/github.com/blacknon/go-sshlib/nfs_sftpfs.go b/vendor/github.com/blacknon/go-sshlib/nfs_sftpfs.go index 45ae926a..da8b6b93 100644 --- a/vendor/github.com/blacknon/go-sshlib/nfs_sftpfs.go +++ b/vendor/github.com/blacknon/go-sshlib/nfs_sftpfs.go @@ -5,6 +5,7 @@ package sshlib import ( + "fmt" "os" "path/filepath" "strconv" @@ -47,30 +48,25 @@ type SFTPFS struct { // Create func (fs *SFTPFS) Create(filename string) (billy.File, error) { - _, err := fs.Stat(filename) - if err == nil { - return nil, os.ErrExist - } - - dir := filepath.Dir(filename) - err = fs.MkdirAll(dir, os.ModeDir) - if err != nil { - return nil, err - } - - f, err := fs.Client.Create(filename) - if err != nil { - return nil, err - } - return &sftpFile{File: f}, nil + return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) } // OpenFile func (fs *SFTPFS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) { - // TODO: create dirをする - // https://github.com/src-d/go-billy/blob/master/osfs/os.go#L31-L54 + return fs.openFile(filename, flag, perm, fs.createDir) +} + +func (fs *SFTPFS) openFile(fn string, flag int, perm os.FileMode, createDir func(string) error) (billy.File, error) { + if flag&os.O_CREATE != 0 { + if createDir == nil { + return nil, fmt.Errorf("createDir func cannot be nil if file needs to be opened in create mode") + } + if err := createDir(fn); err != nil { + return nil, err + } + } - f, err := fs.Client.OpenFile(filename, flag) + f, err := fs.Client.OpenFile(fn, flag) if err != nil { return nil, err } diff --git a/vendor/github.com/blacknon/go-sshlib/proxy.go b/vendor/github.com/blacknon/go-sshlib/proxy.go index 59eb0a17..732cedf5 100644 --- a/vendor/github.com/blacknon/go-sshlib/proxy.go +++ b/vendor/github.com/blacknon/go-sshlib/proxy.go @@ -191,6 +191,12 @@ func (n *NetPipe) Dial(network, addr string) (con net.Conn, err error) { // Start the command err = n.Cmd.Start() + // Close the write end of the pipe + go func() { + n.Cmd.Wait() + srv.Close() + }() + return } diff --git a/vendor/github.com/blacknon/go-sshlib/shell.go b/vendor/github.com/blacknon/go-sshlib/shell.go index e9379a58..a1859471 100644 --- a/vendor/github.com/blacknon/go-sshlib/shell.go +++ b/vendor/github.com/blacknon/go-sshlib/shell.go @@ -20,7 +20,13 @@ import ( // Shell connect login shell over ssh. func (c *Connect) Shell(session *ssh.Session) (err error) { // Input terminal Make raw - fd := int(os.Stdin.Fd()) + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdin.Fd()) + } + state, err := terminal.MakeRaw(fd) if err != nil { return @@ -33,6 +39,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { return } + // set tty + if c.PtyRelayTty != nil { + session.Stdin = c.PtyRelayTty + session.Stdout = c.PtyRelayTty + session.Stderr = c.PtyRelayTty + } + // Start shell err = session.Shell() if err != nil { @@ -42,6 +55,11 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { // keep alive packet go c.SendKeepAlive(session) + // if tty is set, get signal winch + if c.PtyRelayTty != nil { + go c.ChangeWinSize(session) + } + err = session.Wait() if err != nil { return @@ -54,7 +72,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { // Used to start a shell with a specified command. func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { // Input terminal Make raw - fd := int(os.Stdin.Fd()) + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdin.Fd()) + } + state, err := terminal.MakeRaw(fd) if err != nil { return @@ -67,6 +91,13 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { return } + // set tty + if c.PtyRelayTty != nil { + session.Stdin = c.PtyRelayTty + session.Stdout = c.PtyRelayTty + session.Stderr = c.PtyRelayTty + } + // Start shell err = session.Start(command) if err != nil { @@ -84,6 +115,23 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { return } +func (c *Connect) ChangeWinSize(session *ssh.Session) { + // Get terminal window size + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdout.Fd()) + } + width, height, err := terminal.GetSize(fd) + if err != nil { + return + } + + // Send window size + session.WindowChange(height, width) +} + // SetLog set up terminal log logging. // This only happens in Connect.Shell(). func (c *Connect) SetLog(path string, timestamp bool) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 3fc60ccb..82df86ff 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -25,7 +25,7 @@ github.com/blacknon/crypto11 github.com/blacknon/go-nfs-sshlib github.com/blacknon/go-nfs-sshlib/file github.com/blacknon/go-nfs-sshlib/helpers -# github.com/blacknon/go-sshlib v0.1.16 +# github.com/blacknon/go-sshlib v0.1.18 ## explicit; go 1.22.4 github.com/blacknon/go-sshlib # github.com/blacknon/go-x11auth v0.1.0