diff --git a/server/server.go b/server/server.go index 0b909b80..b563b7c2 100644 --- a/server/server.go +++ b/server/server.go @@ -8,7 +8,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "heckel.io/ntfy/log" "io" "net" "net/http" @@ -23,6 +22,8 @@ import ( "time" "unicode/utf8" + "heckel.io/ntfy/log" + "github.com/emersion/go-smtp" "github.com/gorilla/websocket" "golang.org/x/sync/errgroup" @@ -76,6 +77,9 @@ var ( //go:embed "example.html" exampleSource string + //go:embed site/app.html + appHTML string + //go:embed site webFs embed.FS webFsCached = &util.CachingEmbedFS{ModTime: time.Now(), FS: webFs} @@ -317,10 +321,10 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit func (s *Server) handleHome(w http.ResponseWriter, r *http.Request, v *visitor) error { if s.config.WebRootIsApp { - r.URL.Path = webAppIndex - } else { - r.URL.Path = webHomeIndex + return s.handleRoot(w, r, v) } + + r.URL.Path = webHomeIndex return s.handleStatic(w, r, v) } @@ -332,8 +336,7 @@ func (s *Server) handleTopic(w http.ResponseWriter, r *http.Request, v *visitor) _, err := io.WriteString(w, `{"unifiedpush":{"version":1}}`+"\n") return err } - r.URL.Path = webAppIndex - return s.handleStatic(w, r, v) + return s.handleRoot(w, r, v) } func (s *Server) handleEmpty(_ http.ResponseWriter, _ *http.Request, _ *visitor) error { @@ -353,17 +356,12 @@ func (s *Server) handleExample(w http.ResponseWriter, _ *http.Request, _ *visito } func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visitor) error { - appRoot := "/" - if !s.config.WebRootIsApp { - appRoot = "/app" - } disallowedTopicsStr := `"` + strings.Join(disallowedTopics, `", "`) + `"` w.Header().Set("Content-Type", "text/javascript") _, err := io.WriteString(w, fmt.Sprintf(`// Generated server configuration var config = { - appRoot: "%s", disallowedTopics: [%s] -};`, appRoot, disallowedTopicsStr)) +};`, disallowedTopicsStr)) return err } @@ -380,6 +378,17 @@ func (s *Server) handleUserStats(w http.ResponseWriter, r *http.Request, v *visi return nil } +func (s *Server) handleRoot(w http.ResponseWriter, r *http.Request, _ *visitor) error { + // Does this need to be sanitized? + html := strings.ReplaceAll(appHTML, `currentPath="/"`, `currentPath="`+r.URL.Path+`"`) + handle := func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(html)) + } + + util.Gzip(http.HandlerFunc(handle)).ServeHTTP(w, r) + return nil +} + func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request, _ *visitor) error { r.URL.Path = webSiteDir + r.URL.Path util.Gzip(http.FileServer(http.FS(webFsCached))).ServeHTTP(w, r) @@ -509,7 +518,7 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) { return } req.Header.Set("X-Poll-ID", m.ID) - var httpClient = &http.Client{ + httpClient := &http.Client{ Timeout: time.Second * 10, } response, err := httpClient.Do(req) diff --git a/web/package.json b/web/package.json index e97191b0..b6122127 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,7 @@ { "name": "ntfy", "version": "1.0.0", + "homepage": ".", "private": true, "scripts": { "start": "react-scripts start", diff --git a/web/public/config.js b/web/public/config.js index cd5fbf05..78dc6ec2 100644 --- a/web/public/config.js +++ b/web/public/config.js @@ -4,6 +4,5 @@ // The actual config is dynamically generated server-side. var config = { - appRoot: "/", disallowedTopics: ["docs", "static", "file", "app", "settings"] }; diff --git a/web/public/index.html b/web/public/index.html index 2c9751f3..e3d1a55c 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -1,9 +1,19 @@ + + + ntfy web - @@ -15,7 +25,7 @@ - + @@ -23,14 +33,14 @@ - + - +
- + diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js index cafad049..e8e0a405 100644 --- a/web/src/components/Navigation.js +++ b/web/src/components/Navigation.js @@ -122,7 +122,7 @@ const NavList = (props) => { - openUrl("/docs")}> + openUrl("docs")}> diff --git a/web/src/components/i18n.js b/web/src/components/i18n.js index 42eb5721..c2eeb53e 100644 --- a/web/src/components/i18n.js +++ b/web/src/components/i18n.js @@ -22,7 +22,7 @@ i18n escapeValue: false, // not needed for react as it escapes by default }, backend: { - loadPath: '/static/langs/{{lng}}.json', + loadPath: 'static/langs/{{lng}}.json', } }); diff --git a/web/src/components/routes.js b/web/src/components/routes.js index 7a7a7857..e5e7f5c8 100644 --- a/web/src/components/routes.js +++ b/web/src/components/routes.js @@ -1,16 +1,17 @@ import config from "../app/config"; import {shortUrl} from "../app/utils"; +const root = RootPath; // Defined in `public/index.html`. const routes = { - root: config.appRoot, - settings: "/settings", - subscription: "/:topic", - subscriptionExternal: "/:baseUrl/:topic", + root: root, + settings: root+"settings", + subscription: root+":topic", + subscriptionExternal: root+":baseUrl/:topic", forSubscription: (subscription) => { if (subscription.baseUrl !== window.location.origin) { - return `/${shortUrl(subscription.baseUrl)}/${subscription.topic}`; + return root+`${shortUrl(subscription.baseUrl)}/${subscription.topic}`; } - return `/${subscription.topic}`; + return root+`${subscription.topic}`; } };