sftpserv.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package sftpserv
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "strconv"
  6. "time"
  7. "imuslab.com/arozos/mod/database"
  8. "imuslab.com/arozos/mod/fileservers"
  9. "imuslab.com/arozos/mod/info/logger"
  10. "imuslab.com/arozos/mod/network/upnp"
  11. "imuslab.com/arozos/mod/storage/sftpserver"
  12. user "imuslab.com/arozos/mod/user"
  13. "imuslab.com/arozos/mod/utils"
  14. )
  15. type ManagerOption struct {
  16. Hostname string
  17. UserManager *user.UserHandler
  18. KeyFile string
  19. Logger *logger.Logger
  20. Sysdb *database.Database
  21. Upnp *upnp.UPnPClient
  22. }
  23. type Manager struct {
  24. listeningPort int
  25. instance *sftpserver.Instance
  26. option *ManagerOption
  27. }
  28. func NewSFTPServer(option *ManagerOption) *Manager {
  29. option.Sysdb.NewTable("sftp")
  30. i, lp, _ := newSFTPServerInstance(option)
  31. return &Manager{
  32. listeningPort: lp,
  33. instance: i,
  34. option: option,
  35. }
  36. }
  37. func newSFTPServerInstance(option *ManagerOption) (*sftpserver.Instance, int, error) {
  38. //Load default port from database
  39. defaultListeningPort := 2022
  40. if option.Sysdb.KeyExists("sftp", "port") {
  41. option.Sysdb.Read("sftp", "port", &defaultListeningPort)
  42. }
  43. //Create an SFTP Server
  44. var currentConfig = sftpserver.SFTPConfig{
  45. ListeningIP: "0.0.0.0:" + strconv.Itoa(defaultListeningPort),
  46. KeyFile: option.KeyFile,
  47. UserManager: option.UserManager,
  48. }
  49. enableUPnP := getUpnPEnabled(option.Sysdb)
  50. if enableUPnP && option.Upnp != nil {
  51. option.Upnp.ForwardPort(defaultListeningPort, option.Hostname+" sftp-service")
  52. }
  53. enableOnStart := false
  54. option.Sysdb.Read("sftp", "enabled", &enableOnStart)
  55. if enableOnStart {
  56. i, err := sftpserver.NewSFTPServer(&currentConfig)
  57. return i, defaultListeningPort, err
  58. } else {
  59. return nil, defaultListeningPort, nil
  60. }
  61. }
  62. func (m *Manager) closeInstance() {
  63. //Close the instance
  64. m.instance.Close()
  65. m.instance = nil
  66. //Remove the UPNP rules if enabled
  67. enableUPnP := getUpnPEnabled(m.option.Sysdb)
  68. if enableUPnP {
  69. m.option.Upnp.ClosePort(m.listeningPort)
  70. }
  71. }
  72. /*
  73. Handlers for handling config change
  74. */
  75. //Get or Set listening port for SFTP
  76. func (m *Manager) HandleListeningPort(w http.ResponseWriter, r *http.Request) {
  77. newport, _ := utils.Mv(r, "port", true)
  78. if newport == "" {
  79. //Resp with the current operating port
  80. js, _ := json.Marshal(m.listeningPort)
  81. utils.SendJSONResponse(w, string(js))
  82. } else {
  83. portInt, err := strconv.Atoi(newport)
  84. if err != nil {
  85. utils.SendErrorResponse(w, "invalid port number given")
  86. return
  87. }
  88. err = m.option.Sysdb.Write("sftp", "port", portInt)
  89. if err != nil {
  90. utils.SendErrorResponse(w, err.Error())
  91. return
  92. }
  93. //Update the temp port buffer
  94. m.listeningPort = portInt
  95. if m.IsEnabled() {
  96. //Restart the services
  97. m.ServerToggle(false)
  98. time.Sleep(300 * time.Microsecond)
  99. m.ServerToggle(true)
  100. }
  101. utils.SendOK(w)
  102. }
  103. }
  104. func getUpnPEnabled(sysdb *database.Database) bool {
  105. enableUPnP := false
  106. if sysdb.KeyExists("sftp", "upnp") {
  107. sysdb.Read("sftp", "upnp", &enableUPnP)
  108. }
  109. return enableUPnP
  110. }
  111. func (m *Manager) HandleGetConnectedClients(w http.ResponseWriter, r *http.Request) {
  112. userCount := 0
  113. if m.IsEnabled() {
  114. m.instance.ConnectedClients.Range(func(k, v interface{}) bool {
  115. userCount++
  116. return true
  117. })
  118. }
  119. js, _ := json.Marshal(userCount)
  120. utils.SendJSONResponse(w, string(js))
  121. }
  122. func (m *Manager) HandleToogleUPnP(w http.ResponseWriter, r *http.Request) {
  123. enableUpnp, _ := utils.Mv(r, "enabled", true)
  124. if enableUpnp == "" {
  125. //Get the current state of Upnp
  126. currentEnabled := getUpnPEnabled(m.option.Sysdb)
  127. js, _ := json.Marshal(currentEnabled)
  128. utils.SendJSONResponse(w, string(js))
  129. } else if enableUpnp == "true" {
  130. //Enable UpnP
  131. m.option.Sysdb.Write("sftp", "upnp", true)
  132. if m.IsEnabled() {
  133. //Restart the services
  134. m.ServerToggle(false)
  135. time.Sleep(300 * time.Microsecond)
  136. m.ServerToggle(true)
  137. }
  138. utils.SendOK(w)
  139. } else if enableUpnp == "false" {
  140. //Disable UpnP
  141. m.option.Sysdb.Write("sftp", "upnp", false)
  142. if m.IsEnabled() {
  143. //Restart the services
  144. m.ServerToggle(false)
  145. time.Sleep(300 * time.Microsecond)
  146. m.ServerToggle(true)
  147. }
  148. //Remove UPnP forwarded port
  149. m.option.Upnp.ClosePort(m.listeningPort)
  150. utils.SendOK(w)
  151. } else {
  152. utils.SendErrorResponse(w, "unknown operation")
  153. }
  154. }
  155. /*
  156. Functions requested by the file server service router
  157. */
  158. func (m *Manager) ServerToggle(enabled bool) error {
  159. if m.instance != nil && !enabled {
  160. //Shutdown the running instances
  161. m.closeInstance()
  162. m.option.Sysdb.Write("sftp", "enabled", false)
  163. } else if m.instance == nil && enabled {
  164. //Startup a new instance
  165. m.option.Sysdb.Write("sftp", "enabled", true)
  166. i, lp, err := newSFTPServerInstance(m.option)
  167. if err != nil {
  168. m.option.Sysdb.Write("sftp", "enabled", false)
  169. return err
  170. }
  171. m.listeningPort = lp
  172. m.instance = i
  173. }
  174. return nil
  175. }
  176. func (m *Manager) IsEnabled() bool {
  177. return m.instance != nil && !m.instance.Closed
  178. }
  179. func (m *Manager) GetEndpoints(userinfo *user.User) []*fileservers.Endpoint {
  180. eps := []*fileservers.Endpoint{}
  181. eps = append(eps, &fileservers.Endpoint{
  182. ProtocolName: "sftp://",
  183. Port: m.listeningPort,
  184. Subpath: "",
  185. })
  186. return eps
  187. }