satellite/console/consoleweb: remove templating for index.html

Previously, we evaluated index.html as a template in order to insert
frontend config values into meta tags. Now that the frontend fetches
its config through the satellite API, this is no longer necessary.

Resolves #5494

Change-Id: Ic98507c5e16cd80317bd9c31d4b55abda0dd7e34
This commit is contained in:
Jeremy Wharton 2023-04-05 17:35:01 -05:00
parent 6e866856c4
commit 45d5a93085
2 changed files with 37 additions and 172 deletions

View File

@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"html/template"
"io/fs"
"mime"
"net"
"net/http"
@ -30,7 +31,6 @@ import (
"golang.org/x/sync/errgroup"
"storj.io/common/errs2"
"storj.io/common/memory"
"storj.io/common/storj"
"storj.io/storj/private/web"
"storj.io/storj/satellite/abtesting"
@ -134,12 +134,7 @@ type Server struct {
schema graphql.Schema
templatesCache *templates
}
type templates struct {
index *template.Template
error *template.Template
errorTemplate *template.Template
}
// apiAuth exposes methods to control authentication process for each generated API endpoint.
@ -382,9 +377,9 @@ func (server *Server) Run(ctx context.Context) (err error) {
return Error.Wrap(err)
}
_, err = server.loadTemplates()
_, err = server.loadErrorTemplate()
if err != nil {
// TODO: should it return error if some template can not be initialized or just log about it?
// TODO: should it return error if the template cannot be initialized or just log about it?
return Error.Wrap(err)
}
@ -439,99 +434,32 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
header.Set("X-Content-Type-Options", "nosniff")
header.Set("Referrer-Policy", "same-origin") // Only expose the referring url when navigating around the satellite itself.
var data struct {
ExternalAddress string
SatelliteName string
SatelliteNodeURL string
StripePublicKey string
PartneredSatellites string
DefaultProjectLimit int
GeneralRequestURL string
ProjectLimitsIncreaseRequestURL string
GatewayCredentialsRequestURL string
IsBetaSatellite bool
BetaSatelliteFeedbackURL string
BetaSatelliteSupportURL string
DocumentationURL string
CouponCodeBillingUIEnabled bool
CouponCodeSignupUIEnabled bool
FileBrowserFlowDisabled bool
LinksharingURL string
PathwayOverviewEnabled bool
RegistrationRecaptchaEnabled bool
RegistrationRecaptchaSiteKey string
RegistrationHcaptchaEnabled bool
RegistrationHcaptchaSiteKey string
LoginRecaptchaEnabled bool
LoginRecaptchaSiteKey string
LoginHcaptchaEnabled bool
LoginHcaptchaSiteKey string
AllProjectsDashboard bool
DefaultPaidStorageLimit memory.Size
DefaultPaidBandwidthLimit memory.Size
InactivityTimerEnabled bool
InactivityTimerDuration int
InactivityTimerViewerEnabled bool
OptionalSignupSuccessURL string
HomepageURL string
NativeTokenPaymentsEnabled bool
PasswordMinimumLength int
PasswordMaximumLength int
ABTestingEnabled bool
PricingPackagesEnabled bool
}
data.ExternalAddress = server.config.ExternalAddress
data.SatelliteName = server.config.SatelliteName
data.SatelliteNodeURL = server.nodeURL.String()
data.StripePublicKey = server.stripePublicKey
data.PartneredSatellites = server.config.PartneredSatellites.String()
data.DefaultProjectLimit = server.config.DefaultProjectLimit
data.GeneralRequestURL = server.config.GeneralRequestURL
data.ProjectLimitsIncreaseRequestURL = server.config.ProjectLimitsIncreaseRequestURL
data.GatewayCredentialsRequestURL = server.config.GatewayCredentialsRequestURL
data.IsBetaSatellite = server.config.IsBetaSatellite
data.BetaSatelliteFeedbackURL = server.config.BetaSatelliteFeedbackURL
data.BetaSatelliteSupportURL = server.config.BetaSatelliteSupportURL
data.DocumentationURL = server.config.DocumentationURL
data.CouponCodeBillingUIEnabled = server.config.CouponCodeBillingUIEnabled
data.CouponCodeSignupUIEnabled = server.config.CouponCodeSignupUIEnabled
data.FileBrowserFlowDisabled = server.config.FileBrowserFlowDisabled
data.LinksharingURL = server.config.LinksharingURL
data.PathwayOverviewEnabled = server.config.PathwayOverviewEnabled
data.DefaultPaidStorageLimit = server.config.UsageLimits.Storage.Paid
data.DefaultPaidBandwidthLimit = server.config.UsageLimits.Bandwidth.Paid
data.RegistrationRecaptchaEnabled = server.config.Captcha.Registration.Recaptcha.Enabled
data.RegistrationRecaptchaSiteKey = server.config.Captcha.Registration.Recaptcha.SiteKey
data.RegistrationHcaptchaEnabled = server.config.Captcha.Registration.Hcaptcha.Enabled
data.RegistrationHcaptchaSiteKey = server.config.Captcha.Registration.Hcaptcha.SiteKey
data.LoginRecaptchaEnabled = server.config.Captcha.Login.Recaptcha.Enabled
data.LoginRecaptchaSiteKey = server.config.Captcha.Login.Recaptcha.SiteKey
data.LoginHcaptchaEnabled = server.config.Captcha.Login.Hcaptcha.Enabled
data.LoginHcaptchaSiteKey = server.config.Captcha.Login.Hcaptcha.SiteKey
data.AllProjectsDashboard = server.config.AllProjectsDashboard
data.InactivityTimerEnabled = server.config.Session.InactivityTimerEnabled
data.InactivityTimerDuration = server.config.Session.InactivityTimerDuration
data.InactivityTimerViewerEnabled = server.config.Session.InactivityTimerViewerEnabled
data.OptionalSignupSuccessURL = server.config.OptionalSignupSuccessURL
data.HomepageURL = server.config.HomepageURL
data.NativeTokenPaymentsEnabled = server.config.NativeTokenPaymentsEnabled
data.PasswordMinimumLength = console.PasswordMinimumLength
data.PasswordMaximumLength = console.PasswordMaximumLength
data.ABTestingEnabled = server.config.ABTesting.Enabled
data.PricingPackagesEnabled = server.config.PricingPackagesEnabled
templates, err := server.loadTemplates()
if err != nil || templates.index == nil {
server.log.Error("unable to load templates", zap.Error(err))
fmt.Fprintf(w, "Unable to load templates. See whether satellite UI has been built.")
path := filepath.Join(server.config.StaticDir, "dist", "index.html")
file, err := os.Open(path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
server.log.Error("index.html was not generated. run 'npm run build' in the "+server.config.StaticDir+" directory", zap.Error(err))
} else {
server.log.Error("error loading index.html", zap.String("path", path), zap.Error(err))
}
server.serveError(w, http.StatusInternalServerError)
return
}
if err := templates.index.Execute(w, data); err != nil {
server.log.Error("index template could not be executed", zap.Error(err))
defer func() {
if err := file.Close(); err != nil {
server.log.Error("error closing index.html", zap.String("path", path), zap.Error(err))
}
}()
info, err := file.Stat()
if err != nil {
server.log.Error("failed to retrieve file info", zap.Error(err))
server.serveError(w, http.StatusInternalServerError)
return
}
http.ServeContent(w, r, path, info.ModTime(), file)
}
// withAuth performs initial authorization before every request.
@ -854,18 +782,18 @@ func (server *Server) graphqlHandler(w http.ResponseWriter, r *http.Request) {
server.log.Debug(fmt.Sprintf("%s", result))
}
// serveError serves error static pages.
// serveError serves a static error page.
func (server *Server) serveError(w http.ResponseWriter, status int) {
w.WriteHeader(status)
templates, err := server.loadTemplates()
template, err := server.loadErrorTemplate()
if err != nil {
server.log.Error("unable to load templates", zap.Error(err))
server.log.Error("unable to load error template", zap.Error(err))
return
}
data := struct{ StatusCode int }{StatusCode: status}
err = templates.error.Execute(w, data)
err = template.Execute(w, data)
if err != nil {
server.log.Error("cannot parse error template", zap.Error(err))
}
@ -916,40 +844,16 @@ func (server *Server) brotliMiddleware(fn http.Handler) http.Handler {
})
}
// loadTemplates is used to initialize all templates.
func (server *Server) loadTemplates() (_ *templates, err error) {
if server.config.Watch {
return server.parseTemplates()
// loadTemplates is used to initialize the error page template.
func (server *Server) loadErrorTemplate() (_ *template.Template, err error) {
if server.errorTemplate == nil || server.config.Watch {
server.errorTemplate, err = template.ParseFiles(filepath.Join(server.config.StaticDir, "static", "errors", "error.html"))
if err != nil {
return nil, Error.Wrap(err)
}
}
if server.templatesCache != nil {
return server.templatesCache, nil
}
templates, err := server.parseTemplates()
if err != nil {
return nil, Error.Wrap(err)
}
server.templatesCache = templates
return server.templatesCache, nil
}
func (server *Server) parseTemplates() (_ *templates, err error) {
var t templates
t.index, err = template.ParseFiles(filepath.Join(server.config.StaticDir, "dist", "index.html"))
if err != nil {
server.log.Error("dist folder is not generated. use 'npm run build' command", zap.Error(err))
// Loading index is optional.
}
t.error, err = template.ParseFiles(filepath.Join(server.config.StaticDir, "static", "errors", "error.html"))
if err != nil {
return &t, Error.Wrap(err)
}
return &t, nil
return server.errorTemplate, nil
}
// NewUserIDRateLimiter constructs a RateLimiter that limits based on user ID.

View File

@ -3,45 +3,6 @@
<head lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="external-address" content="{{ .ExternalAddress }}">
<meta name="satellite-name" content="{{ .SatelliteName }}">
<meta name="satellite-nodeurl" content="{{ .SatelliteNodeURL }}">
<meta name="stripe-public-key" content="{{ .StripePublicKey }}">
<meta name="partnered-satellites" content="{{ .PartneredSatellites }}">
<meta name="default-project-limit" content="{{ .DefaultProjectLimit }}">
<meta name="general-request-url" content="{{ .GeneralRequestURL }}">
<meta name="project-limits-increase-request-url" content="{{ .ProjectLimitsIncreaseRequestURL }}">
<meta name="gateway-credentials-request-url" content="{{ .GatewayCredentialsRequestURL }}">
<meta name="is-beta-satellite" content="{{ .IsBetaSatellite }}">
<meta name="beta-satellite-feedback-url" content="{{ .BetaSatelliteFeedbackURL }}">
<meta name="beta-satellite-support-url" content="{{ .BetaSatelliteSupportURL }}">
<meta name="documentation-url" content="{{ .DocumentationURL }}">
<meta name="coupon-code-billing-ui-enabled" content="{{ .CouponCodeBillingUIEnabled }}">
<meta name="coupon-code-signup-ui-enabled" content="{{ .CouponCodeSignupUIEnabled }}">
<meta name="file-browser-flow-disabled" content="{{ .FileBrowserFlowDisabled }}">
<meta name="linksharing-url" content="{{ .LinksharingURL }}">
<meta name="registration-recaptcha-enabled" content="{{ .RegistrationRecaptchaEnabled }}">
<meta name="registration-recaptcha-site-key" content="{{ .RegistrationRecaptchaSiteKey }}">
<meta name="registration-hcaptcha-enabled" content="{{ .RegistrationHcaptchaEnabled }}">
<meta name="registration-hcaptcha-site-key" content="{{ .RegistrationHcaptchaSiteKey }}">
<meta name="login-recaptcha-enabled" content="{{ .LoginRecaptchaEnabled }}">
<meta name="login-recaptcha-site-key" content="{{ .LoginRecaptchaSiteKey }}">
<meta name="login-hcaptcha-enabled" content="{{ .LoginHcaptchaEnabled }}">
<meta name="login-hcaptcha-site-key" content="{{ .LoginHcaptchaSiteKey }}">
<meta name="all-projects-dashboard" content="{{ .AllProjectsDashboard }}">
<meta name="default-paid-storage-limit" content="{{ .DefaultPaidStorageLimit }}">
<meta name="default-paid-bandwidth-limit" content="{{ .DefaultPaidBandwidthLimit }}">
<meta name="inactivity-timer-enabled" content="{{ .InactivityTimerEnabled }}">
<meta name="inactivity-timer-duration" content="{{ .InactivityTimerDuration }}">
<meta name="inactivity-timer-viewer-enabled" content="{{ .InactivityTimerViewerEnabled }}">
<meta name="optional-signup-success-url" content="{{ .OptionalSignupSuccessURL }}">
<meta name="homepage-url" content="{{ .HomepageURL }}">
<meta name="native-token-payments-enabled" content="{{ .NativeTokenPaymentsEnabled }}">
<meta name="password-minimum-length" content="{{ .PasswordMinimumLength }}">
<meta name="password-maximum-length" content="{{ .PasswordMaximumLength }}">
<meta name="ab-testing-enabled" content="{{ .ABTestingEnabled }}">
<meta name="pricing-packages-enabled" content="{{ .PricingPackagesEnabled }}">
<title>{{ .SatelliteName }}</title>
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACDVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////8nbP8obf8pbf8qbv8rb/8sb/8tcP8ucf8vcf8vcv8xc/8zdP81df81dv82dv83d/84eP85eP86ef87ev89e/8+fP8/fP9Aff9Bfv9Cfv9Df/9EgP9FgP9Ggf9Hgv9Jg/9LhP9Mhf9Nhv9Oh/9Ph/9RiP9Rif9Sif9Ui/9Vi/9WjP9Xjf9Yjf9aj/9dkf9ekf9ilP9jlf9llv9nl/9omP9rmv9sm/9tnP9vnf9wnv9yn/91of92ov93o/94o/98pv9/qP+Bqf+Cqv+Eq/+FrP+Hrf+Irv+Jr/+Kr/+Msf+Nsv+Stf+Ttf+Ttv+Utv+Vt/+WuP+XuP+Zuf+Zuv+hv/+kwf+lwv+mwv+nw/+oxP+pxP+pxf+qxf+rxv+yy/+0zP+1zf+3zv+4z/+60P+70f+90v+/0/+/1P/B1f/D1v/E1//F1//F2P/G2P/H2f/I2v/J2v/K2//L3P/P3v/Q3//R4P/S4P/V4v/V4//W4//X5P/Y5P/b5v/b5//c5//d6P/e6f/f6f/g6v/h6//j7P/k7f/l7f/m7v/q8f/r8f/u8//w9f/x9f/x9v/z9//0+P/2+f/3+f/3+v/4+v/5+//6/P/8/f/9/v/+/v////9uCbVDAAAAFXRSTlMABAU4Ozw9PpSWl5ilp6ip4+Tl/P6nIcp/AAAAAWJLR0SuuWuTpwAAAh5JREFUOMtjYGBgYOcXEl6HAYSF+FgZQICJex1OwMkEVIAi3+Xh1ozM5wKaj8xfpBwcITsbWYSNgR+JtzpJYvU6jbAVSEK8DEIITpOZqnxItISWfgVCTJAB7v4ZXpKRC9uMNCqXJci6TID7hQFMrV2zJE7abTKQFesDJGb7SYTOX7sGLAVWUKCgrGZcDeaDFaxb12alqC6XDlMwTyKnRLJ1HbKCddNEc0skJkAVdEssXatRiKqgVmLlatUqqILVpuaOEnLJy4GsIhONuHlAOldVwtJWcwnMDb2i4dPKdHVKV3uqRCdYqU9psVDOmh0vUQN35FTRhevWLU+V0FeZBdTtpSQRvgAoKtuMqmBdpKxvKYjXJ+o+cx0WBRPFO6ABHuesMheLghIdePiutc7AoqBLchZchVMSFgUr9HTS8sEgL1C0E1XBRNGUeeV6OlFONjbqSjY2Nv7mKjnzMyXqYQrW2OsYS8smLkOE5OpsFSkdQ6PlUAU9EgtXq6MFdZ3EkpVKNVAFc8TKW6QbURVMFK1slOyGuSFdUkLOoQtZwSRXaRmpKLgj1y1eMjdIImguTMHCCAnvGcuXQhIMPMl1O8hnrOy31GtfnaNi3oRIcohEu7ZY20DZK0DGTCV7NVKi5UVK40vDJVatU/dfgCTEw8AsgsSdLx+TKjUdOeMAsycnMr/BzrIcmc8ByrycuDMvByM4f7PyCmLL/gK8LEBJALYsGEdXEyupAAAAAElFTkSuQmCC" type="image/x-icon">
<link rel="dns-prefetch" href="https://js.stripe.com">
</head>