github.com/puellanivis/breton@v0.2.16/lib/files/sftpfiles/sftpfiles.go (about) 1 package sftpfiles 2 3 import ( 4 "context" 5 "net/url" 6 "os" 7 "path/filepath" 8 "sync" 9 10 "github.com/puellanivis/breton/lib/files" 11 "github.com/puellanivis/breton/lib/os/user" 12 13 "golang.org/x/crypto/ssh" 14 "golang.org/x/crypto/ssh/knownhosts" 15 ) 16 17 type filesystem struct { 18 once sync.Once 19 20 agent *Agent 21 auths []ssh.AuthMethod 22 knownhosts ssh.HostKeyCallback 23 24 mu sync.Mutex 25 hosts map[string]*Host 26 } 27 28 func (fs *filesystem) lazyInit() { 29 if agent, err := GetAgent(); err == nil && agent != nil { 30 fs.agent = agent 31 fs.auths = append(fs.auths, ssh.PublicKeysCallback(agent.Signers)) 32 } 33 34 if home, err := user.CurrentHomeDir(); err == nil { 35 filename := filepath.Join(home, ".ssh", "known_hosts") 36 37 if cb, err := knownhosts.New(filename); err == nil { 38 fs.knownhosts = cb 39 } 40 } 41 } 42 43 func init() { 44 fs := &filesystem{ 45 hosts: make(map[string]*Host), 46 } 47 48 files.RegisterScheme(fs, "sftp", "scp") 49 } 50 51 func (fs *filesystem) getHost(uri *url.URL) *Host { 52 fs.once.Do(fs.lazyInit) 53 54 h := NewHost(uri) 55 56 fs.mu.Lock() 57 defer fs.mu.Unlock() 58 59 key := h.Name() 60 61 if h := fs.hosts[key]; h != nil { 62 return h 63 } 64 65 _ = h.addAuths(fs.auths...) 66 _, _ = h.SetHostKeyCallback(fs.knownhosts, nil) 67 68 fs.hosts[key] = h 69 70 return h 71 } 72 73 func (fs *filesystem) List(ctx context.Context, uri *url.URL) ([]os.FileInfo, error) { 74 h := fs.getHost(uri) 75 76 cl, err := h.Connect() 77 if err != nil { 78 return nil, files.PathError("connect", h.Name(), err) 79 } 80 81 fi, err := cl.ReadDir(uri.Path) 82 if err != nil { 83 fixURL := *uri 84 fixURL.Host = h.uri.Host 85 fixURL.User = h.uri.User 86 87 return nil, files.PathError("readdir", fixURL.String(), err) 88 } 89 90 return fi, nil 91 }