diff --git a/config.example.json b/config.example.json index b54734db1..0e1270e88 100644 --- a/config.example.json +++ b/config.example.json @@ -215,7 +215,12 @@ "PatchServer": "", "Banners": [], "Messages": [], - "Links": [] + "Links": [], + "LandingPage": { + "Enabled": true, + "Title": "My Frontier Server", + "Content": "

Welcome! Download the client from our Discord.

" + } }, "Channel": { "Enabled": true diff --git a/config/config.go b/config/config.go index 114f01885..4cc558cdc 100644 --- a/config/config.go +++ b/config/config.go @@ -254,6 +254,14 @@ type API struct { Banners []APISignBanner Messages []APISignMessage Links []APISignLink + LandingPage LandingPage +} + +// LandingPage holds config for the browser-facing landing page at /. +type LandingPage struct { + Enabled bool // Toggle the landing page on/off + Title string // Page title (e.g. "My Frontier Server") + Content string // Body content — supports raw HTML } type APISignBanner struct { diff --git a/server/api/api_server.go b/server/api/api_server.go index 424516efc..c250e1dee 100644 --- a/server/api/api_server.go +++ b/server/api/api_server.go @@ -63,6 +63,7 @@ func (s *APIServer) Start() error { r.HandleFunc("/character/export", s.ExportSave) r.HandleFunc("/api/ss/bbs/upload.php", s.ScreenShot) r.HandleFunc("/api/ss/bbs/{id}", s.ScreenShotGet) + r.HandleFunc("/", s.LandingPage) r.HandleFunc("/health", s.Health) r.HandleFunc("/version", s.Version) handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r) diff --git a/server/api/landing_page.go b/server/api/landing_page.go new file mode 100644 index 000000000..65216d258 --- /dev/null +++ b/server/api/landing_page.go @@ -0,0 +1,35 @@ +package api + +import ( + _ "embed" + "html/template" + "net/http" +) + +//go:embed landing_page.html +var landingPageHTML string + +var landingPageTmpl = template.Must(template.New("landing").Parse(landingPageHTML)) + +type landingPageData struct { + Title string + Content template.HTML +} + +// LandingPage serves a configurable HTML landing page at /. +func (s *APIServer) LandingPage(w http.ResponseWriter, r *http.Request) { + lp := s.erupeConfig.API.LandingPage + if !lp.Enabled { + http.NotFound(w, r) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + data := landingPageData{ + Title: lp.Title, + Content: template.HTML(lp.Content), + } + if err := landingPageTmpl.Execute(w, data); err != nil { + s.logger.Error("Failed to render landing page") + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } +} diff --git a/server/api/landing_page.html b/server/api/landing_page.html new file mode 100644 index 000000000..72aac540a --- /dev/null +++ b/server/api/landing_page.html @@ -0,0 +1,24 @@ + + + + + +{{.Title}} + + + +
+

{{.Title}}

+
{{.Content}}
+
+ +