Fix auth base64, fix iPhone things

This commit is contained in:
Philipp Heckel 2022-03-10 18:11:12 -05:00
parent ccb9da9333
commit 160c72997f
7 changed files with 48 additions and 11 deletions

View file

@ -340,6 +340,7 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, r *http.Request) error {
appRoot = "/app" appRoot = "/app"
} }
disallowedTopicsStr := `"` + strings.Join(disallowedTopics, `", "`) + `"` disallowedTopicsStr := `"` + strings.Join(disallowedTopics, `", "`) + `"`
w.Header().Set("Content-Type", "application/json")
_, err := io.WriteString(w, fmt.Sprintf(`// Generated server configuration _, err := io.WriteString(w, fmt.Sprintf(`// Generated server configuration
var config = { var config = {
appRoot: "%s", appRoot: "%s",

11
web/package-lock.json generated
View file

@ -14,6 +14,7 @@
"@mui/material": "latest", "@mui/material": "latest",
"dexie": "^3.2.1", "dexie": "^3.2.1",
"dexie-react-hooks": "^1.1.1", "dexie-react-hooks": "^1.1.1",
"js-base64": "^3.7.2",
"react": "latest", "react": "latest",
"react-dom": "latest", "react-dom": "latest",
"react-infinite-scroll-component": "^6.1.0", "react-infinite-scroll-component": "^6.1.0",
@ -10775,6 +10776,11 @@
"url": "https://github.com/chalk/supports-color?sponsor=1" "url": "https://github.com/chalk/supports-color?sponsor=1"
} }
}, },
"node_modules/js-base64": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz",
"integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ=="
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -23917,6 +23923,11 @@
} }
} }
}, },
"js-base64": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz",
"integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ=="
},
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",

View file

@ -15,6 +15,7 @@
"@mui/material": "latest", "@mui/material": "latest",
"dexie": "^3.2.1", "dexie": "^3.2.1",
"dexie-react-hooks": "^1.1.1", "dexie-react-hooks": "^1.1.1",
"js-base64": "^3.7.2",
"react": "latest", "react": "latest",
"react-dom": "latest", "react-dom": "latest",
"react-infinite-scroll-component": "^6.1.0", "react-infinite-scroll-component": "^6.1.0",

View file

