diff --git a/go.mod b/go.mod index 8f84c0293..9521ded9b 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/google/go-querystring v1.0.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect - github.com/jlaffaye/ftp v0.0.0-20190411155707-52d3001130a6 + github.com/jlaffaye/ftp v0.0.0-20190519203911-8f5b34ce006f github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/koofr/go-httpclient v0.0.0-20180104120329-03786175608a github.com/koofr/go-koofrclient v0.0.0-20190131164641-7f327592caff diff --git a/go.sum b/go.sum index 0ed92d17f..33b68af63 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,10 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jlaffaye/ftp v0.0.0-20190411155707-52d3001130a6 h1:tAJSNnBx4ZAfMe8IuISVFsoS13fDJfb54k8/X5jGIfI= github.com/jlaffaye/ftp v0.0.0-20190411155707-52d3001130a6/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= +github.com/jlaffaye/ftp v0.0.0-20190427163646-6a014d5e22e6 h1:L8GOc4DyMAj4NyTq5He3pY/tfgLWcgwGXGnan5RWf1A= +github.com/jlaffaye/ftp v0.0.0-20190427163646-6a014d5e22e6/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= +github.com/jlaffaye/ftp v0.0.0-20190519203911-8f5b34ce006f h1:oUoY3Lvi7PD1F3CuayxfdJtwmKV7WNQBdXt8fK1breU= +github.com/jlaffaye/ftp v0.0.0-20190519203911-8f5b34ce006f/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= diff --git a/vendor/github.com/jlaffaye/ftp/README.md b/vendor/github.com/jlaffaye/ftp/README.md index 0ef7d6863..9059ddfaa 100644 --- a/vendor/github.com/jlaffaye/ftp/README.md +++ b/vendor/github.com/jlaffaye/ftp/README.md @@ -16,19 +16,19 @@ go get -u github.com/jlaffaye/ftp ## Example ## ```go -c, err := ftp.DialWithOptions("ftp.example.org", DialWithTimeout(5*time.Second)) +c, err := ftp.Dial("ftp.example.org:21", ftp.DialWithTimeout(5*time.Second)) if err != nil { - t.Fatal(err) + log.Fatal(err) } err = c.Login("anonymous", "anonymous") if err != nil { - t.Fatal(err) + log.Fatal(err) } // Do something with the FTP conn -if err := c.Close(); err != nil { - t.Fatal(err) +if err := c.Quit(); err != nil { + log.Fatal(err) } ``` diff --git a/vendor/github.com/jlaffaye/ftp/debug.go b/vendor/github.com/jlaffaye/ftp/debug.go new file mode 100644 index 000000000..864566cc7 --- /dev/null +++ b/vendor/github.com/jlaffaye/ftp/debug.go @@ -0,0 +1,21 @@ +package ftp + +import "io" + +type debugWrapper struct { + conn io.ReadWriteCloser + io.Reader + io.Writer +} + +func newDebugWrapper(conn io.ReadWriteCloser, w io.Writer) io.ReadWriteCloser { + return &debugWrapper{ + Reader: io.TeeReader(conn, w), + Writer: io.MultiWriter(w, conn), + conn: conn, + } +} + +func (w *debugWrapper) Close() error { + return w.conn.Close() +} diff --git a/vendor/github.com/jlaffaye/ftp/ftp.go b/vendor/github.com/jlaffaye/ftp/ftp.go index 13214e3e2..5bd19d2c0 100644 --- a/vendor/github.com/jlaffaye/ftp/ftp.go +++ b/vendor/github.com/jlaffaye/ftp/ftp.go @@ -40,7 +40,7 @@ type ServerConn struct { mlstSupported bool } -// DialOption represents an option to start a new connection with DialWithOptions +// DialOption represents an option to start a new connection with Dial type DialOption struct { setup func(do *dialOptions) } @@ -49,10 +49,12 @@ type DialOption struct { type dialOptions struct { context context.Context dialer net.Dialer - tlsConfig tls.Config + tlsConfig *tls.Config conn net.Conn disableEPSV bool location *time.Location + debugOutput io.Writer + dialFunc func(network, address string) (net.Conn, error) } // Entry describes a file and is returned by List(). @@ -70,8 +72,8 @@ type Response struct { closed bool } -// DialWithOptions connects to the specified address with optinal options -func DialWithOptions(addr string, options ...DialOption) (*ServerConn, error) { +// Dial connects to the specified address with optinal options +func Dial(addr string, options ...DialOption) (*ServerConn, error) { do := &dialOptions{} for _, option := range options { option.setup(do) @@ -83,27 +85,40 @@ func DialWithOptions(addr string, options ...DialOption) (*ServerConn, error) { tconn := do.conn if tconn == nil { - ctx := do.context + var err error - if ctx == nil { - ctx = context.Background() + if do.dialFunc != nil { + tconn, err = do.dialFunc("tcp", addr) + } else if do.tlsConfig != nil { + tconn, err = tls.DialWithDialer(&do.dialer , "tcp", addr, do.tlsConfig) + } else { + ctx := do.context + + if ctx == nil { + ctx = context.Background() + } + + tconn, err = do.dialer.DialContext(ctx, "tcp", addr) } - conn, err := do.dialer.DialContext(ctx, "tcp", addr) if err != nil { return nil, err } - tconn = conn } // Use the resolved IP address in case addr contains a domain name // If we use the domain name, we might not resolve to the same IP. remoteAddr := tconn.RemoteAddr().(*net.TCPAddr) + var sourceConn io.ReadWriteCloser = tconn + if do.debugOutput != nil { + sourceConn = newDebugWrapper(tconn, do.debugOutput) + } + c := &ServerConn{ options: do, features: make(map[string]string), - conn: textproto.NewConn(tconn), + conn: textproto.NewConn(sourceConn), host: remoteAddr.IP.String(), } @@ -172,28 +187,47 @@ func DialWithContext(ctx context.Context) DialOption { } // DialWithTLS returns a DialOption that configures the ServerConn with specified TLS config -func DialWithTLS(tlsConfig tls.Config) DialOption { +// +// If called together with the DialWithDialFunc option, the DialWithDialFunc function +// will be used when dialing new connections but regardless of the function, +// the connection will be treated as a TLS connection. +func DialWithTLS(tlsConfig *tls.Config) DialOption { return DialOption{func(do *dialOptions) { do.tlsConfig = tlsConfig }} } +// DialWithDebugOutput returns a DialOption that configures the ServerConn to write to the Writer +// everything it reads from the server +func DialWithDebugOutput(w io.Writer) DialOption { + return DialOption{func(do *dialOptions) { + do.debugOutput = w + }} +} + +// DialWithDialFunc returns a DialOption that configures the ServerConn to use the +// specified function to establish both control and data connections +// +// If used together with the DialWithNetConn option, the DialWithNetConn +// takes precedence for the control connection, while data connections will +// be established using function specified with the DialWithDialFunc option +func DialWithDialFunc(f func(network, address string) (net.Conn, error)) DialOption { + return DialOption{func(do *dialOptions) { + do.dialFunc = f + }} +} + // Connect is an alias to Dial, for backward compatibility func Connect(addr string) (*ServerConn, error) { return Dial(addr) } -// Dial is like DialTimeout with no timeout -func Dial(addr string) (*ServerConn, error) { - return DialTimeout(addr, 0) -} - // DialTimeout initializes the connection to the specified ftp server address. // // It is generally followed by a call to Login() as most FTP commands require // an authenticated user. func DialTimeout(addr string, timeout time.Duration) (*ServerConn, error) { - return DialWithOptions(addr, DialWithTimeout(timeout)) + return Dial(addr, DialWithTimeout(timeout)) } // Login authenticates the client with specified user and password. @@ -225,6 +259,12 @@ func (c *ServerConn) Login(user, password string) error { // Switch to UTF-8 err = c.setUTF8() + // If using implicit TLS, make data connections also use TLS + if c.options.tlsConfig != nil { + c.cmd(StatusCommandOK, "PBSZ 0") + c.cmd(StatusCommandOK, "PROT P") + } + return err } @@ -378,7 +418,20 @@ func (c *ServerConn) openDataConn() (net.Conn, error) { return nil, err } - return c.options.dialer.Dial("tcp", net.JoinHostPort(host, strconv.Itoa(port))) + addr := net.JoinHostPort(host, strconv.Itoa(port)) + if c.options.dialFunc != nil { + return c.options.dialFunc("tcp", addr) + } + + if c.options.tlsConfig != nil { + conn, err := c.options.dialer.Dial("tcp", addr) + if err != nil { + return nil, err + } + return tls.Client(conn, c.options.tlsConfig), err + } + + return c.options.dialer.Dial("tcp", addr) } // cmd is a helper function to execute a command and check for the expected FTP diff --git a/vendor/modules.txt b/vendor/modules.txt index be0510b94..5ea06f90a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -98,7 +98,7 @@ github.com/google/go-querystring/query github.com/hashicorp/golang-lru/simplelru # github.com/inconshreveable/mousetrap v1.0.0 github.com/inconshreveable/mousetrap -# github.com/jlaffaye/ftp v0.0.0-20190411155707-52d3001130a6 +# github.com/jlaffaye/ftp v0.0.0-20190519203911-8f5b34ce006f github.com/jlaffaye/ftp # github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath