mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-21 23:20:24 +00:00
parent
99cd1ccfe5
commit
0609188d3f
9 changed files with 112 additions and 48 deletions
|
@ -206,7 +206,8 @@ func init() {
|
|||
This can be an absolute path or a path
|
||||
relative to the current directory
|
||||
`)
|
||||
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, "0 means a random unprivileged port")
|
||||
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, `0 means a random unprivileged port,
|
||||
< 0 disabled`)
|
||||
portableCmd.Flags().IntVar(&portableFTPDPort, "ftpd-port", -1, `0 means a random unprivileged port,
|
||||
< 0 disabled`)
|
||||
portableCmd.Flags().IntVar(&portableWebDAVPort, "webdav-port", -1, `0 means a random unprivileged port,
|
||||
|
@ -237,7 +238,7 @@ The format is:
|
|||
/dir::pattern1,pattern2.
|
||||
For example: "/somedir::*.jpg,a*b?.png"`)
|
||||
portableCmd.Flags().BoolVarP(&portableAdvertiseService, "advertise-service", "S", false,
|
||||
`Advertise SFTP/FTP service using
|
||||
`Advertise configured services using
|
||||
multicast DNS`)
|
||||
portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false,
|
||||
`If the SFTP/FTP service is
|
||||
|
|
|
@ -582,7 +582,7 @@ type ConnectionStatus struct {
|
|||
Protocol string `json:"protocol"`
|
||||
// active uploads/downloads
|
||||
Transfers []ConnectionTransfer `json:"active_transfers,omitempty"`
|
||||
// SSH command or WevDAV method
|
||||
// SSH command or WebDAV method
|
||||
Command string `json:"command,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -240,6 +240,21 @@ func GetHTTPConfig() httpclient.Config {
|
|||
return globalConf.HTTPConfig
|
||||
}
|
||||
|
||||
// HasServicesToStart returns true if the config defines at least a service to start.
|
||||
// Supported services are SFTP, FTP and WebDAV
|
||||
func HasServicesToStart() bool {
|
||||
if globalConf.SFTPD.BindPort > 0 {
|
||||
return true
|
||||
}
|
||||
if globalConf.FTPD.BindPort > 0 {
|
||||
return true
|
||||
}
|
||||
if globalConf.WebDAVD.BindPort > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getRedactedGlobalConf() globalConfig {
|
||||
conf := globalConf
|
||||
conf.ProviderConf.Password = "[redacted]"
|
||||
|
|
|
@ -281,6 +281,33 @@ func TestSetGetConfig(t *testing.T) {
|
|||
assert.Equal(t, webDavConf.CertificateKeyFile, config.GetWebDAVDConfig().CertificateKeyFile)
|
||||
}
|
||||
|
||||
func TestServiceToStart(t *testing.T) {
|
||||
configDir := ".."
|
||||
err := config.LoadConfig(configDir, configName)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, config.HasServicesToStart())
|
||||
sftpdConf := config.GetSFTPDConfig()
|
||||
sftpdConf.BindPort = 0
|
||||
config.SetSFTPDConfig(sftpdConf)
|
||||
assert.False(t, config.HasServicesToStart())
|
||||
ftpdConf := config.GetFTPDConfig()
|
||||
ftpdConf.BindPort = 2121
|
||||
config.SetFTPDConfig(ftpdConf)
|
||||
assert.True(t, config.HasServicesToStart())
|
||||
ftpdConf.BindPort = 0
|
||||
config.SetFTPDConfig(ftpdConf)
|
||||
webdavdConf := config.GetWebDAVDConfig()
|
||||
webdavdConf.BindPort = 9000
|
||||
config.SetWebDAVDConfig(webdavdConf)
|
||||
assert.True(t, config.HasServicesToStart())
|
||||
webdavdConf.BindPort = 0
|
||||
config.SetWebDAVDConfig(webdavdConf)
|
||||
assert.False(t, config.HasServicesToStart())
|
||||
sftpdConf.BindPort = 2022
|
||||
config.SetSFTPDConfig(sftpdConf)
|
||||
assert.True(t, config.HasServicesToStart())
|
||||
}
|
||||
|
||||
func TestConfigFromEnv(t *testing.T) {
|
||||
os.Setenv("SFTPGO_SFTPD__BIND_ADDRESS", "127.0.0.1")
|
||||
os.Setenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS", "41")
|
||||
|
|
|
@ -64,7 +64,7 @@ The configuration file contains the following sections:
|
|||
- If `proxy_protocol` is set to 2 and we receive a proxy header from an IP that is not in the list then the connection will be rejected
|
||||
- `post_connect_hook`, string. Absolute path to the command to execute or HTTP URL to notify. See [Post connect hook](./post-connect-hook.md) for more details. Leave empty to disable
|
||||
- **"sftpd"**, the configuration for the SFTP server
|
||||
- `bind_port`, integer. The port used for serving SFTP requests. Default: 2022
|
||||
- `bind_port`, integer. The port used for serving SFTP requests. 0 means disabled. Default: 2022
|
||||
- `bind_address`, string. Leave blank to listen on all available network interfaces. Default: ""
|
||||
- `idle_timeout`, integer. Deprecated, please use the same key in `common` section.
|
||||
- `max_auth_tries` integer. Maximum number of authentication attempts permitted per connection. If set to a negative number, the number of attempts is unlimited. If set to zero, the number of attempts is limited to 6.
|
||||
|
|
|
@ -19,7 +19,7 @@ Flags:
|
|||
advertised via multicast DNS, this
|
||||
flag allows to put username/password
|
||||
inside the advertised TXT record
|
||||
-S, --advertise-service Advertise SFTP/FTP service using
|
||||
-S, --advertise-service Advertise configured services using
|
||||
multicast DNS
|
||||
--allowed-patterns stringArray Allowed file patterns case insensitive.
|
||||
The format is:
|
||||
|
@ -88,7 +88,8 @@ Flags:
|
|||
parallel (default 2)
|
||||
--s3-upload-part-size int The buffer size for multipart uploads
|
||||
(MB) (default 5)
|
||||
-s, --sftpd-port int 0 means a random unprivileged port
|
||||
-s, --sftpd-port int 0 means a random unprivileged port,
|
||||
< 0 disabled
|
||||
-c, --ssh-commands strings SSH commands to enable.
|
||||
"*" means any supported SSH command
|
||||
including scp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -73,6 +74,12 @@ func (s *Service) Start() error {
|
|||
logger.Error(logSender, "", "error loading configuration: %v", err)
|
||||
}
|
||||
}
|
||||
if !config.HasServicesToStart() {
|
||||
infoString := "No service configured, nothing to do"
|
||||
logger.Info(logSender, "", infoString)
|
||||
logger.InfoToConsole(infoString)
|
||||
return errors.New(infoString)
|
||||
}
|
||||
|
||||
common.Initialize(config.GetCommonConfig())
|
||||
|
||||
|
@ -115,15 +122,19 @@ func (s *Service) startServices() {
|
|||
httpdConf := config.GetHTTPDConfig()
|
||||
webDavDConf := config.GetWebDAVDConfig()
|
||||
|
||||
go func() {
|
||||
logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
|
||||
if err := sftpdConf.Initialize(s.ConfigDir); err != nil {
|
||||
logger.Error(logSender, "", "could not start SFTP server: %v", err)
|
||||
logger.ErrorToConsole("could not start SFTP server: %v", err)
|
||||
s.Error = err
|
||||
}
|
||||
s.Shutdown <- true
|
||||
}()
|
||||
if sftpdConf.BindPort > 0 {
|
||||
go func() {
|
||||
logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
|
||||
if err := sftpdConf.Initialize(s.ConfigDir); err != nil {
|
||||
logger.Error(logSender, "", "could not start SFTP server: %v", err)
|
||||
logger.ErrorToConsole("could not start SFTP server: %v", err)
|
||||
s.Error = err
|
||||
}
|
||||
s.Shutdown <- true
|
||||
}()
|
||||
} else {
|
||||
logger.Debug(logSender, "", "SFTP server not started, disabled in config file")
|
||||
}
|
||||
|
||||
if httpdConf.BindPort > 0 {
|
||||
go func() {
|
||||
|
@ -162,7 +173,7 @@ func (s *Service) startServices() {
|
|||
s.Shutdown <- true
|
||||
}()
|
||||
} else {
|
||||
logger.Debug(logSender, "", "WevDAV server not started, disabled in config file")
|
||||
logger.Debug(logSender, "", "WebDAV server not started, disabled in config file")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,21 +32,7 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
|
|||
if err != nil {
|
||||
fmt.Printf("error loading configuration file: %v using defaults\n", err)
|
||||
}
|
||||
if len(s.PortableUser.Username) == 0 {
|
||||
s.PortableUser.Username = "user"
|
||||
}
|
||||
printablePassword := ""
|
||||
if len(s.PortableUser.Password) > 0 {
|
||||
printablePassword = "[redacted]"
|
||||
}
|
||||
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
|
||||
var b strings.Builder
|
||||
for i := 0; i < 8; i++ {
|
||||
b.WriteRune(chars[rand.Intn(len(chars))])
|
||||
}
|
||||
s.PortableUser.Password = b.String()
|
||||
printablePassword = s.PortableUser.Password
|
||||
}
|
||||
printablePassword := s.configurePortableUser()
|
||||
dataProviderConf := config.GetProviderConf()
|
||||
dataProviderConf.Driver = dataprovider.MemoryDataProviderName
|
||||
dataProviderConf.Name = ""
|
||||
|
@ -57,16 +43,19 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
|
|||
config.SetHTTPDConfig(httpdConf)
|
||||
sftpdConf := config.GetSFTPDConfig()
|
||||
sftpdConf.MaxAuthTries = 12
|
||||
if sftpdPort > 0 {
|
||||
sftpdConf.BindPort = sftpdPort
|
||||
} else {
|
||||
// dynamic ports starts from 49152
|
||||
sftpdConf.BindPort = 49152 + rand.Intn(15000)
|
||||
}
|
||||
if utils.IsStringInSlice("*", enabledSSHCommands) {
|
||||
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
|
||||
} else {
|
||||
sftpdConf.EnabledSSHCommands = enabledSSHCommands
|
||||
sftpdConf.BindPort = sftpdPort
|
||||
if sftpdPort >= 0 {
|
||||
if sftpdPort > 0 {
|
||||
sftpdConf.BindPort = sftpdPort
|
||||
} else {
|
||||
// dynamic ports starts from 49152
|
||||
sftpdConf.BindPort = 49152 + rand.Intn(15000)
|
||||
}
|
||||
if utils.IsStringInSlice("*", enabledSSHCommands) {
|
||||
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
|
||||
} else {
|
||||
sftpdConf.EnabledSSHCommands = enabledSSHCommands
|
||||
}
|
||||
}
|
||||
config.SetSFTPDConfig(sftpdConf)
|
||||
|
||||
|
@ -102,8 +91,8 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
|
|||
|
||||
s.advertiseServices(advertiseService, advertiseCredentials)
|
||||
|
||||
logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
|
||||
"permissions: %+v, enabled ssh commands: %v file patterns filters: %+v %v", sftpdConf.BindPort, s.PortableUser.Username,
|
||||
logger.InfoToConsole("Portable mode ready, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
|
||||
"permissions: %+v, enabled ssh commands: %v file patterns filters: %+v %v", s.PortableUser.Username,
|
||||
printablePassword, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
|
||||
sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FilePatterns, s.getServiceOptionalInfoString())
|
||||
return nil
|
||||
|
@ -111,15 +100,15 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
|
|||
|
||||
func (s *Service) getServiceOptionalInfoString() string {
|
||||
var info strings.Builder
|
||||
if config.GetSFTPDConfig().BindPort > 0 {
|
||||
info.WriteString(fmt.Sprintf("SFTP port: %v ", config.GetSFTPDConfig().BindPort))
|
||||
}
|
||||
if config.GetFTPDConfig().BindPort > 0 {
|
||||
info.WriteString(fmt.Sprintf("FTP port: %v ", config.GetFTPDConfig().BindPort))
|
||||
}
|
||||
if config.GetWebDAVDConfig().BindPort > 0 {
|
||||
if info.Len() == 0 {
|
||||
info.WriteString(" ")
|
||||
}
|
||||
scheme := "http"
|
||||
if len(config.GetWebDAVDConfig().CertificateFile) > 0 && len(config.GetWebDAVDConfig().CertificateKeyFile) > 0 {
|
||||
if config.GetWebDAVDConfig().CertificateFile != "" && config.GetWebDAVDConfig().CertificateKeyFile != "" {
|
||||
scheme = "https"
|
||||
}
|
||||
info.WriteString(fmt.Sprintf("WebDAV URL: %v://<your IP>:%v/%v",
|
||||
|
@ -230,3 +219,23 @@ func (s *Service) getPortableDirToServe() string {
|
|||
}
|
||||
return dirToServe
|
||||
}
|
||||
|
||||
// configures the portable user and return the printable password if any
|
||||
func (s *Service) configurePortableUser() string {
|
||||
if s.PortableUser.Username == "" {
|
||||
s.PortableUser.Username = "user"
|
||||
}
|
||||
printablePassword := ""
|
||||
if len(s.PortableUser.Password) > 0 {
|
||||
printablePassword = "[redacted]"
|
||||
}
|
||||
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
|
||||
var b strings.Builder
|
||||
for i := 0; i < 8; i++ {
|
||||
b.WriteRune(chars[rand.Intn(len(chars))])
|
||||
}
|
||||
s.PortableUser.Password = b.String()
|
||||
printablePassword = s.PortableUser.Password
|
||||
}
|
||||
return printablePassword
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ type Configuration struct {
|
|||
// Initialize configures and starts the WebDav server
|
||||
func (c *Configuration) Initialize(configDir string) error {
|
||||
var err error
|
||||
logger.Debug(logSender, "", "initializing WevDav server with config %+v", *c)
|
||||
logger.Debug(logSender, "", "initializing WebDAV server with config %+v", *c)
|
||||
mimeTypeCache = mimeCache{
|
||||
maxSize: c.Cache.MimeTypes.MaxSize,
|
||||
mimeTypes: make(map[string]string),
|
||||
|
|
Loading…
Reference in a new issue