@ -5,6 +5,9 @@ import logo from "../img/ntfy.png";
class Notifier { class Notifier {
async notify(subscriptionId, notification, onClickFallback) { async notify(subscriptionId, notification, onClickFallback) {
if (!this.supported()) {
return;
}
const subscription = await subscriptionManager.get(subscriptionId); const subscription = await subscriptionManager.get(subscriptionId);
const shouldNotify = await this.shouldNotify(subscription, notification); const shouldNotify = await this.shouldNotify(subscription, notification);
if (!shouldNotify) { if (!shouldNotify) {
@ -38,10 +41,14 @@ class Notifier {
} }
granted() { granted() {
return Notification.permission === 'granted'; return this.supported() && Notification.permission === 'granted';
} }
maybeRequestPermission(cb) { maybeRequestPermission(cb) {
if (!this.supported()) {
cb(false);
return;
}
if (!this.granted()) { if (!this.granted()) {
Notification.requestPermission().then((permission) => { Notification.requestPermission().then((permission) => {
const granted = permission === 'granted'; const granted = permission === 'granted';
@ -61,6 +68,10 @@ class Notifier {
} }
return true; return true;
} }
supported() {
return 'Notification' in window;
}
} }
const notifier = new Notifier(); const notifier = new Notifier();

View file

@ -7,6 +7,7 @@ import dadum from "../sounds/dadum.mp3";
import pop from "../sounds/pop.mp3"; import pop from "../sounds/pop.mp3";
import popSwoosh from "../sounds/pop-swoosh.mp3"; import popSwoosh from "../sounds/pop-swoosh.mp3";
import config from "./config"; import config from "./config";
import {Base64} from 'js-base64';
export const topicUrl = (baseUrl, topic) => `${baseUrl}/${topic}`; export const topicUrl = (baseUrl, topic) => `${baseUrl}/${topic}`;
export const topicUrlWs = (baseUrl, topic) => `${topicUrl(baseUrl, topic)}/ws` export const topicUrlWs = (baseUrl, topic) => `${topicUrl(baseUrl, topic)}/ws`
@ -96,14 +97,11 @@ export const basicAuth = (username, password) => {
} }
export const encodeBase64 = (s) => { export const encodeBase64 = (s) => {
return new Buffer(s).toString('base64'); return Base64.encode(s);
} }
export const encodeBase64Url = (s) => { export const encodeBase64Url = (s) => {
return encodeBase64(s) return Base64.encodeURI(s);
.replaceAll('+', '-')
.replaceAll('/', '_')
.replaceAll('=', '');
} }
// https://jameshfisher.com/2017/10/30/web-cryptography-api-hello-world/ // https://jameshfisher.com/2017/10/30/web-cryptography-api-hello-world/

View file

@ -20,7 +20,6 @@ import ErrorBoundary from "./ErrorBoundary";
import routes from "./routes"; import routes from "./routes";
import {useAutoSubscribe, useConnectionListeners} from "./hooks"; import {useAutoSubscribe, useConnectionListeners} from "./hooks";
// TODO iPhone blank screen
// TODO better "send test message" (a la android app) // TODO better "send test message" (a la android app)
// TODO docs // TODO docs
// TODO screenshot on homepage // TODO screenshot on homepage

View file

@ -82,13 +82,15 @@ const NavList = (props) => {
}; };
const showSubscriptionsList = props.subscriptions?.length > 0; const showSubscriptionsList = props.subscriptions?.length > 0;
const showGrantPermissionsBox = props.subscriptions?.length > 0 && !props.notificationsGranted; const showNotificationNotSupportedBox = !notifier.supported();
const showNotificationGrantBox = notifier.supported() && props.subscriptions?.length > 0 && !props.notificationsGranted;
return ( return (
<> <>
<Toolbar sx={{ display: { xs: 'none', sm: 'block' } }}/> <Toolbar sx={{ display: { xs: 'none', sm: 'block' } }}/>
<List component="nav" sx={{ paddingTop: (showGrantPermissionsBox) ? '0' : '' }}> <List component="nav" sx={{ paddingTop: (showNotificationGrantBox || showNotificationNotSupportedBox) ? '0' : '' }}>
{showGrantPermissionsBox && <PermissionAlert onRequestPermissionClick={handleRequestNotificationPermission}/>} {showNotificationNotSupportedBox && <NotificationNotSupportedAlert/>}
{showNotificationGrantBox && <NotificationGrantAlert onRequestPermissionClick={handleRequestNotificationPermission}/>}
{!showSubscriptionsList && {!showSubscriptionsList &&
<ListItemButton onClick={() => navigate(routes.root)} selected={location.pathname === config.appRoot}> <ListItemButton onClick={() => navigate(routes.root)} selected={location.pathname === config.appRoot}>
<ListItemIcon><ChatBubble/></ListItemIcon> <ListItemIcon><ChatBubble/></ListItemIcon>
@ -167,7 +169,7 @@ const SubscriptionItem = (props) => {
); );
}; };
const PermissionAlert = (props) => { const NotificationGrantAlert = (props) => {
return ( return (
<> <>
<Alert severity="warning" sx={{paddingTop: 2}}> <Alert severity="warning" sx={{paddingTop: 2}}>
@ -189,4 +191,18 @@ const PermissionAlert = (props) => {
); );
}; };
const NotificationNotSupportedAlert = () => {
return (
<>
<Alert severity="warning" sx={{paddingTop: 2}}>
<AlertTitle>Notifications not supported</AlertTitle>
<Typography gutterBottom>
Notifications are not supported in your browser.
</Typography>
</Alert>
<Divider/>
</>
);
};
export default Navigation; export default Navigation;