package sftp import ( "emperror.dev/errors" "github.com/apex/log" "github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/server" ) var noMatchingServerError = errors.New("no matching server with that UUID was found") func Initialize(config config.SystemConfiguration) error { s := &Server{ User: User{ Uid: config.User.Uid, Gid: config.User.Gid, }, Settings: Settings{ BasePath: config.Data, ReadOnly: config.Sftp.ReadOnly, BindAddress: config.Sftp.Address, BindPort: config.Sftp.Port, }, CredentialValidator: validateCredentials, PathValidator: validatePath, DiskSpaceValidator: validateDiskSpace, } if err := New(s); err != nil { return errors.WithStackIf(err) } // Initialize the SFTP server in a background thread since this is // a long running operation. go func(s *Server) { if err := s.Initialize(); err != nil { log.WithField("subsystem", "sftp").WithField("error", errors.WithStackIf(err)).Error("failed to initialize SFTP subsystem") } }(s) return nil } func validatePath(fs FileSystem, p string) (string, error) { s := server.GetServers().Find(func(server *server.Server) bool { return server.Id() == fs.UUID }) if s == nil { return "", noMatchingServerError } return s.Filesystem().SafePath(p) } func validateDiskSpace(fs FileSystem) bool { s := server.GetServers().Find(func(server *server.Server) bool { return server.Id() == fs.UUID }) if s == nil { return false } return s.Filesystem().HasSpaceAvailable(true) } // Validates a set of credentials for a SFTP login against Pterodactyl Panel and returns // the server's UUID if the credentials were valid. func validateCredentials(c api.SftpAuthRequest) (*api.SftpAuthResponse, error) { f := log.Fields{"subsystem": "sftp", "username": c.User, "ip": c.IP} log.WithFields(f).Debug("validating credentials for SFTP connection") resp, err := api.New().ValidateSftpCredentials(c) if err != nil { if api.IsInvalidCredentialsError(err) { log.WithFields(f).Warn("failed to validate user credentials (invalid username or password)") } else { log.WithFields(f).Error("encountered an error while trying to validate user credentials") } return resp, err } s := server.GetServers().Find(func(server *server.Server) bool { return server.Id() == resp.Server }) if s == nil { return resp, noMatchingServerError } s.Log().WithFields(f).Debug("credentials successfully validated and matched user to server instance") return resp, err }