Browse Source

WebUI: extract a common struct for all pages

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 1 year ago
parent
commit
74836af66e
4 changed files with 130 additions and 140 deletions
  1. 14 16
      internal/httpd/server.go
  2. 19 8
      internal/httpd/web.go
  3. 29 36
      internal/httpd/webadmin.go
  4. 68 80
      internal/httpd/webclient.go

+ 14 - 16
internal/httpd/server.go

@@ -162,14 +162,13 @@ func (s *httpdServer) refreshCookie(next http.Handler) http.Handler {
 
 func (s *httpdServer) renderClientLoginPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := loginPage{
-		CurrentURL:   webClientLoginPath,
-		Version:      version.Get().Version,
-		Error:        error,
-		CSRFToken:    createCSRFToken(ip),
-		CSPNonce:     secure.CSPNonce(r.Context()),
-		StaticURL:    webStaticFilesPath,
-		Branding:     s.binding.Branding.WebClient,
-		FormDisabled: s.binding.isWebClientLoginFormDisabled(),
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webClientLoginPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Branding:       s.binding.Branding.WebClient,
+		FormDisabled:   s.binding.isWebClientLoginFormDisabled(),
 	}
 	if next := r.URL.Query().Get("next"); strings.HasPrefix(next, webClientFilesPath) {
 		data.CurrentURL += "?next=" + url.QueryEscape(next)
@@ -575,14 +574,13 @@ func (s *httpdServer) handleWebAdminLoginPost(w http.ResponseWriter, r *http.Req
 
 func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := loginPage{
-		CurrentURL:   webAdminLoginPath,
-		Version:      version.Get().Version,
-		Error:        error,
-		CSRFToken:    createCSRFToken(ip),
-		CSPNonce:     secure.CSPNonce(r.Context()),
-		StaticURL:    webStaticFilesPath,
-		Branding:     s.binding.Branding.WebAdmin,
-		FormDisabled: s.binding.isWebAdminLoginFormDisabled(),
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webAdminLoginPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Branding:       s.binding.Branding.WebAdmin,
+		FormDisabled:   s.binding.isWebAdminLoginFormDisabled(),
 	}
 	if s.binding.showClientLoginURL() {
 		data.AltLoginURL = webClientLoginPath

+ 19 - 8
internal/httpd/web.go

@@ -15,7 +15,10 @@
 package httpd
 
 import (
+	"net/http"
 	"strings"
+
+	"github.com/unrolled/secure"
 )
 
 const (
@@ -41,13 +44,17 @@ const (
 	templateCommonBase         = "base.html"
 )
 
+type commonBasePage struct {
+	CSPNonce  string
+	StaticURL string
+}
+
 type loginPage struct {
+	commonBasePage
 	CurrentURL     string
 	Version        string
 	Error          string
 	CSRFToken      string
-	CSPNonce       string
-	StaticURL      string
 	AltLoginURL    string
 	AltLoginName   string
 	ForgotPwdURL   string
@@ -57,34 +64,31 @@ type loginPage struct {
 }
 
 type twoFactorPage struct {
+	commonBasePage
 	CurrentURL  string
 	Version     string
 	Error       string
 	CSRFToken   string
-	CSPNonce    string
-	StaticURL   string
 	RecoveryURL string
 	Title       string
 	Branding    UIBranding
 }
 
 type forgotPwdPage struct {
+	commonBasePage
 	CurrentURL string
 	Error      string
 	CSRFToken  string
-	CSPNonce   string
-	StaticURL  string
 	LoginURL   string
 	Title      string
 	Branding   UIBranding
 }
 
 type resetPwdPage struct {
+	commonBasePage
 	CurrentURL string
 	Error      string
 	CSRFToken  string
-	CSPNonce   string
-	StaticURL  string
 	LoginURL   string
 	Title      string
 	Branding   UIBranding
@@ -104,3 +108,10 @@ func getSliceFromDelimitedValues(values, delimiter string) []string {
 func hasPrefixAndSuffix(key, prefix, suffix string) bool {
 	return strings.HasPrefix(key, prefix) && strings.HasSuffix(key, suffix)
 }
+
+func getCommonBasePage(r *http.Request) commonBasePage {
+	return commonBasePage{
+		CSPNonce:  secure.CSPNonce(r.Context()),
+		StaticURL: webStaticFilesPath,
+	}
+}

+ 29 - 36
internal/httpd/webadmin.go

@@ -32,7 +32,6 @@ import (
 	"github.com/go-chi/render"
 	"github.com/sftpgo/sdk"
 	sdkkms "github.com/sftpgo/sdk/kms"
-	"github.com/unrolled/secure"
 
 	"github.com/drakkan/sftpgo/v2/internal/acme"
 	"github.com/drakkan/sftpgo/v2/internal/common"
@@ -132,6 +131,7 @@ var (
 )
 
 type basePage struct {
+	commonBasePage
 	Title               string
 	CurrentURL          string
 	UsersURL            string
@@ -164,7 +164,6 @@ type basePage struct {
 	FolderQuotaScanURL  string
 	StatusURL           string
 	MaintenanceURL      string
-	StaticURL           string
 	UsersTitle          string
 	AdminsTitle         string
 	ConnectionsTitle    string
@@ -181,7 +180,6 @@ type basePage struct {
 	ConfigsTitle        string
 	Version             string
 	CSRFToken           string
-	CSPNonce            string
 	IsEventManagerPage  bool
 	IsIPManagerPage     bool
 	IsServerManagerPage bool
@@ -697,6 +695,7 @@ func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request)
 		csrfToken = createCSRFToken(util.GetIPFromRemoteAddress(r.RemoteAddr))
 	}
 	return basePage{
+		commonBasePage:      getCommonBasePage(r),
 		Title:               title,
 		CurrentURL:          currentURL,
 		UsersURL:            webUsersPath,
@@ -729,7 +728,6 @@ func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request)
 		StatusURL:           webStatusPath,
 		FolderQuotaScanURL:  webScanVFolderPath,
 		MaintenanceURL:      webMaintenancePath,
-		StaticURL:           webStaticFilesPath,
 		UsersTitle:          pageUsersTitle,
 		AdminsTitle:         pageAdminsTitle,
 		ConnectionsTitle:    pageConnectionsTitle,
@@ -753,7 +751,6 @@ func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request)
 		HasSearcher:         plugin.Handler.HasSearcher(),
 		HasExternalLogin:    isLoggedInWithOIDC(r),
 		CSRFToken:           csrfToken,
-		CSPNonce:            secure.CSPNonce(r.Context()),
 		Branding:            s.binding.Branding.WebAdmin,
 	}
 }
@@ -802,55 +799,51 @@ func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request,
 
 func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := forgotPwdPage{
-		CurrentURL: webAdminForgotPwdPath,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		Title:      pageForgotPwdTitle,
-		Branding:   s.binding.Branding.WebAdmin,
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webAdminForgotPwdPath,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Title:          pageForgotPwdTitle,
+		Branding:       s.binding.Branding.WebAdmin,
 	}
 	renderAdminTemplate(w, templateForgotPassword, data)
 }
 
 func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := resetPwdPage{
-		CurrentURL: webAdminResetPwdPath,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		Title:      pageResetPwdTitle,
-		Branding:   s.binding.Branding.WebAdmin,
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webAdminResetPwdPath,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Title:          pageResetPwdTitle,
+		Branding:       s.binding.Branding.WebAdmin,
 	}
 	renderAdminTemplate(w, templateResetPassword, data)
 }
 
 func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := twoFactorPage{
-		Title:       pageTwoFactorTitle,
-		CurrentURL:  webAdminTwoFactorPath,
-		Version:     version.Get().Version,
-		Error:       error,
-		CSRFToken:   createCSRFToken(ip),
-		CSPNonce:    secure.CSPNonce(r.Context()),
-		StaticURL:   webStaticFilesPath,
-		RecoveryURL: webAdminTwoFactorRecoveryPath,
-		Branding:    s.binding.Branding.WebAdmin,
+		commonBasePage: getCommonBasePage(r),
+		Title:          pageTwoFactorTitle,
+		CurrentURL:     webAdminTwoFactorPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		RecoveryURL:    webAdminTwoFactorRecoveryPath,
+		Branding:       s.binding.Branding.WebAdmin,
 	}
 	renderAdminTemplate(w, templateTwoFactor, data)
 }
 
 func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := twoFactorPage{
-		Title:      pageTwoFactorRecoveryTitle,
-		CurrentURL: webAdminTwoFactorRecoveryPath,
-		Version:    version.Get().Version,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		Branding:   s.binding.Branding.WebAdmin,
+		commonBasePage: getCommonBasePage(r),
+		Title:          pageTwoFactorRecoveryTitle,
+		CurrentURL:     webAdminTwoFactorRecoveryPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Branding:       s.binding.Branding.WebAdmin,
 	}
 	renderAdminTemplate(w, templateTwoFactorRecovery, data)
 }

+ 68 - 80
internal/httpd/webclient.go

@@ -34,7 +34,6 @@ import (
 	"github.com/go-chi/render"
 	"github.com/rs/xid"
 	"github.com/sftpgo/sdk"
-	"github.com/unrolled/secure"
 
 	"github.com/drakkan/sftpgo/v2/internal/common"
 	"github.com/drakkan/sftpgo/v2/internal/dataprovider"
@@ -99,6 +98,7 @@ func isZeroTime(t time.Time) bool {
 }
 
 type baseClientPage struct {
+	commonBasePage
 	Title        string
 	CurrentURL   string
 	FilesURL     string
@@ -107,7 +107,6 @@ type baseClientPage struct {
 	ProfileURL   string
 	PingURL      string
 	ChangePwdURL string
-	StaticURL    string
 	LogoutURL    string
 	LoginURL     string
 	EditURL      string
@@ -118,7 +117,6 @@ type baseClientPage struct {
 	ProfileTitle string
 	Version      string
 	CSRFToken    string
-	CSPNonce     string
 	LoggedUser   *dataprovider.User
 	Branding     UIBranding
 }
@@ -129,11 +127,10 @@ type dirMapping struct {
 }
 
 type viewPDFPage struct {
-	Title     string
-	URL       string
-	StaticURL string
-	CSPNonce  string
-	Branding  UIBranding
+	commonBasePage
+	Title    string
+	URL      string
+	Branding UIBranding
 }
 
 type editFilePage struct {
@@ -167,12 +164,11 @@ type filesPage struct {
 }
 
 type shareLoginPage struct {
+	commonBasePage
 	CurrentURL string
 	Version    string
 	Error      string
 	CSRFToken  string
-	CSPNonce   string
-	StaticURL  string
 	Branding   UIBranding
 }
 
@@ -553,27 +549,26 @@ func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Re
 	v := version.Get()
 
 	data := baseClientPage{
-		Title:        title,
-		CurrentURL:   currentURL,
-		FilesURL:     webClientFilesPath,
-		SharesURL:    webClientSharesPath,
-		ShareURL:     webClientSharePath,
-		ProfileURL:   webClientProfilePath,
-		PingURL:      webClientPingPath,
-		ChangePwdURL: webChangeClientPwdPath,
-		StaticURL:    webStaticFilesPath,
-		LogoutURL:    webClientLogoutPath,
-		EditURL:      webClientEditFilePath,
-		MFAURL:       webClientMFAPath,
-		MFATitle:     pageClient2FATitle,
-		FilesTitle:   pageClientFilesTitle,
-		SharesTitle:  pageClientSharesTitle,
-		ProfileTitle: pageClientProfileTitle,
-		Version:      fmt.Sprintf("%v-%v", v.Version, v.CommitHash),
-		CSRFToken:    csrfToken,
-		CSPNonce:     secure.CSPNonce(r.Context()),
-		LoggedUser:   getUserFromToken(r),
-		Branding:     s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		Title:          title,
+		CurrentURL:     currentURL,
+		FilesURL:       webClientFilesPath,
+		SharesURL:      webClientSharesPath,
+		ShareURL:       webClientSharePath,
+		ProfileURL:     webClientProfilePath,
+		PingURL:        webClientPingPath,
+		ChangePwdURL:   webChangeClientPwdPath,
+		LogoutURL:      webClientLogoutPath,
+		EditURL:        webClientEditFilePath,
+		MFAURL:         webClientMFAPath,
+		MFATitle:       pageClient2FATitle,
+		FilesTitle:     pageClientFilesTitle,
+		SharesTitle:    pageClientSharesTitle,
+		ProfileTitle:   pageClientProfileTitle,
+		Version:        fmt.Sprintf("%v-%v", v.Version, v.CommitHash),
+		CSRFToken:      csrfToken,
+		LoggedUser:     getUserFromToken(r),
+		Branding:       s.binding.Branding.WebClient,
 	}
 	if !strings.HasPrefix(r.RequestURI, webClientPubSharesPath) {
 		data.LoginURL = webClientLoginPath
@@ -583,41 +578,38 @@ func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Re
 
 func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := forgotPwdPage{
-		CurrentURL: webClientForgotPwdPath,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		LoginURL:   webClientLoginPath,
-		Title:      pageClientForgotPwdTitle,
-		Branding:   s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webClientForgotPwdPath,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		LoginURL:       webClientLoginPath,
+		Title:          pageClientForgotPwdTitle,
+		Branding:       s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateForgotPassword, data)
 }
 
 func (s *httpdServer) renderClientResetPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := resetPwdPage{
-		CurrentURL: webClientResetPwdPath,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		LoginURL:   webClientLoginPath,
-		Title:      pageClientResetPwdTitle,
-		Branding:   s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     webClientResetPwdPath,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		LoginURL:       webClientLoginPath,
+		Title:          pageClientResetPwdTitle,
+		Branding:       s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateResetPassword, data)
 }
 
 func (s *httpdServer) renderShareLoginPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := shareLoginPage{
-		CurrentURL: r.RequestURI,
-		Version:    version.Get().Version,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		Branding:   s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		CurrentURL:     r.RequestURI,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Branding:       s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateShareLogin, data)
 }
@@ -665,15 +657,14 @@ func (s *httpdServer) renderClientNotFoundPage(w http.ResponseWriter, r *http.Re
 
 func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := twoFactorPage{
-		Title:       pageTwoFactorTitle,
-		CurrentURL:  webClientTwoFactorPath,
-		Version:     version.Get().Version,
-		Error:       error,
-		CSRFToken:   createCSRFToken(ip),
-		CSPNonce:    secure.CSPNonce(r.Context()),
-		StaticURL:   webStaticFilesPath,
-		RecoveryURL: webClientTwoFactorRecoveryPath,
-		Branding:    s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		Title:          pageTwoFactorTitle,
+		CurrentURL:     webClientTwoFactorPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		RecoveryURL:    webClientTwoFactorRecoveryPath,
+		Branding:       s.binding.Branding.WebClient,
 	}
 	if next := r.URL.Query().Get("next"); strings.HasPrefix(next, webClientFilesPath) {
 		data.CurrentURL += "?next=" + url.QueryEscape(next)
@@ -683,14 +674,13 @@ func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, r *http.R
 
 func (s *httpdServer) renderClientTwoFactorRecoveryPage(w http.ResponseWriter, r *http.Request, error, ip string) {
 	data := twoFactorPage{
-		Title:      pageTwoFactorRecoveryTitle,
-		CurrentURL: webClientTwoFactorRecoveryPath,
-		Version:    version.Get().Version,
-		Error:      error,
-		CSRFToken:  createCSRFToken(ip),
-		CSPNonce:   secure.CSPNonce(r.Context()),
-		StaticURL:  webStaticFilesPath,
-		Branding:   s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		Title:          pageTwoFactorRecoveryTitle,
+		CurrentURL:     webClientTwoFactorRecoveryPath,
+		Version:        version.Get().Version,
+		Error:          error,
+		CSRFToken:      createCSRFToken(ip),
+		Branding:       s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateTwoFactorRecovery, data)
 }
@@ -1088,12 +1078,11 @@ func (s *httpdServer) handleShareViewPDF(w http.ResponseWriter, r *http.Request)
 	}
 	name := util.CleanPath(r.URL.Query().Get("path"))
 	data := viewPDFPage{
-		Title: path.Base(name),
+		commonBasePage: getCommonBasePage(r),
+		Title:          path.Base(name),
 		URL: fmt.Sprintf("%s?path=%s&_=%d", path.Join(webClientPubSharesPath, share.ShareID, "getpdf"),
 			url.QueryEscape(name), time.Now().UTC().Unix()),
-		StaticURL: webStaticFilesPath,
-		CSPNonce:  secure.CSPNonce(r.Context()),
-		Branding:  s.binding.Branding.WebClient,
+		Branding: s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateClientViewPDF, data)
 }
@@ -1704,11 +1693,10 @@ func (s *httpdServer) handleClientViewPDF(w http.ResponseWriter, r *http.Request
 	}
 	name = util.CleanPath(name)
 	data := viewPDFPage{
-		Title:     path.Base(name),
-		URL:       fmt.Sprintf("%s?path=%s&_=%d", webClientGetPDFPath, url.QueryEscape(name), time.Now().UTC().Unix()),
-		StaticURL: webStaticFilesPath,
-		CSPNonce:  secure.CSPNonce(r.Context()),
-		Branding:  s.binding.Branding.WebClient,
+		commonBasePage: getCommonBasePage(r),
+		Title:          path.Base(name),
+		URL:            fmt.Sprintf("%s?path=%s&_=%d", webClientGetPDFPath, url.QueryEscape(name), time.Now().UTC().Unix()),
+		Branding:       s.binding.Branding.WebClient,
 	}
 	renderClientTemplate(w, templateClientViewPDF, data)
 }