httpd.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Package httpd implements REST API and Web interface for SFTPGo.
  2. // REST API allows to manage users and quota and to get real time reports for the active connections
  3. // with possibility of forcibly closing a connection.
  4. // The OpenAPI 3 schema for the exposed API can be found inside the source tree:
  5. // https://github.com/drakkan/sftpgo/tree/master/api/schema/openapi.yaml
  6. // A basic Web interface to manage users and connections is provided too
  7. package httpd
  8. import (
  9. "crypto/tls"
  10. "fmt"
  11. "net/http"
  12. "path/filepath"
  13. "time"
  14. "github.com/drakkan/sftpgo/dataprovider"
  15. "github.com/drakkan/sftpgo/logger"
  16. "github.com/drakkan/sftpgo/utils"
  17. "github.com/go-chi/chi"
  18. )
  19. const (
  20. logSender = "httpd"
  21. apiPrefix = "/api/v1"
  22. activeConnectionsPath = "/api/v1/connection"
  23. quotaScanPath = "/api/v1/quota_scan"
  24. userPath = "/api/v1/user"
  25. versionPath = "/api/v1/version"
  26. providerStatusPath = "/api/v1/providerstatus"
  27. dumpDataPath = "/api/v1/dumpdata"
  28. loadDataPath = "/api/v1/loaddata"
  29. metricsPath = "/metrics"
  30. pprofBasePath = "/debug"
  31. webBasePath = "/web"
  32. webUsersPath = "/web/users"
  33. webUserPath = "/web/user"
  34. webConnectionsPath = "/web/connections"
  35. webStaticFilesPath = "/static"
  36. maxRestoreSize = 10485760 // 10 MB
  37. maxRequestSize = 1048576 // 1MB
  38. )
  39. var (
  40. router *chi.Mux
  41. dataProvider dataprovider.Provider
  42. backupsPath string
  43. httpAuth httpAuthProvider
  44. certMgr *certManager
  45. )
  46. // Conf httpd daemon configuration
  47. type Conf struct {
  48. // The port used for serving HTTP requests. 0 disable the HTTP server. Default: 8080
  49. BindPort int `json:"bind_port" mapstructure:"bind_port"`
  50. // The address to listen on. A blank value means listen on all available network interfaces. Default: "127.0.0.1"
  51. BindAddress string `json:"bind_address" mapstructure:"bind_address"`
  52. // Path to the HTML web templates. This can be an absolute path or a path relative to the config dir
  53. TemplatesPath string `json:"templates_path" mapstructure:"templates_path"`
  54. // Path to the static files for the web interface. This can be an absolute path or a path relative to the config dir
  55. StaticFilesPath string `json:"static_files_path" mapstructure:"static_files_path"`
  56. // Path to the backup directory. This can be an absolute path or a path relative to the config dir
  57. BackupsPath string `json:"backups_path" mapstructure:"backups_path"`
  58. // Path to a file used to store usernames and password for basic authentication.
  59. // This can be an absolute path or a path relative to the config dir.
  60. // We support HTTP basic authentication and the file format must conform to the one generated using the Apache
  61. // htpasswd tool. The supported password formats are bcrypt ($2y$ prefix) and md5 crypt ($apr1$ prefix).
  62. // If empty HTTP authentication is disabled
  63. AuthUserFile string `json:"auth_user_file" mapstructure:"auth_user_file"`
  64. // If files containing a certificate and matching private key for the server are provided the server will expect
  65. // HTTPS connections.
  66. // Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
  67. // "paramchange" request to the running service on Windows.
  68. CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
  69. CertificateKeyFile string `json:"certificate_key_file" mapstructure:"certificate_key_file"`
  70. }
  71. type apiResponse struct {
  72. Error string `json:"error"`
  73. Message string `json:"message"`
  74. HTTPStatus int `json:"status"`
  75. }
  76. // SetDataProvider sets the data provider to use to fetch the data about users
  77. func SetDataProvider(provider dataprovider.Provider) {
  78. dataProvider = provider
  79. }
  80. // Initialize configures and starts the HTTP server
  81. func (c Conf) Initialize(configDir string, profiler bool) error {
  82. var err error
  83. logger.Debug(logSender, "", "initializing HTTP server with config %+v", c)
  84. backupsPath = getConfigPath(c.BackupsPath, configDir)
  85. staticFilesPath := getConfigPath(c.StaticFilesPath, configDir)
  86. templatesPath := getConfigPath(c.TemplatesPath, configDir)
  87. if len(backupsPath) == 0 || len(staticFilesPath) == 0 || len(templatesPath) == 0 {
  88. return fmt.Errorf("Required directory is invalid, backup path %#v, static file path: %#v template path: %#v",
  89. backupsPath, staticFilesPath, templatesPath)
  90. }
  91. authUserFile := getConfigPath(c.AuthUserFile, configDir)
  92. httpAuth, err = newBasicAuthProvider(authUserFile)
  93. if err != nil {
  94. return err
  95. }
  96. certificateFile := getConfigPath(c.CertificateFile, configDir)
  97. certificateKeyFile := getConfigPath(c.CertificateKeyFile, configDir)
  98. loadTemplates(templatesPath)
  99. initializeRouter(staticFilesPath, profiler)
  100. httpServer := &http.Server{
  101. Addr: fmt.Sprintf("%s:%d", c.BindAddress, c.BindPort),
  102. Handler: router,
  103. ReadTimeout: 60 * time.Second,
  104. WriteTimeout: 60 * time.Second,
  105. IdleTimeout: 120 * time.Second,
  106. MaxHeaderBytes: 1 << 16, // 64KB
  107. }
  108. if len(certificateFile) > 0 && len(certificateKeyFile) > 0 {
  109. certMgr, err = newCertManager(certificateFile, certificateKeyFile)
  110. if err != nil {
  111. return err
  112. }
  113. config := &tls.Config{
  114. GetCertificate: certMgr.GetCertificateFunc(),
  115. }
  116. httpServer.TLSConfig = config
  117. return httpServer.ListenAndServeTLS("", "")
  118. }
  119. return httpServer.ListenAndServe()
  120. }
  121. // ReloadTLSCertificate reloads the TLS certificate and key from the configured paths
  122. func ReloadTLSCertificate() {
  123. if certMgr != nil {
  124. certMgr.loadCertificate()
  125. }
  126. }
  127. func getConfigPath(name, configDir string) string {
  128. if !utils.IsFileInputValid(name) {
  129. return ""
  130. }
  131. if len(name) > 0 && !filepath.IsAbs(name) {
  132. return filepath.Join(configDir, name)
  133. }
  134. return name
  135. }