diff --git a/cmd/serve/ftp/ftp.go b/cmd/serve/ftp/ftp.go index c7de78a5b..1bd42bd53 100644 --- a/cmd/serve/ftp/ftp.go +++ b/cmd/serve/ftp/ftp.go @@ -16,19 +16,52 @@ import ( ftp "github.com/goftp/server" "github.com/rclone/rclone/cmd" - "github.com/rclone/rclone/cmd/serve/ftp/ftpflags" - "github.com/rclone/rclone/cmd/serve/ftp/ftpopt" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/accounting" + "github.com/rclone/rclone/fs/config/flags" "github.com/rclone/rclone/fs/log" + "github.com/rclone/rclone/fs/rc" "github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs/vfsflags" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) +// Options contains options for the http Server +type Options struct { + //TODO add more options + ListenAddr string // Port to listen on + PublicIP string // Passive ports range + PassivePorts string // Passive ports range + BasicUser string // single username for basic auth if not using Htpasswd + BasicPass string // password for BasicUser +} + +// DefaultOpt is the default values used for Options +var DefaultOpt = Options{ + ListenAddr: "localhost:2121", + PublicIP: "", + PassivePorts: "30000-32000", + BasicUser: "anonymous", + BasicPass: "", +} + +// Opt is options set by command line flags +var Opt = DefaultOpt + +// AddFlags adds flags for ftp +func AddFlags(flagSet *pflag.FlagSet) { + rc.AddOption("ftp", &Opt) + flags.StringVarP(flagSet, &Opt.ListenAddr, "addr", "", Opt.ListenAddr, "IPaddress:Port or :Port to bind server to.") + flags.StringVarP(flagSet, &Opt.PublicIP, "public-ip", "", Opt.PublicIP, "Public IP address to advertise for passive connections.") + flags.StringVarP(flagSet, &Opt.PassivePorts, "passive-port", "", Opt.PassivePorts, "Passive port range to use.") + flags.StringVarP(flagSet, &Opt.BasicUser, "user", "", Opt.BasicUser, "User name for authentication.") + flags.StringVarP(flagSet, &Opt.BasicPass, "pass", "", Opt.BasicPass, "Password for authentication. (empty value allow every password)") +} + func init() { - ftpflags.AddFlags(Command.Flags()) vfsflags.AddFlags(Command.Flags()) + AddFlags(Command.Flags()) } // Command definition for cobra @@ -39,12 +72,28 @@ var Command = &cobra.Command{ rclone serve ftp implements a basic ftp server to serve the remote over FTP protocol. This can be viewed with a ftp client or you can make a remote of type ftp to read and write it. -` + ftpopt.Help + vfs.Help, + +### Server options + +Use --addr to specify which IP address and port the server should +listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all +IPs. By default it only listens on localhost. You can use port +:0 to let the OS choose an available port. + +If you set --addr to listen on a public or LAN accessible IP address +then using Authentication is advised - see the next section for info. + +#### Authentication + +By default this will serve files without needing a login. + +You can set a single username and password with the --user and --pass flags. +` + vfs.Help, Run: func(command *cobra.Command, args []string) { cmd.CheckArgs(1, 1, command, args) f := cmd.NewFsSrc(args) cmd.Run(false, false, command, func() error { - s, err := newServer(f, &ftpflags.Opt) + s, err := newServer(f, &Opt) if err != nil { return err } @@ -57,10 +106,11 @@ or you can make a remote of type ftp to read and write it. type server struct { f fs.Fs srv *ftp.Server + opt Options } // Make a new FTP to serve the remote -func newServer(f fs.Fs, opt *ftpopt.Options) (*server, error) { +func newServer(f fs.Fs, opt *Options) (*server, error) { host, port, err := net.SplitHostPort(opt.ListenAddr) if err != nil { return nil, errors.New("Failed to parse host:port") @@ -70,6 +120,10 @@ func newServer(f fs.Fs, opt *ftpopt.Options) (*server, error) { return nil, errors.New("Failed to parse host:port") } + s := &server{ + f: f, + opt: *opt, + } ftpopt := &ftp.ServerOpts{ Name: "Rclone FTP Server", WelcomeMessage: "Welcome on Rclone FTP Server", @@ -80,17 +134,12 @@ func newServer(f fs.Fs, opt *ftpopt.Options) (*server, error) { Port: portNum, PublicIp: opt.PublicIP, PassivePorts: opt.PassivePorts, - Auth: &Auth{ - BasicUser: opt.BasicUser, - BasicPass: opt.BasicPass, - }, - Logger: &Logger{}, + Auth: &Auth{s}, + Logger: &Logger{}, //TODO implement a maximum of https://godoc.org/github.com/goftp/server#ServerOpts } - return &server{ - f: f, - srv: ftp.NewServer(ftpopt), - }, nil + s.srv = ftp.NewServer(ftpopt) + return s, nil } // serve runs the ftp server @@ -134,13 +183,12 @@ func (l *Logger) PrintResponse(sessionID string, code int, message string) { //Auth struct to handle ftp auth (temporary simple for POC) type Auth struct { - BasicUser string - BasicPass string + s *server } //CheckPasswd handle auth based on configuration func (a *Auth) CheckPasswd(user, pass string) (bool, error) { - return a.BasicUser == user && (a.BasicPass == "" || a.BasicPass == pass), nil + return a.s.opt.BasicUser == user && (a.s.opt.BasicPass == "" || a.s.opt.BasicPass == pass), nil } //DriverFactory factory of ftp driver for each session diff --git a/cmd/serve/ftp/ftp_test.go b/cmd/serve/ftp/ftp_test.go index d424548c2..9500d0e39 100644 --- a/cmd/serve/ftp/ftp_test.go +++ b/cmd/serve/ftp/ftp_test.go @@ -16,7 +16,6 @@ import ( ftp "github.com/goftp/server" _ "github.com/rclone/rclone/backend/local" - "github.com/rclone/rclone/cmd/serve/ftp/ftpopt" "github.com/rclone/rclone/fstest" "github.com/stretchr/testify/assert" ) @@ -30,7 +29,7 @@ const ( // TestFTP runs the ftp server then runs the unit tests for the // ftp remote against it. func TestFTP(t *testing.T) { - opt := ftpopt.DefaultOpt + opt := DefaultOpt opt.ListenAddr = testHOST + ":" + testPORT opt.PassivePorts = testPASSIVEPORTRANGE opt.BasicUser = "rclone" diff --git a/cmd/serve/ftp/ftpflags/ftpflags.go b/cmd/serve/ftp/ftpflags/ftpflags.go deleted file mode 100644 index 9ef62b1c9..000000000 --- a/cmd/serve/ftp/ftpflags/ftpflags.go +++ /dev/null @@ -1,28 +0,0 @@ -package ftpflags - -import ( - "github.com/rclone/rclone/cmd/serve/ftp/ftpopt" - "github.com/rclone/rclone/fs/config/flags" - "github.com/rclone/rclone/fs/rc" - "github.com/spf13/pflag" -) - -// Options set by command line flags -var ( - Opt = ftpopt.DefaultOpt -) - -// AddFlagsPrefix adds flags for the ftpopt -func AddFlagsPrefix(flagSet *pflag.FlagSet, prefix string, Opt *ftpopt.Options) { - rc.AddOption("ftp", &Opt) - flags.StringVarP(flagSet, &Opt.ListenAddr, prefix+"addr", "", Opt.ListenAddr, "IPaddress:Port or :Port to bind server to.") - flags.StringVarP(flagSet, &Opt.PublicIP, prefix+"public-ip", "", Opt.PublicIP, "Public IP address to advertise for passive connections.") - flags.StringVarP(flagSet, &Opt.PassivePorts, prefix+"passive-port", "", Opt.PassivePorts, "Passive port range to use.") - flags.StringVarP(flagSet, &Opt.BasicUser, prefix+"user", "", Opt.BasicUser, "User name for authentication.") - flags.StringVarP(flagSet, &Opt.BasicPass, prefix+"pass", "", Opt.BasicPass, "Password for authentication. (empty value allow every password)") -} - -// AddFlags adds flags for the httplib -func AddFlags(flagSet *pflag.FlagSet) { - AddFlagsPrefix(flagSet, "", &Opt) -} diff --git a/cmd/serve/ftp/ftpopt/ftp_options.go b/cmd/serve/ftp/ftpopt/ftp_options.go deleted file mode 100644 index 4101a64ec..000000000 --- a/cmd/serve/ftp/ftpopt/ftp_options.go +++ /dev/null @@ -1,40 +0,0 @@ -package ftpopt - -// Help contains text describing the http server to add to the command -// help. -var Help = ` -### Server options - -Use --addr to specify which IP address and port the server should -listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all -IPs. By default it only listens on localhost. You can use port -:0 to let the OS choose an available port. - -If you set --addr to listen on a public or LAN accessible IP address -then using Authentication is advised - see the next section for info. - -#### Authentication - -By default this will serve files without needing a login. - -You can set a single username and password with the --user and --pass flags. -` - -// Options contains options for the http Server -type Options struct { - //TODO add more options - ListenAddr string // Port to listen on - PublicIP string // Passive ports range - PassivePorts string // Passive ports range - BasicUser string // single username for basic auth if not using Htpasswd - BasicPass string // password for BasicUser -} - -// DefaultOpt is the default values used for Options -var DefaultOpt = Options{ - ListenAddr: "localhost:2121", - PublicIP: "", - PassivePorts: "30000-32000", - BasicUser: "anonymous", - BasicPass: "", -}