123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package sftpserv
- import (
- "encoding/json"
- "net/http"
- "strconv"
- "time"
- "imuslab.com/arozos/mod/database"
- "imuslab.com/arozos/mod/fileservers"
- "imuslab.com/arozos/mod/info/logger"
- "imuslab.com/arozos/mod/network/upnp"
- "imuslab.com/arozos/mod/storage/sftpserver"
- user "imuslab.com/arozos/mod/user"
- "imuslab.com/arozos/mod/utils"
- )
- type ManagerOption struct {
- Hostname string
- UserManager *user.UserHandler
- KeyFile string
- Logger *logger.Logger
- Sysdb *database.Database
- Upnp *upnp.UPnPClient
- }
- type Manager struct {
- listeningPort int
- instance *sftpserver.Instance
- option *ManagerOption
- }
- func NewSFTPServer(option *ManagerOption) *Manager {
- option.Sysdb.NewTable("sftp")
- i, lp, _ := newSFTPServerInstance(option)
- return &Manager{
- listeningPort: lp,
- instance: i,
- option: option,
- }
- }
- func newSFTPServerInstance(option *ManagerOption) (*sftpserver.Instance, int, error) {
- //Load default port from database
- defaultListeningPort := 2022
- if option.Sysdb.KeyExists("sftp", "port") {
- option.Sysdb.Read("sftp", "port", &defaultListeningPort)
- }
- //Create an SFTP Server
- var currentConfig = sftpserver.SFTPConfig{
- ListeningIP: "0.0.0.0:" + strconv.Itoa(defaultListeningPort),
- KeyFile: option.KeyFile,
- UserManager: option.UserManager,
- }
- enableUPnP := getUpnPEnabled(option.Sysdb)
- if enableUPnP && option.Upnp != nil {
- option.Upnp.ForwardPort(defaultListeningPort, option.Hostname+" sftp-service")
- }
- enableOnStart := false
- option.Sysdb.Read("sftp", "enabled", &enableOnStart)
- if enableOnStart {
- i, err := sftpserver.NewSFTPServer(¤tConfig)
- return i, defaultListeningPort, err
- } else {
- return nil, defaultListeningPort, nil
- }
- }
- func (m *Manager) closeInstance() {
- //Close the instance
- m.instance.Close()
- m.instance = nil
- //Remove the UPNP rules if enabled
- enableUPnP := getUpnPEnabled(m.option.Sysdb)
- if enableUPnP {
- m.option.Upnp.ClosePort(m.listeningPort)
- }
- }
- /*
- Handlers for handling config change
- */
- //Get or Set listening port for SFTP
- func (m *Manager) HandleListeningPort(w http.ResponseWriter, r *http.Request) {
- newport, _ := utils.Mv(r, "port", true)
- if newport == "" {
- //Resp with the current operating port
- js, _ := json.Marshal(m.listeningPort)
- utils.SendJSONResponse(w, string(js))
- } else {
- portInt, err := strconv.Atoi(newport)
- if err != nil {
- utils.SendErrorResponse(w, "invalid port number given")
- return
- }
- err = m.option.Sysdb.Write("sftp", "port", portInt)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Update the temp port buffer
- m.listeningPort = portInt
- if m.IsEnabled() {
- //Restart the services
- m.ServerToggle(false)
- time.Sleep(300 * time.Microsecond)
- m.ServerToggle(true)
- }
- utils.SendOK(w)
- }
- }
- func getUpnPEnabled(sysdb *database.Database) bool {
- enableUPnP := false
- if sysdb.KeyExists("sftp", "upnp") {
- sysdb.Read("sftp", "upnp", &enableUPnP)
- }
- return enableUPnP
- }
- func (m *Manager) HandleGetConnectedClients(w http.ResponseWriter, r *http.Request) {
- userCount := 0
- if m.IsEnabled() {
- m.instance.ConnectedClients.Range(func(k, v interface{}) bool {
- userCount++
- return true
- })
- }
- js, _ := json.Marshal(userCount)
- utils.SendJSONResponse(w, string(js))
- }
- func (m *Manager) HandleToogleUPnP(w http.ResponseWriter, r *http.Request) {
- enableUpnp, _ := utils.Mv(r, "enabled", true)
- if enableUpnp == "" {
- //Get the current state of Upnp
- currentEnabled := getUpnPEnabled(m.option.Sysdb)
- js, _ := json.Marshal(currentEnabled)
- utils.SendJSONResponse(w, string(js))
- } else if enableUpnp == "true" {
- //Enable UpnP
- m.option.Sysdb.Write("sftp", "upnp", true)
- if m.IsEnabled() {
- //Restart the services
- m.ServerToggle(false)
- time.Sleep(300 * time.Microsecond)
- m.ServerToggle(true)
- }
- utils.SendOK(w)
- } else if enableUpnp == "false" {
- //Disable UpnP
- m.option.Sysdb.Write("sftp", "upnp", false)
- if m.IsEnabled() {
- //Restart the services
- m.ServerToggle(false)
- time.Sleep(300 * time.Microsecond)
- m.ServerToggle(true)
- }
- //Remove UPnP forwarded port
- m.option.Upnp.ClosePort(m.listeningPort)
- utils.SendOK(w)
- } else {
- utils.SendErrorResponse(w, "unknown operation")
- }
- }
- /*
- Functions requested by the file server service router
- */
- func (m *Manager) ServerToggle(enabled bool) error {
- if m.instance != nil && !enabled {
- //Shutdown the running instances
- m.closeInstance()
- m.option.Sysdb.Write("sftp", "enabled", false)
- } else if m.instance == nil && enabled {
- //Startup a new instance
- m.option.Sysdb.Write("sftp", "enabled", true)
- i, lp, err := newSFTPServerInstance(m.option)
- if err != nil {
- m.option.Sysdb.Write("sftp", "enabled", false)
- return err
- }
- m.listeningPort = lp
- m.instance = i
- }
- return nil
- }
- func (m *Manager) IsEnabled() bool {
- return m.instance != nil && !m.instance.Closed
- }
- func (m *Manager) GetEndpoints(userinfo *user.User) []*fileservers.Endpoint {
- eps := []*fileservers.Endpoint{}
- eps = append(eps, &fileservers.Endpoint{
- ProtocolName: "sftp://",
- Port: m.listeningPort,
- Subpath: "",
- })
- return eps
- }
|