Web UI: propagate CSPNonce to templates

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-11-15 18:48:16 +01:00
parent d32d0d7587
commit 37b0c229fc
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
16 changed files with 140 additions and 108 deletions

View file

@ -166,6 +166,7 @@ func (s *httpdServer) renderClientLoginPage(w http.ResponseWriter, r *http.Reque
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
FormDisabled: s.binding.isWebClientLoginFormDisabled(), FormDisabled: s.binding.isWebClientLoginFormDisabled(),
@ -445,17 +446,17 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
} }
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
s.renderTwoFactorRecoveryPage(w, err.Error(), ipAddr) s.renderTwoFactorRecoveryPage(w, r, err.Error(), ipAddr)
return return
} }
username := claims.Username username := claims.Username
recoveryCode := strings.TrimSpace(r.Form.Get("recovery_code")) recoveryCode := strings.TrimSpace(r.Form.Get("recovery_code"))
if username == "" || recoveryCode == "" { if username == "" || recoveryCode == "" {
s.renderTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr) s.renderTwoFactorRecoveryPage(w, r, "Invalid credentials", ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderTwoFactorRecoveryPage(w, err.Error(), ipAddr) s.renderTwoFactorRecoveryPage(w, r, err.Error(), ipAddr)
return return
} }
admin, err := dataprovider.AdminExists(username) admin, err := dataprovider.AdminExists(username)
@ -463,11 +464,11 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
if errors.Is(err, util.ErrNotFound) { if errors.Is(err, util.ErrNotFound) {
handleDefenderEventLoginFailed(ipAddr, err) //nolint:errcheck handleDefenderEventLoginFailed(ipAddr, err) //nolint:errcheck
} }
s.renderTwoFactorRecoveryPage(w, "Invalid credentials", ipAddr) s.renderTwoFactorRecoveryPage(w, r, "Invalid credentials", ipAddr)
return return
} }
if !admin.Filters.TOTPConfig.Enabled { if !admin.Filters.TOTPConfig.Enabled {
s.renderTwoFactorRecoveryPage(w, "Two factory authentication is not enabled", ipAddr) s.renderTwoFactorRecoveryPage(w, r, "Two factory authentication is not enabled", ipAddr)
return return
} }
for idx, code := range admin.Filters.RecoveryCodes { for idx, code := range admin.Filters.RecoveryCodes {
@ -477,7 +478,7 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
} }
if code.Secret.GetPayload() == recoveryCode { if code.Secret.GetPayload() == recoveryCode {
if code.Used { if code.Used {
s.renderTwoFactorRecoveryPage(w, "This recovery code was already used", ipAddr) s.renderTwoFactorRecoveryPage(w, r, "This recovery code was already used", ipAddr)
return return
} }
admin.Filters.RecoveryCodes[idx].Used = true admin.Filters.RecoveryCodes[idx].Used = true
@ -492,7 +493,7 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter,
} }
} }
handleDefenderEventLoginFailed(ipAddr, dataprovider.ErrInvalidCredentials) //nolint:errcheck handleDefenderEventLoginFailed(ipAddr, dataprovider.ErrInvalidCredentials) //nolint:errcheck
s.renderTwoFactorRecoveryPage(w, "Invalid recovery code", ipAddr) s.renderTwoFactorRecoveryPage(w, r, "Invalid recovery code", ipAddr)
} }
func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http.Request) {
@ -504,18 +505,18 @@ func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http
} }
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
s.renderTwoFactorPage(w, err.Error(), ipAddr) s.renderTwoFactorPage(w, r, err.Error(), ipAddr)
return return
} }
username := claims.Username username := claims.Username
passcode := strings.TrimSpace(r.Form.Get("passcode")) passcode := strings.TrimSpace(r.Form.Get("passcode"))
if username == "" || passcode == "" { if username == "" || passcode == "" {
s.renderTwoFactorPage(w, "Invalid credentials", ipAddr) s.renderTwoFactorPage(w, r, "Invalid credentials", ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
err = handleDefenderEventLoginFailed(ipAddr, err) err = handleDefenderEventLoginFailed(ipAddr, err)
s.renderTwoFactorPage(w, err.Error(), ipAddr) s.renderTwoFactorPage(w, r, err.Error(), ipAddr)
return return
} }
admin, err := dataprovider.AdminExists(username) admin, err := dataprovider.AdminExists(username)
@ -523,11 +524,11 @@ func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http
if errors.Is(err, util.ErrNotFound) { if errors.Is(err, util.ErrNotFound) {
handleDefenderEventLoginFailed(ipAddr, err) //nolint:errcheck handleDefenderEventLoginFailed(ipAddr, err) //nolint:errcheck
} }
s.renderTwoFactorPage(w, "Invalid credentials", ipAddr) s.renderTwoFactorPage(w, r, "Invalid credentials", ipAddr)
return return
} }
if !admin.Filters.TOTPConfig.Enabled { if !admin.Filters.TOTPConfig.Enabled {
s.renderTwoFactorPage(w, "Two factory authentication is not enabled", ipAddr) s.renderTwoFactorPage(w, r, "Two factory authentication is not enabled", ipAddr)
return return
} }
err = admin.Filters.TOTPConfig.Secret.Decrypt() err = admin.Filters.TOTPConfig.Secret.Decrypt()
@ -539,7 +540,7 @@ func (s *httpdServer) handleWebAdminTwoFactorPost(w http.ResponseWriter, r *http
admin.Filters.TOTPConfig.Secret.GetPayload()) admin.Filters.TOTPConfig.Secret.GetPayload())
if !match || err != nil { if !match || err != nil {
handleDefenderEventLoginFailed(ipAddr, dataprovider.ErrInvalidCredentials) //nolint:errcheck handleDefenderEventLoginFailed(ipAddr, dataprovider.ErrInvalidCredentials) //nolint:errcheck
s.renderTwoFactorPage(w, "Invalid authentication code", ipAddr) s.renderTwoFactorPage(w, r, "Invalid authentication code", ipAddr)
return return
} }
s.loginAdmin(w, r, &admin, true, s.renderTwoFactorPage, ipAddr) s.loginAdmin(w, r, &admin, true, s.renderTwoFactorPage, ipAddr)
@ -550,34 +551,35 @@ func (s *httpdServer) handleWebAdminLoginPost(w http.ResponseWriter, r *http.Req
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
s.renderAdminLoginPage(w, err.Error(), ipAddr) s.renderAdminLoginPage(w, r, err.Error(), ipAddr)
return return
} }
username := strings.TrimSpace(r.Form.Get("username")) username := strings.TrimSpace(r.Form.Get("username"))
password := strings.TrimSpace(r.Form.Get("password")) password := strings.TrimSpace(r.Form.Get("password"))
if username == "" || password == "" { if username == "" || password == "" {
s.renderAdminLoginPage(w, "Invalid credentials", ipAddr) s.renderAdminLoginPage(w, r, "Invalid credentials", ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
s.renderAdminLoginPage(w, err.Error(), ipAddr) s.renderAdminLoginPage(w, r, err.Error(), ipAddr)
return return
} }
admin, err := dataprovider.CheckAdminAndPass(username, password, ipAddr) admin, err := dataprovider.CheckAdminAndPass(username, password, ipAddr)
if err != nil { if err != nil {
err = handleDefenderEventLoginFailed(ipAddr, err) err = handleDefenderEventLoginFailed(ipAddr, err)
s.renderAdminLoginPage(w, err.Error(), ipAddr) s.renderAdminLoginPage(w, r, err.Error(), ipAddr)
return return
} }
s.loginAdmin(w, r, &admin, false, s.renderAdminLoginPage, ipAddr) s.loginAdmin(w, r, &admin, false, s.renderAdminLoginPage, ipAddr)
} }
func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderAdminLoginPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := loginPage{ data := loginPage{
CurrentURL: webAdminLoginPath, CurrentURL: webAdminLoginPath,
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
FormDisabled: s.binding.isWebAdminLoginFormDisabled(), FormDisabled: s.binding.isWebAdminLoginFormDisabled(),
@ -601,7 +603,7 @@ func (s *httpdServer) handleWebAdminLogin(w http.ResponseWriter, r *http.Request
http.Redirect(w, r, webAdminSetupPath, http.StatusFound) http.Redirect(w, r, webAdminSetupPath, http.StatusFound)
return return
} }
s.renderAdminLoginPage(w, getFlashMessage(w, r), util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderAdminLoginPage(w, r, getFlashMessage(w, r), util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebAdminLogout(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminLogout(w http.ResponseWriter, r *http.Request) {
@ -639,7 +641,7 @@ func (s *httpdServer) handleWebAdminPasswordResetPost(w http.ResponseWriter, r *
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
s.renderResetPwdPage(w, err.Error(), ipAddr) s.renderResetPwdPage(w, r, err.Error(), ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
@ -650,10 +652,10 @@ func (s *httpdServer) handleWebAdminPasswordResetPost(w http.ResponseWriter, r *
strings.TrimSpace(r.Form.Get("password")), true) strings.TrimSpace(r.Form.Get("password")), true)
if err != nil { if err != nil {
if e, ok := err.(*util.ValidationError); ok { if e, ok := err.(*util.ValidationError); ok {
s.renderResetPwdPage(w, e.GetErrorString(), ipAddr) s.renderResetPwdPage(w, r, e.GetErrorString(), ipAddr)
return return
} }
s.renderResetPwdPage(w, err.Error(), ipAddr) s.renderResetPwdPage(w, r, err.Error(), ipAddr)
return return
} }
@ -759,7 +761,7 @@ func (s *httpdServer) loginUser(
func (s *httpdServer) loginAdmin( func (s *httpdServer) loginAdmin(
w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin, w http.ResponseWriter, r *http.Request, admin *dataprovider.Admin,
isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, error, ip string), isSecondFactorAuth bool, errorFunc func(w http.ResponseWriter, r *http.Request, error, ip string),
ipAddr string, ipAddr string,
) { ) {
c := jwtTokenClaims{ c := jwtTokenClaims{
@ -782,7 +784,7 @@ func (s *httpdServer) loginAdmin(
s.renderAdminSetupPage(w, r, admin.Username, err.Error()) s.renderAdminSetupPage(w, r, admin.Username, err.Error())
return return
} }
errorFunc(w, err.Error(), ipAddr) errorFunc(w, r, err.Error(), ipAddr)
return return
} }
if isSecondFactorAuth { if isSecondFactorAuth {

View file

@ -44,6 +44,7 @@ type loginPage struct {
Version string Version string
Error string Error string
CSRFToken string CSRFToken string
CSPNonce string
StaticURL string StaticURL string
AltLoginURL string AltLoginURL string
AltLoginName string AltLoginName string
@ -58,6 +59,7 @@ type twoFactorPage struct {
Version string Version string
Error string Error string
CSRFToken string CSRFToken string
CSPNonce string
StaticURL string StaticURL string
RecoveryURL string RecoveryURL string
Branding UIBranding Branding UIBranding
@ -67,6 +69,7 @@ type forgotPwdPage struct {
CurrentURL string CurrentURL string
Error string Error string
CSRFToken string CSRFToken string
CSPNonce string
StaticURL string StaticURL string
LoginURL string LoginURL string
Title string Title string
@ -77,6 +80,7 @@ type resetPwdPage struct {
CurrentURL string CurrentURL string
Error string Error string
CSRFToken string CSRFToken string
CSPNonce string
StaticURL string StaticURL string
LoginURL string LoginURL string
Title string Title string

View file

@ -32,6 +32,7 @@ import (
"github.com/go-chi/render" "github.com/go-chi/render"
"github.com/sftpgo/sdk" "github.com/sftpgo/sdk"
sdkkms "github.com/sftpgo/sdk/kms" sdkkms "github.com/sftpgo/sdk/kms"
"github.com/unrolled/secure"
"github.com/drakkan/sftpgo/v2/internal/acme" "github.com/drakkan/sftpgo/v2/internal/acme"
"github.com/drakkan/sftpgo/v2/internal/common" "github.com/drakkan/sftpgo/v2/internal/common"
@ -180,6 +181,7 @@ type basePage struct {
ConfigsTitle string ConfigsTitle string
Version string Version string
CSRFToken string CSRFToken string
CSPNonce string
IsEventManagerPage bool IsEventManagerPage bool
IsIPManagerPage bool IsIPManagerPage bool
IsServerManagerPage bool IsServerManagerPage bool
@ -751,6 +753,7 @@ func (s *httpdServer) getBasePageData(title, currentURL string, r *http.Request)
HasSearcher: plugin.Handler.HasSearcher(), HasSearcher: plugin.Handler.HasSearcher(),
HasExternalLogin: isLoggedInWithOIDC(r), HasExternalLogin: isLoggedInWithOIDC(r),
CSRFToken: csrfToken, CSRFToken: csrfToken,
CSPNonce: secure.CSPNonce(r.Context()),
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
} }
} }
@ -797,11 +800,12 @@ func (s *httpdServer) renderNotFoundPage(w http.ResponseWriter, r *http.Request,
s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "") s.renderMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
} }
func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := forgotPwdPage{ data := forgotPwdPage{
CurrentURL: webAdminForgotPwdPath, CurrentURL: webAdminForgotPwdPath,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Title: pageForgotPwdTitle, Title: pageForgotPwdTitle,
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
@ -809,11 +813,12 @@ func (s *httpdServer) renderForgotPwdPage(w http.ResponseWriter, error, ip strin
renderAdminTemplate(w, templateForgotPassword, data) renderAdminTemplate(w, templateForgotPassword, data)
} }
func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := resetPwdPage{ data := resetPwdPage{
CurrentURL: webAdminResetPwdPath, CurrentURL: webAdminResetPwdPath,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Title: pageResetPwdTitle, Title: pageResetPwdTitle,
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
@ -821,12 +826,13 @@ func (s *httpdServer) renderResetPwdPage(w http.ResponseWriter, error, ip string
renderAdminTemplate(w, templateResetPassword, data) renderAdminTemplate(w, templateResetPassword, data)
} }
func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := twoFactorPage{ data := twoFactorPage{
CurrentURL: webAdminTwoFactorPath, CurrentURL: webAdminTwoFactorPath,
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
RecoveryURL: webAdminTwoFactorRecoveryPath, RecoveryURL: webAdminTwoFactorRecoveryPath,
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
@ -834,12 +840,13 @@ func (s *httpdServer) renderTwoFactorPage(w http.ResponseWriter, error, ip strin
renderAdminTemplate(w, templateTwoFactor, data) renderAdminTemplate(w, templateTwoFactor, data)
} }
func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderTwoFactorRecoveryPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := twoFactorPage{ data := twoFactorPage{
CurrentURL: webAdminTwoFactorRecoveryPath, CurrentURL: webAdminTwoFactorRecoveryPath,
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Branding: s.binding.Branding.WebAdmin, Branding: s.binding.Branding.WebAdmin,
} }
@ -2634,7 +2641,7 @@ func (s *httpdServer) handleWebAdminForgotPwd(w http.ResponseWriter, r *http.Req
s.renderNotFoundPage(w, r, errors.New("this page does not exist")) s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
return return
} }
s.renderForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderForgotPwdPage(w, r, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http.Request) {
@ -2643,7 +2650,7 @@ func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
s.renderForgotPwdPage(w, err.Error(), ipAddr) s.renderForgotPwdPage(w, r, err.Error(), ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
@ -2653,10 +2660,10 @@ func (s *httpdServer) handleWebAdminForgotPwdPost(w http.ResponseWriter, r *http
err = handleForgotPassword(r, r.Form.Get("username"), true) err = handleForgotPassword(r, r.Form.Get("username"), true)
if err != nil { if err != nil {
if e, ok := err.(*util.ValidationError); ok { if e, ok := err.(*util.ValidationError); ok {
s.renderForgotPwdPage(w, e.GetErrorString(), ipAddr) s.renderForgotPwdPage(w, r, e.GetErrorString(), ipAddr)
return return
} }
s.renderForgotPwdPage(w, err.Error(), ipAddr) s.renderForgotPwdPage(w, r, err.Error(), ipAddr)
return return
} }
http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound) http.Redirect(w, r, webAdminResetPwdPath, http.StatusFound)
@ -2668,17 +2675,17 @@ func (s *httpdServer) handleWebAdminPasswordReset(w http.ResponseWriter, r *http
s.renderNotFoundPage(w, r, errors.New("this page does not exist")) s.renderNotFoundPage(w, r, errors.New("this page does not exist"))
return return
} }
s.renderResetPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderResetPwdPage(w, r, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminTwoFactor(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderTwoFactorPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderTwoFactorPage(w, r, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminTwoFactorRecovery(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
s.renderTwoFactorRecoveryPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderTwoFactorRecoveryPage(w, r, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebAdminMFA(w http.ResponseWriter, r *http.Request) {

View file

@ -34,6 +34,7 @@ import (
"github.com/go-chi/render" "github.com/go-chi/render"
"github.com/rs/xid" "github.com/rs/xid"
"github.com/sftpgo/sdk" "github.com/sftpgo/sdk"
"github.com/unrolled/secure"
"github.com/drakkan/sftpgo/v2/internal/common" "github.com/drakkan/sftpgo/v2/internal/common"
"github.com/drakkan/sftpgo/v2/internal/dataprovider" "github.com/drakkan/sftpgo/v2/internal/dataprovider"
@ -115,6 +116,7 @@ type baseClientPage struct {
ProfileTitle string ProfileTitle string
Version string Version string
CSRFToken string CSRFToken string
CSPNonce string
LoggedUser *dataprovider.User LoggedUser *dataprovider.User
Branding UIBranding Branding UIBranding
} }
@ -128,6 +130,7 @@ type viewPDFPage struct {
Title string Title string
URL string URL string
StaticURL string StaticURL string
CSPNonce string
Branding UIBranding Branding UIBranding
} }
@ -553,6 +556,7 @@ func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Re
ProfileTitle: pageClientProfileTitle, ProfileTitle: pageClientProfileTitle,
Version: fmt.Sprintf("%v-%v", v.Version, v.CommitHash), Version: fmt.Sprintf("%v-%v", v.Version, v.CommitHash),
CSRFToken: csrfToken, CSRFToken: csrfToken,
CSPNonce: secure.CSPNonce(r.Context()),
LoggedUser: getUserFromToken(r), LoggedUser: getUserFromToken(r),
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
} }
@ -562,11 +566,12 @@ func (s *httpdServer) getBaseClientPageData(title, currentURL string, r *http.Re
return data return data
} }
func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, error, ip string) { func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := forgotPwdPage{ data := forgotPwdPage{
CurrentURL: webClientForgotPwdPath, CurrentURL: webClientForgotPwdPath,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
LoginURL: webClientLoginPath, LoginURL: webClientLoginPath,
Title: pageClientForgotPwdTitle, Title: pageClientForgotPwdTitle,
@ -575,11 +580,12 @@ func (s *httpdServer) renderClientForgotPwdPage(w http.ResponseWriter, error, ip
renderClientTemplate(w, templateForgotPassword, data) renderClientTemplate(w, templateForgotPassword, data)
} }
func (s *httpdServer) renderClientResetPwdPage(w http.ResponseWriter, _ *http.Request, error, ip string) { func (s *httpdServer) renderClientResetPwdPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := resetPwdPage{ data := resetPwdPage{
CurrentURL: webClientResetPwdPath, CurrentURL: webClientResetPwdPath,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
LoginURL: webClientLoginPath, LoginURL: webClientLoginPath,
Title: pageClientResetPwdTitle, Title: pageClientResetPwdTitle,
@ -647,6 +653,7 @@ func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, r *http.R
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
RecoveryURL: webClientTwoFactorRecoveryPath, RecoveryURL: webClientTwoFactorRecoveryPath,
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
@ -657,12 +664,13 @@ func (s *httpdServer) renderClientTwoFactorPage(w http.ResponseWriter, r *http.R
renderClientTemplate(w, templateTwoFactor, data) renderClientTemplate(w, templateTwoFactor, data)
} }
func (s *httpdServer) renderClientTwoFactorRecoveryPage(w http.ResponseWriter, _ *http.Request, error, ip string) { func (s *httpdServer) renderClientTwoFactorRecoveryPage(w http.ResponseWriter, r *http.Request, error, ip string) {
data := twoFactorPage{ data := twoFactorPage{
CurrentURL: webClientTwoFactorRecoveryPath, CurrentURL: webClientTwoFactorRecoveryPath,
Version: version.Get().Version, Version: version.Get().Version,
Error: error, Error: error,
CSRFToken: createCSRFToken(ip), CSRFToken: createCSRFToken(ip),
CSPNonce: secure.CSPNonce(r.Context()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
} }
@ -1056,6 +1064,7 @@ func (s *httpdServer) handleShareViewPDF(w http.ResponseWriter, r *http.Request)
URL: fmt.Sprintf("%s?path=%s&_=%d", path.Join(webClientPubSharesPath, share.ShareID, "getpdf"), URL: fmt.Sprintf("%s?path=%s&_=%d", path.Join(webClientPubSharesPath, share.ShareID, "getpdf"),
url.QueryEscape(name), time.Now().UTC().Unix()), url.QueryEscape(name), time.Now().UTC().Unix()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
CSPNonce: secure.CSPNonce(r.Context()),
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
} }
renderClientTemplate(w, templateClientViewPDF, data) renderClientTemplate(w, templateClientViewPDF, data)
@ -1618,7 +1627,7 @@ func (s *httpdServer) handleWebClientForgotPwd(w http.ResponseWriter, r *http.Re
s.renderClientNotFoundPage(w, r, errors.New("this page does not exist")) s.renderClientNotFoundPage(w, r, errors.New("this page does not exist"))
return return
} }
s.renderClientForgotPwdPage(w, "", util.GetIPFromRemoteAddress(r.RemoteAddr)) s.renderClientForgotPwdPage(w, r, "", util.GetIPFromRemoteAddress(r.RemoteAddr))
} }
func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *http.Request) { func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *http.Request) {
@ -1627,7 +1636,7 @@ func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *htt
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
s.renderClientForgotPwdPage(w, err.Error(), ipAddr) s.renderClientForgotPwdPage(w, r, err.Error(), ipAddr)
return return
} }
if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil { if err := verifyCSRFToken(r.Form.Get(csrfFormToken), ipAddr); err != nil {
@ -1638,10 +1647,10 @@ func (s *httpdServer) handleWebClientForgotPwdPost(w http.ResponseWriter, r *htt
err = handleForgotPassword(r, username, false) err = handleForgotPassword(r, username, false)
if err != nil { if err != nil {
if e, ok := err.(*util.ValidationError); ok { if e, ok := err.(*util.ValidationError); ok {
s.renderClientForgotPwdPage(w, e.GetErrorString(), ipAddr) s.renderClientForgotPwdPage(w, r, e.GetErrorString(), ipAddr)
return return
} }
s.renderClientForgotPwdPage(w, err.Error(), ipAddr) s.renderClientForgotPwdPage(w, r, err.Error(), ipAddr)
return return
} }
http.Redirect(w, r, webClientResetPwdPath, http.StatusFound) http.Redirect(w, r, webClientResetPwdPath, http.StatusFound)
@ -1668,6 +1677,7 @@ func (s *httpdServer) handleClientViewPDF(w http.ResponseWriter, r *http.Request
Title: path.Base(name), Title: path.Base(name),
URL: fmt.Sprintf("%s?path=%s&_=%d", webClientGetPDFPath, url.QueryEscape(name), time.Now().UTC().Unix()), URL: fmt.Sprintf("%s?path=%s&_=%d", webClientGetPDFPath, url.QueryEscape(name), time.Now().UTC().Unix()),
StaticURL: webStaticFilesPath, StaticURL: webStaticFilesPath,
CSPNonce: secure.CSPNonce(r.Context()),
Branding: s.binding.Branding.WebClient, Branding: s.binding.Branding.WebClient,
} }
renderClientTemplate(w, templateClientViewPDF, data) renderClientTemplate(w, templateClientViewPDF, data)

View file

@ -33,7 +33,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "theme-setup"}} {{- define "theme-setup"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .}} nonce="{{.}}"{{- end}}>
var defaultThemeMode = "system"; var defaultThemeMode = "system";
var themeMode; var themeMode;
if ( document.documentElement ) { if ( document.documentElement ) {
@ -55,11 +55,13 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end }} {{- end }}
{{- define "commonjs"}} {{- define "commonjs"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .}} nonce="{{.}}"{{- end}}>
if (window.top != window.self) { if (window.top != window.self) {
window.top.location.replace(window.self.location.href); window.top.location.replace(window.self.location.href);
} }
//{{- if .}}
window.VIDEOJS_NO_DYNAMIC_STYLE = true
//{{- end }}
window.addEventListener("pageshow", function (event) { window.addEventListener("pageshow", function (event) {
if (event.persisted) { if (event.persisted) {
let loadings = document.querySelectorAll('[data-kt-indicator=on]'); let loadings = document.querySelectorAll('[data-kt-indicator=on]');
@ -75,7 +77,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "basejs"}} {{- define "basejs"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .}} nonce="{{.}}"{{- end}}>
function escapeHTML(str) { function escapeHTML(str) {
var div = document.createElement('div'); var div = document.createElement('div');
div.appendChild(document.createTextNode(str)); div.appendChild(document.createTextNode(str));
@ -141,7 +143,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "globalstyle"}} {{- define "globalstyle"}}
<style> <style {{- if .}} nonce="{{.}}"{{- end}}>
.text-sidebar { .text-sidebar {
color: var(--bs-white); color: var(--bs-white);
} }
@ -161,13 +163,13 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "fonts"}} {{- define "fonts"}}
<style> <style {{- if .}} nonce="{{.CSPNonce}}"{{- end}}>
/* cyrillic-ext */ /* cyrillic-ext */
@font-face { @font-face {
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
} }
@ -176,7 +178,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
} }
@ -185,7 +187,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
unicode-range: U+1F00-1FFF; unicode-range: U+1F00-1FFF;
} }
@ -194,7 +196,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
unicode-range: U+0370-03FF; unicode-range: U+0370-03FF;
} }
@ -203,7 +205,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
} }
@ -212,7 +214,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
@ -221,7 +223,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
@ -230,7 +232,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
} }
@ -239,7 +241,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
} }
@ -248,7 +250,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
unicode-range: U+1F00-1FFF; unicode-range: U+1F00-1FFF;
} }
@ -257,7 +259,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
unicode-range: U+0370-03FF; unicode-range: U+0370-03FF;
} }
@ -266,7 +268,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
} }
@ -275,7 +277,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
@ -284,7 +286,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
@ -293,7 +295,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
} }
@ -302,7 +304,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
} }
@ -311,7 +313,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
unicode-range: U+1F00-1FFF; unicode-range: U+1F00-1FFF;
} }
@ -320,7 +322,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
unicode-range: U+0370-03FF; unicode-range: U+0370-03FF;
} }
@ -329,7 +331,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
} }
@ -338,7 +340,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
@ -347,7 +349,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
@ -356,7 +358,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
} }
@ -365,7 +367,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
} }
@ -374,7 +376,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
unicode-range: U+1F00-1FFF; unicode-range: U+1F00-1FFF;
} }
@ -383,7 +385,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
unicode-range: U+0370-03FF; unicode-range: U+0370-03FF;
} }
@ -392,7 +394,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
} }
@ -401,7 +403,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
@ -410,7 +412,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
@ -419,7 +421,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
} }
@ -428,7 +430,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
} }
@ -437,7 +439,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2) format('woff2');
unicode-range: U+1F00-1FFF; unicode-range: U+1F00-1FFF;
} }
@ -446,7 +448,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2) format('woff2');
unicode-range: U+0370-03FF; unicode-range: U+0370-03FF;
} }
@ -455,7 +457,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
} }
@ -464,7 +466,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
} }
@ -473,7 +475,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url({{.}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2'); src: url({{.StaticURL}}/vendor/fonts/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
</style> </style>

View file

@ -22,20 +22,20 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<meta name="description" content="" /> <meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="{{.StaticURL}}{{.Branding.FaviconPath}}" /> <link rel="shortcut icon" href="{{.StaticURL}}{{.Branding.FaviconPath}}" />
{{- template "fonts" .StaticURL }} {{- template "fonts" . }}
{{- range .Branding.DefaultCSS}} {{- range .Branding.DefaultCSS}}
<link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css"> <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
{{- end}} {{- end}}
{{- template "globalstyle" }} {{- template "globalstyle" .CSPNonce }}
{{- block "extra_css" .}}{{- end}} {{- block "extra_css" .}}{{- end}}
{{- range .Branding.ExtraCSS}} {{- range .Branding.ExtraCSS}}
<link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css"> <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
{{- end}} {{- end}}
{{- template "commonjs" }} {{- template "commonjs" .CSPNonce }}
</head> </head>
<body data-kt-app-header-fixed="true" data-kt-app-header-fixed-mobile="true" data-kt-app-toolbar-enabled="true" data-kt-app-sidebar-enabled="true" data-kt-app-sidebar-fixed="true" data-kt-app-sidebar-push-header="true" data-kt-app-sidebar-push-toolbar="true" data-kt-app-sidebar-push-footer="true" class="app-default"> <body data-kt-app-header-fixed="true" data-kt-app-header-fixed-mobile="true" data-kt-app-toolbar-enabled="true" data-kt-app-sidebar-enabled="true" data-kt-app-sidebar-fixed="true" data-kt-app-sidebar-push-header="true" data-kt-app-sidebar-push-toolbar="true" data-kt-app-sidebar-push-footer="true" class="app-default">
{{- template "theme-setup"}} {{- template "theme-setup" .CSPNonce }}
<div class="d-flex flex-column flex-root app-root" id="kt_app_root"> <div class="d-flex flex-column flex-root app-root" id="kt_app_root">
<div class="app-page flex-column flex-column-fluid " id="kt_app_page"> <div class="app-page flex-column flex-column-fluid " id="kt_app_page">
{{- if .LoggedUser.Username}} {{- if .LoggedUser.Username}}
@ -294,8 +294,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- block "modals" .}}{{- end}} {{- block "modals" .}}{{- end}}
<script src="{{.StaticURL}}/assets/plugins/global/plugins.bundle.js"></script> <script src="{{.StaticURL}}/assets/plugins/global/plugins.bundle.js"></script>
<script src="{{.StaticURL}}/assets/js/scripts.bundle.js"></script> <script src="{{.StaticURL}}/assets/js/scripts.bundle.js"></script>
{{- template "basejs" }} {{- template "basejs" .CSPNonce }}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
var ModalAlert = function () { var ModalAlert = function () {
var modal; var modal;
var promiseResolve; var promiseResolve;

View file

@ -22,19 +22,19 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<meta name="description" content="" /> <meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="{{.StaticURL}}{{.Branding.FaviconPath}}" /> <link rel="shortcut icon" href="{{.StaticURL}}{{.Branding.FaviconPath}}" />
{{- template "fonts" .StaticURL }} {{- template "fonts" . }}
{{- range .Branding.DefaultCSS}} {{- range .Branding.DefaultCSS}}
<link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css"> <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
{{- end}} {{- end}}
{{- template "globalstyle" }} {{- template "globalstyle" .CSPNonce }}
{{- range .Branding.ExtraCSS}} {{- range .Branding.ExtraCSS}}
<link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css"> <link href="{{$.StaticURL}}{{.}}" rel="stylesheet" type="text/css">
{{- end}} {{- end}}
{{- template "commonjs" }} {{- template "commonjs" .CSPNonce}}
</head> </head>
<body class="app-blank"> <body class="app-blank">
{{- template "theme-setup"}} {{- template "theme-setup" .CSPNonce}}
<div class="d-flex flex-column flex-root"> <div class="d-flex flex-column flex-root">
<div class="d-flex flex-column flex-column-fluid bgi-position-y-bottom position-x-center bgi-no-repeat bgi-size-contain bgi-attachment-fixed"> <div class="d-flex flex-column flex-column-fluid bgi-position-y-bottom position-x-center bgi-no-repeat bgi-size-contain bgi-attachment-fixed">
<div class="d-flex flex-center flex-column flex-column-fluid p-10 pb-lg-20"> <div class="d-flex flex-center flex-column flex-column-fluid p-10 pb-lg-20">
@ -46,8 +46,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div> </div>
<script src="{{.StaticURL}}/assets/plugins/global/plugins.bundle.js"></script> <script src="{{.StaticURL}}/assets/plugins/global/plugins.bundle.js"></script>
<script src="{{.StaticURL}}/assets/js/scripts.bundle.js"></script> <script src="{{.StaticURL}}/assets/js/scripts.bundle.js"></script>
{{- template "basejs" }} {{- template "basejs" .CSPNonce }}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
KTUtil.onDOMContentLoaded(function () { KTUtil.onDOMContentLoaded(function () {
$('#sign_in_form').submit(function (event) { $('#sign_in_form').submit(function (event) {
let submitButton = document.querySelector('#sign_in_submit'); let submitButton = document.querySelector('#sign_in_submit');

View file

@ -63,7 +63,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{end}} {{end}}
{{- define "extra_js"}} {{- define "extra_js"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.}}"{{- end}}>
KTUtil.onDOMContentLoaded(function () { KTUtil.onDOMContentLoaded(function () {
$('#change_pwd_form').submit(function (event) { $('#change_pwd_form').submit(function (event) {
let submitButton = document.querySelector('#form_submit'); let submitButton = document.querySelector('#form_submit');

View file

@ -101,7 +101,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "extra_js"}} {{- define "extra_js"}}
<script src="{{.StaticURL}}/vendor/codemirror/cm6.bundle.min.js"></script> <script src="{{.StaticURL}}/vendor/codemirror/cm6.bundle.min.js"></script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.}}"{{- end}}>
var cmView; var cmView;
function keepAlive() { function keepAlive() {

View file

@ -170,7 +170,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<link href="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.css" rel="stylesheet" type="text/css"/> <link href="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.css" rel="stylesheet" type="text/css"/>
<link href="{{.StaticURL}}/vendor/glightbox/glightbox.min.css" rel="stylesheet" type="text/css"/> <link href="{{.StaticURL}}/vendor/glightbox/glightbox.min.css" rel="stylesheet" type="text/css"/>
<link href="{{.StaticURL}}/vendor/video-js/video-js.min.css" rel="stylesheet" type="text/css"/> <link href="{{.StaticURL}}/vendor/video-js/video-js.min.css" rel="stylesheet" type="text/css"/>
<style> <style {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
.gslide-description-bg { .gslide-description-bg {
background: var(--bs-app-bg-color) !important; background: var(--bs-app-bg-color) !important;
opacity: 0.9; opacity: 0.9;
@ -184,7 +184,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script> <script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script>
<script src="{{.StaticURL}}/vendor/video-js/video.min.js"></script> <script src="{{.StaticURL}}/vendor/video-js/video.min.js"></script>
{{- if not .ShareUploadBaseURL}} {{- if not .ShareUploadBaseURL}}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
const supportedEditExtensions = ["csv", "bat", "dyalog", "apl", "asc", "pgp", "sig", "asn", "asn1", "b", "bf", const supportedEditExtensions = ["csv", "bat", "dyalog", "apl", "asc", "pgp", "sig", "asn", "asn1", "b", "bf",
"c", "h", "ino", "cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx", "cob", "cpy", "cbl", "cs", "clj", "c", "h", "ino", "cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx", "cob", "cpy", "cbl", "cs", "clj",
"cljc", "cljx", "cljs", "gss", "cmake", "cmake.in", "coffee", "cl", "lisp", "el", "cyp", "cypher", "cljc", "cljx", "cljs", "gss", "cmake", "cmake.in", "coffee", "cl", "lisp", "el", "cyp", "cypher",
@ -205,7 +205,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
const supportedEditFilenames = ["readme", "dockerfile", "pkgbuild"] const supportedEditFilenames = ["readme", "dockerfile", "pkgbuild"]
</script> </script>
{{- end}} {{- end}}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
function keepAlive() { function keepAlive() {
//{{- if not .ShareUploadBaseURL}} //{{- if not .ShareUploadBaseURL}}
axios.get('{{.PingURL}}',{ axios.get('{{.PingURL}}',{
@ -382,7 +382,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
//{{- end}} //{{- end}}
</script> </script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
var KTDatatablesServerSide = function () { var KTDatatablesServerSide = function () {
// Shared variables // Shared variables
//var table; //var table;

View file

@ -60,7 +60,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="form-group row mt-10"> <div class="form-group row mt-10">
<label class="col-md-3 col-form-label">Configuration</label> <label class="col-md-3 col-form-label">Configuration</label>
<div class="col-md-9"> <div class="col-md-9">
<select id="id_config" name="config_name" onchange="onConfigChanged();" class="form-select" data-control="select2" data-hide-search="true"> <select id="id_config" name="config_name" class="form-select" data-control="select2" data-hide-search="true">
<option value="">None</option> <option value="">None</option>
{{range .TOTPConfigs}} {{range .TOTPConfigs}}
<option value="{{.}}" {{if eq . $.TOTPConfig.ConfigName}}selected{{end}}>{{.}}</option> <option value="{{.}}" {{if eq . $.TOTPConfig.ConfigName}}selected{{end}}>{{.}}</option>
@ -266,7 +266,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "extra_js"}} {{- define "extra_js"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
const qrModal = new bootstrap.Modal('#qrcode_modal'); const qrModal = new bootstrap.Modal('#qrcode_modal');
const recCodesModal = new bootstrap.Modal('#recovery_codes_modal'); const recCodesModal = new bootstrap.Modal('#recovery_codes_modal');
@ -685,6 +685,13 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}); });
} }
var configSelect = $('#id_config');
if (configSelect){
configSelect.on("change", function(){
onConfigChanged();
});
}
}); });
</script> </script>

View file

@ -139,7 +139,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "extra_js"}} {{- define "extra_js"}}
{{- if .LoggedUser.CanManagePublicKeys}} {{- if .LoggedUser.CanManagePublicKeys}}
<script src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script> <script src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.}}"{{- end}}>
KTUtil.onDOMContentLoaded(function () { KTUtil.onDOMContentLoaded(function () {
$('#public_keys').repeater({ $('#public_keys').repeater({
initEmpty: false, initEmpty: false,

View file

@ -189,7 +189,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "extra_js"}} {{- define "extra_js"}}
<script src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script> <script src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
KTUtil.onDOMContentLoaded(function () { KTUtil.onDOMContentLoaded(function () {
$('#paths').repeater({ $('#paths').repeater({
initEmpty: false, initEmpty: false,

View file

@ -106,7 +106,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{define "extra_js"}} {{define "extra_js"}}
<script src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script> <script src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
function deleteAction(shareID) { function deleteAction(shareID) {
let errDivEl = $('#errorMsg'); let errDivEl = $('#errorMsg');

View file

@ -54,7 +54,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}} {{- end}}
{{- define "extra_js"}} {{- define "extra_js"}}
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.}}"{{- end}}>
function uploadFiles(files) { function uploadFiles(files) {
let has_errors = false; let has_errors = false;

View file

@ -27,7 +27,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<body> <body>
<script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script> <script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script>
<script type="text/javascript"> <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.}}"{{- end}}>
PDFObject.embed("{{.URL}}", document.body); PDFObject.embed("{{.URL}}", document.body);
</script> </script>
</body> </body>