slightly better
This commit is contained in:
parent
86c132f9cd
commit
f9b8d6ed1b
7 changed files with 47 additions and 27 deletions
|
@ -8,7 +8,6 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"heckel.io/ntfy/log"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -23,6 +22,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"heckel.io/ntfy/log"
|
||||||
|
|
||||||
"github.com/emersion/go-smtp"
|
"github.com/emersion/go-smtp"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
@ -76,6 +77,9 @@ var (
|
||||||
//go:embed "example.html"
|
//go:embed "example.html"
|
||||||
exampleSource string
|
exampleSource string
|
||||||
|
|
||||||
|
//go:embed site/app.html
|
||||||
|
appHTML string
|
||||||
|
|
||||||
//go:embed site
|
//go:embed site
|
||||||
webFs embed.FS
|
webFs embed.FS
|
||||||
webFsCached = &util.CachingEmbedFS{ModTime: time.Now(), FS: webFs}
|
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 {
|
func (s *Server) handleHome(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||||
if s.config.WebRootIsApp {
|
if s.config.WebRootIsApp {
|
||||||
r.URL.Path = webAppIndex
|
return s.handleRoot(w, r, v)
|
||||||
} else {
|
|
||||||
r.URL.Path = webHomeIndex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.URL.Path = webHomeIndex
|
||||||
return s.handleStatic(w, r, v)
|
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")
|
_, err := io.WriteString(w, `{"unifiedpush":{"version":1}}`+"\n")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.URL.Path = webAppIndex
|
return s.handleRoot(w, r, v)
|
||||||
return s.handleStatic(w, r, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleEmpty(_ http.ResponseWriter, _ *http.Request, _ *visitor) error {
|
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 {
|
func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visitor) error {
|
||||||
appRoot := "/"
|
|
||||||
if !s.config.WebRootIsApp {
|
|
||||||
appRoot = "/app"
|
|
||||||
}
|
|
||||||
disallowedTopicsStr := `"` + strings.Join(disallowedTopics, `", "`) + `"`
|
disallowedTopicsStr := `"` + strings.Join(disallowedTopics, `", "`) + `"`
|
||||||
w.Header().Set("Content-Type", "text/javascript")
|
w.Header().Set("Content-Type", "text/javascript")
|
||||||
_, err := io.WriteString(w, fmt.Sprintf(`// Generated server configuration
|
_, err := io.WriteString(w, fmt.Sprintf(`// Generated server configuration
|
||||||
var config = {
|
var config = {
|
||||||
appRoot: "%s",
|
|
||||||
disallowedTopics: [%s]
|
disallowedTopics: [%s]
|
||||||
};`, appRoot, disallowedTopicsStr))
|
};`, disallowedTopicsStr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,6 +378,17 @@ func (s *Server) handleUserStats(w http.ResponseWriter, r *http.Request, v *visi
|
||||||
return nil
|
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 {
|
func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request, _ *visitor) error {
|
||||||
r.URL.Path = webSiteDir + r.URL.Path
|
r.URL.Path = webSiteDir + r.URL.Path
|
||||||
util.Gzip(http.FileServer(http.FS(webFsCached))).ServeHTTP(w, r)
|
util.Gzip(http.FileServer(http.FS(webFsCached))).ServeHTTP(w, r)
|
||||||
|
@ -509,7 +518,7 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.Header.Set("X-Poll-ID", m.ID)
|
req.Header.Set("X-Poll-ID", m.ID)
|
||||||
var httpClient = &http.Client{
|
httpClient := &http.Client{
|
||||||
Timeout: time.Second * 10,
|
Timeout: time.Second * 10,
|
||||||
}
|
}
|
||||||
response, err := httpClient.Do(req)
|
response, err := httpClient.Do(req)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "ntfy",
|
"name": "ntfy",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"homepage": ".",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|
|
@ -4,6 +4,5 @@
|
||||||
// The actual config is dynamically generated server-side.
|
// The actual config is dynamically generated server-side.
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
appRoot: "/",
|
|
||||||
disallowedTopics: ["docs", "static", "file", "app", "settings"]
|
disallowedTopics: ["docs", "static", "file", "app", "settings"]
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<base>
|
||||||
|
<script>
|
||||||
|
// Calculate the root path.
|
||||||
|
const currentPath = "/" // Replaced by server.
|
||||||
|
const pathname = window.location.pathname
|
||||||
|
const lastIndex = pathname.lastIndexOf(currentPath)
|
||||||
|
var RootPath = pathname.slice(0, lastIndex+1)
|
||||||
|
console.log(`Root=${RootPath}`)
|
||||||
|
document.querySelector("base").href = RootPath;
|
||||||
|
</script>
|
||||||
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>ntfy web</title>
|
<title>ntfy web</title>
|
||||||
|
|
||||||
<!-- Mobile view -->
|
<!-- Mobile view -->
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
@ -15,7 +25,7 @@
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="#317f6f">
|
<meta name="apple-mobile-web-app-status-bar-style" content="#317f6f">
|
||||||
|
|
||||||
<!-- Favicon, see favicon.io -->
|
<!-- Favicon, see favicon.io -->
|
||||||
<link rel="icon" type="image/png" href="%PUBLIC_URL%/static/img/favicon.png">
|
<link rel="icon" type="image/png" href="static/img/favicon.png">
|
||||||
|
|
||||||
<!-- Previews in Google, Slack, WhatsApp, etc. -->
|
<!-- Previews in Google, Slack, WhatsApp, etc. -->
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
|
@ -23,14 +33,14 @@
|
||||||
<meta property="og:site_name" content="ntfy web" />
|
<meta property="og:site_name" content="ntfy web" />
|
||||||
<meta property="og:title" content="ntfy web" />
|
<meta property="og:title" content="ntfy web" />
|
||||||
<meta property="og:description" content="ntfy lets you send push notifications via scripts from any computer or phone, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." />
|
<meta property="og:description" content="ntfy lets you send push notifications via scripts from any computer or phone, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." />
|
||||||
<meta property="og:image" content="%PUBLIC_URL%/static/img/ntfy.png" />
|
<meta property="og:image" content="static/img/ntfy.png" />
|
||||||
<meta property="og:url" content="https://ntfy.sh" />
|
<meta property="og:url" content="https://ntfy.sh" />
|
||||||
|
|
||||||
<!-- Never index -->
|
<!-- Never index -->
|
||||||
<meta name="robots" content="noindex, nofollow" />
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
|
||||||
<!-- Fonts -->
|
<!-- Fonts -->
|
||||||
<link rel="stylesheet" href="%PUBLIC_URL%/static/css/fonts.css" type="text/css">
|
<link rel="stylesheet" href="static/css/fonts.css" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
@ -38,6 +48,6 @@
|
||||||
or <a href="https://ntfy.sh/docs/subscribe/phone/">Android/iOS app</a> to subscribe.
|
or <a href="https://ntfy.sh/docs/subscribe/phone/">Android/iOS app</a> to subscribe.
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="%PUBLIC_URL%/config.js"></script>
|
<script src="config.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -122,7 +122,7 @@ const NavList = (props) => {
|
||||||
<ListItemIcon><SettingsIcon/></ListItemIcon>
|
<ListItemIcon><SettingsIcon/></ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_settings")}/>
|
<ListItemText primary={t("nav_button_settings")}/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<ListItemButton onClick={() => openUrl("/docs")}>
|
<ListItemButton onClick={() => openUrl("docs")}>
|
||||||
<ListItemIcon><ArticleIcon/></ListItemIcon>
|
<ListItemIcon><ArticleIcon/></ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_documentation")}/>
|
<ListItemText primary={t("nav_button_documentation")}/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
|
|
|
@ -22,7 +22,7 @@ i18n
|
||||||
escapeValue: false, // not needed for react as it escapes by default
|
escapeValue: false, // not needed for react as it escapes by default
|
||||||
},
|
},
|
||||||
backend: {
|
backend: {
|
||||||
loadPath: '/static/langs/{{lng}}.json',
|
loadPath: 'static/langs/{{lng}}.json',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import config from "../app/config";
|
import config from "../app/config";
|
||||||
import {shortUrl} from "../app/utils";
|
import {shortUrl} from "../app/utils";
|
||||||
|
|
||||||
|
const root = RootPath; // Defined in `public/index.html`.
|
||||||
const routes = {
|
const routes = {
|
||||||
root: config.appRoot,
|
root: root,
|
||||||
settings: "/settings",
|
settings: root+"settings",
|
||||||
subscription: "/:topic",
|
subscription: root+":topic",
|
||||||
subscriptionExternal: "/:baseUrl/:topic",
|
subscriptionExternal: root+":baseUrl/:topic",
|
||||||
forSubscription: (subscription) => {
|
forSubscription: (subscription) => {
|
||||||
if (subscription.baseUrl !== window.location.origin) {
|
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}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue