From 74836af66e13695a5acb3f4deca6d1983b051ec6 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sat, 25 Nov 2023 18:30:56 +0100 Subject: [PATCH] WebUI: extract a common struct for all pages Signed-off-by: Nicola Murino --- internal/httpd/server.go | 30 ++++---- internal/httpd/web.go | 27 +++++-- internal/httpd/webadmin.go | 65 +++++++--------- internal/httpd/webclient.go | 148 +++++++++++++++++------------------- 4 files changed, 130 insertions(+), 140 deletions(-) diff --git a/internal/httpd/server.go b/internal/httpd/server.go index cf40f90d..ce6bfce1 100644 --- a/internal/httpd/server.go +++ b/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 diff --git a/internal/httpd/web.go b/internal/httpd/web.go index ccb99b22..03abe3e7 100644 --- a/internal/httpd/web.go +++ b/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, + } +} diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 971fdddc..dbbabe83 100644 --- a/internal/httpd/webadmin.go +++ b/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) } diff --git a/internal/httpd/webclient.go b/internal/httpd/webclient.go index dd02be5e..4489ed8a 100644 --- a/internal/httpd/webclient.go +++ b/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) }