mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 13:26:11 +08:00
sftp: remember entered password in AskPass mode
As reported in https://github.com/rclone/rclone/issues/4660#issuecomment-705502792 After switching to a password callback function, if the ssh connection aborts and needs to be reconnected then the user is-reprompted for their password. Instead we now remember the password they entered and just give that back. We do lose the ability for them to correct mistakes, but that's the situation from before switching to callbacks. We keep the benefits of not asking for passwords until the SSH connection succeeds (right known_hosts entry, for example). This required a small refactor of how `f := &Fs{}` was built, so we can store the saved password in the Fs object
This commit is contained in:
parent
7428e47ebc
commit
bbddadbd04
|
@ -235,6 +235,7 @@ type Fs struct {
|
|||
poolMu sync.Mutex
|
||||
pool []*conn
|
||||
pacer *fs.Pacer // pacer for operations
|
||||
savedpswd string
|
||||
}
|
||||
|
||||
// Object is a remote SFTP file that has been stat'd (so it exists, but is not necessarily open for reading)
|
||||
|
@ -413,6 +414,10 @@ func (f *Fs) putSftpConnection(pc **conn, err error) {
|
|||
// NewFs creates a new Fs object from the name and root. It connects to
|
||||
// the host specified in the config file.
|
||||
func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
|
||||
// This will hold the Fs object. We need to create it here
|
||||
// so we can refer to it in the SSH callback, but it's populated
|
||||
// in NewFsWithConnection
|
||||
f := &Fs{}
|
||||
ctx := context.Background()
|
||||
// Parse config into Options struct
|
||||
opt := new(Options)
|
||||
|
@ -566,33 +571,42 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
|
|||
// Config for password if none was defined and we're allowed to
|
||||
// We don't ask now; we ask if the ssh connection succeeds
|
||||
if opt.Pass == "" && opt.AskPassword {
|
||||
sshConfig.Auth = append(sshConfig.Auth, ssh.PasswordCallback(getPass))
|
||||
sshConfig.Auth = append(sshConfig.Auth, ssh.PasswordCallback(f.getPass))
|
||||
}
|
||||
|
||||
return NewFsWithConnection(ctx, name, root, m, opt, sshConfig)
|
||||
return NewFsWithConnection(ctx, f, name, root, m, opt, sshConfig)
|
||||
}
|
||||
|
||||
// If we're in password mode and ssh connection succeeds then this
|
||||
// callback is called
|
||||
func getPass() (string, error) {
|
||||
_, _ = fmt.Fprint(os.Stderr, "Enter SFTP password: ")
|
||||
return config.ReadPassword(), nil
|
||||
// callback is called. First time around we ask the user, and then
|
||||
// save it so on reconnection we give back the previous string.
|
||||
// This removes the ability to let the user correct a mistaken entry,
|
||||
// but means that reconnects are transparent.
|
||||
// We'll re-use config.Pass for this, 'cos we know it's not been
|
||||
// specified.
|
||||
func (f *Fs) getPass() (string, error) {
|
||||
for f.savedpswd == "" {
|
||||
_, _ = fmt.Fprint(os.Stderr, "Enter SFTP password: ")
|
||||
f.savedpswd = config.ReadPassword()
|
||||
}
|
||||
return f.savedpswd, nil
|
||||
}
|
||||
|
||||
// NewFsWithConnection creates a new Fs object from the name and root and an ssh.ClientConfig. It connects to
|
||||
// the host specified in the ssh.ClientConfig
|
||||
func NewFsWithConnection(ctx context.Context, name string, root string, m configmap.Mapper, opt *Options, sshConfig *ssh.ClientConfig) (fs.Fs, error) {
|
||||
f := &Fs{
|
||||
name: name,
|
||||
root: root,
|
||||
absRoot: root,
|
||||
opt: *opt,
|
||||
m: m,
|
||||
config: sshConfig,
|
||||
url: "sftp://" + opt.User + "@" + opt.Host + ":" + opt.Port + "/" + root,
|
||||
mkdirLock: newStringLock(),
|
||||
pacer: fs.NewPacer(pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
|
||||
}
|
||||
func NewFsWithConnection(ctx context.Context, f *Fs, name string, root string, m configmap.Mapper, opt *Options, sshConfig *ssh.ClientConfig) (fs.Fs, error) {
|
||||
// Populate the Filesystem Object
|
||||
f.name = name
|
||||
f.root = root
|
||||
f.absRoot = root
|
||||
f.opt = *opt
|
||||
f.m = m
|
||||
f.config = sshConfig
|
||||
f.url = "sftp://" + opt.User + "@" + opt.Host + ":" + opt.Port + "/" + root
|
||||
f.mkdirLock = newStringLock()
|
||||
f.pacer = fs.NewPacer(pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant)))
|
||||
f.savedpswd = ""
|
||||
|
||||
f.features = (&fs.Features{
|
||||
CanHaveEmptyDirectories: true,
|
||||
SlowHash: true,
|
||||
|
|
Loading…
Reference in New Issue
Block a user