Redirect UI if unauthorized API response
This commit is contained in:
		
							parent
							
								
									1b39ba70cb
								
							
						
					
					
						commit
						3aac1b2715
					
				
					 11 changed files with 148 additions and 77 deletions
				
			
		|  | @ -42,7 +42,6 @@ import ( | ||||||
| 		expire tokens | 		expire tokens | ||||||
| 		auto-refresh tokens from UI | 		auto-refresh tokens from UI | ||||||
| 		reserve topics | 		reserve topics | ||||||
| 		handle invalid session token |  | ||||||
| 		purge accounts that were not logged into in X | 		purge accounts that were not logged into in X | ||||||
| 		sync subscription display name | 		sync subscription display name | ||||||
| 		reset daily limits for users | 		reset daily limits for users | ||||||
|  |  | ||||||
|  | @ -126,7 +126,7 @@ class Api { | ||||||
|             headers: maybeWithBasicAuth({}, user) |             headers: maybeWithBasicAuth({}, user) | ||||||
|         }); |         }); | ||||||
|         if (response.status === 401 || response.status === 403) { |         if (response.status === 401 || response.status === 403) { | ||||||
|             return false; |             throw new UnauthorizedError(); | ||||||
|         } else if (response.status !== 200) { |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|  | @ -144,7 +144,9 @@ class Api { | ||||||
|             method: "DELETE", |             method: "DELETE", | ||||||
|             headers: maybeWithBearerAuth({}, token) |             headers: maybeWithBearerAuth({}, token) | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -175,7 +177,9 @@ class Api { | ||||||
|         const response = await fetch(url, { |         const response = await fetch(url, { | ||||||
|             headers: maybeWithBearerAuth({}, token) |             headers: maybeWithBearerAuth({}, token) | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|         const account = await response.json(); |         const account = await response.json(); | ||||||
|  | @ -190,7 +194,9 @@ class Api { | ||||||
|             method: "DELETE", |             method: "DELETE", | ||||||
|             headers: maybeWithBearerAuth({}, token) |             headers: maybeWithBearerAuth({}, token) | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -205,7 +211,9 @@ class Api { | ||||||
|                 password: password |                 password: password | ||||||
|             }) |             }) | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -219,7 +227,9 @@ class Api { | ||||||
|             headers: maybeWithBearerAuth({}, token), |             headers: maybeWithBearerAuth({}, token), | ||||||
|             body: body |             body: body | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -233,7 +243,9 @@ class Api { | ||||||
|             headers: maybeWithBearerAuth({}, token), |             headers: maybeWithBearerAuth({}, token), | ||||||
|             body: body |             body: body | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|         const subscription = await response.json(); |         const subscription = await response.json(); | ||||||
|  | @ -248,7 +260,9 @@ class Api { | ||||||
|             method: "DELETE", |             method: "DELETE", | ||||||
|             headers: maybeWithBearerAuth({}, token) |             headers: maybeWithBearerAuth({}, token) | ||||||
|         }); |         }); | ||||||
|         if (response.status !== 200) { |         if (response.status === 401 || response.status === 403) { | ||||||
|  |             throw new UnauthorizedError(); | ||||||
|  |         } else if (response.status !== 200) { | ||||||
|             throw new Error(`Unexpected server response ${response.status}`); |             throw new Error(`Unexpected server response ${response.status}`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -256,13 +270,21 @@ class Api { | ||||||
| 
 | 
 | ||||||
| export class UsernameTakenError extends Error { | export class UsernameTakenError extends Error { | ||||||
|     constructor(username) { |     constructor(username) { | ||||||
|         super(); |         super("Username taken"); | ||||||
|         this.username = username; |         this.username = username; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class AccountCreateLimitReachedError extends Error { | export class AccountCreateLimitReachedError extends Error { | ||||||
|     // Nothing
 |     constructor() { | ||||||
|  |         super("Account creation limit reached"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class UnauthorizedError extends Error { | ||||||
|  |     constructor() { | ||||||
|  |         super("Unauthorized"); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const api = new Api(); | const api = new Api(); | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ import DialogTitle from "@mui/material/DialogTitle"; | ||||||
| import DialogContent from "@mui/material/DialogContent"; | import DialogContent from "@mui/material/DialogContent"; | ||||||
| import TextField from "@mui/material/TextField"; | import TextField from "@mui/material/TextField"; | ||||||
| import DialogActions from "@mui/material/DialogActions"; | import DialogActions from "@mui/material/DialogActions"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import routes from "./routes"; | import routes from "./routes"; | ||||||
| import IconButton from "@mui/material/IconButton"; | import IconButton from "@mui/material/IconButton"; | ||||||
| import {useNavigate, useOutletContext} from "react-router-dom"; | import {useNavigate, useOutletContext} from "react-router-dom"; | ||||||
|  | @ -152,6 +152,10 @@ const ChangePassword = () => { | ||||||
|             console.debug(`[Account] Password changed`); |             console.debug(`[Account] Password changed`); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.log(`[Account] Error changing password`, e); |             console.log(`[Account] Error changing password`, e); | ||||||
|  |             if ((e instanceof UnauthorizedError)) { | ||||||
|  |                 session.reset(); | ||||||
|  |                 window.location.href = routes.login; | ||||||
|  |             } | ||||||
|             // TODO show error
 |             // TODO show error
 | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  | @ -238,6 +242,10 @@ const DeleteAccount = () => { | ||||||
|             window.location.href = routes.app; |             window.location.href = routes.app; | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.log(`[Account] Error deleting account`, e); |             console.log(`[Account] Error deleting account`, e); | ||||||
|  |             if ((e instanceof UnauthorizedError)) { | ||||||
|  |                 session.reset(); | ||||||
|  |                 window.location.href = routes.login; | ||||||
|  |             } | ||||||
|             // TODO show error
 |             // TODO show error
 | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ import MenuList from '@mui/material/MenuList'; | ||||||
| import MoreVertIcon from "@mui/icons-material/MoreVert"; | import MoreVertIcon from "@mui/icons-material/MoreVert"; | ||||||
| import NotificationsIcon from '@mui/icons-material/Notifications'; | import NotificationsIcon from '@mui/icons-material/Notifications'; | ||||||
| import NotificationsOffIcon from '@mui/icons-material/NotificationsOff'; | import NotificationsOffIcon from '@mui/icons-material/NotificationsOff'; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import routes from "./routes"; | import routes from "./routes"; | ||||||
| import subscriptionManager from "../app/SubscriptionManager"; | import subscriptionManager from "../app/SubscriptionManager"; | ||||||
| import logo from "../img/ntfy.svg"; | import logo from "../img/ntfy.svg"; | ||||||
|  | @ -118,7 +118,15 @@ const SettingsIcons = (props) => { | ||||||
|         handleClose(event); |         handleClose(event); | ||||||
|         await subscriptionManager.remove(props.subscription.id); |         await subscriptionManager.remove(props.subscription.id); | ||||||
|         if (session.exists() && props.subscription.remoteId) { |         if (session.exists() && props.subscription.remoteId) { | ||||||
|             await api.deleteAccountSubscription(config.baseUrl, session.token(), props.subscription.remoteId); |             try { | ||||||
|  |                 await api.deleteAccountSubscription(config.baseUrl, session.token(), props.subscription.remoteId); | ||||||
|  |             } catch (e) { | ||||||
|  |                 console.log(`[ActionBar] Error unsubscribing`, e); | ||||||
|  |                 if ((e instanceof UnauthorizedError)) { | ||||||
|  |                     session.reset(); | ||||||
|  |                     window.location.href = routes.login; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         const newSelected = await subscriptionManager.first(); // May be undefined
 |         const newSelected = await subscriptionManager.first(); // May be undefined
 | ||||||
|         if (newSelected) { |         if (newSelected) { | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import {Backdrop, CircularProgress} from "@mui/material"; | ||||||
| import Home from "./Home"; | import Home from "./Home"; | ||||||
| import Login from "./Login"; | import Login from "./Login"; | ||||||
| import i18n from "i18next"; | import i18n from "i18next"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import prefs from "../app/Prefs"; | import prefs from "../app/Prefs"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
| import Pricing from "./Pricing"; | import Pricing from "./Pricing"; | ||||||
|  | @ -96,8 +96,12 @@ const Layout = () => { | ||||||
| 
 | 
 | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         (async () => { |         (async () => { | ||||||
|             const acc = await api.getAccount(config.baseUrl, session.token()); |             // TODO this should not live here
 | ||||||
|             if (acc) { |             try { | ||||||
|  |                 if (!session.token()) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 const acc = await api.getAccount(config.baseUrl, session.token()); | ||||||
|                 setAccount(acc); |                 setAccount(acc); | ||||||
|                 if (acc.language) { |                 if (acc.language) { | ||||||
|                     await i18n.changeLanguage(acc.language); |                     await i18n.changeLanguage(acc.language); | ||||||
|  | @ -116,6 +120,12 @@ const Layout = () => { | ||||||
|                 if (acc.subscriptions) { |                 if (acc.subscriptions) { | ||||||
|                     await subscriptionManager.syncFromRemote(acc.subscriptions); |                     await subscriptionManager.syncFromRemote(acc.subscriptions); | ||||||
|                 } |                 } | ||||||
|  |             } catch (e) { | ||||||
|  |                 console.log(`[App] Error fetching account`, e); | ||||||
|  |                 if ((e instanceof UnauthorizedError)) { | ||||||
|  |                     session.reset(); | ||||||
|  |                     window.location.href = routes.login; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         })(); |         })(); | ||||||
|     }, []); |     }, []); | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import WarningAmberIcon from '@mui/icons-material/WarningAmber'; | ||||||
| import TextField from "@mui/material/TextField"; | import TextField from "@mui/material/TextField"; | ||||||
| import Button from "@mui/material/Button"; | import Button from "@mui/material/Button"; | ||||||
| import Box from "@mui/material/Box"; | import Box from "@mui/material/Box"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import routes from "./routes"; | import routes from "./routes"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
| import {NavLink} from "react-router-dom"; | import {NavLink} from "react-router-dom"; | ||||||
|  | @ -22,17 +22,14 @@ const Login = () => { | ||||||
|         const user = { username, password }; |         const user = { username, password }; | ||||||
|         try { |         try { | ||||||
|             const token = await api.login(config.baseUrl, user); |             const token = await api.login(config.baseUrl, user); | ||||||
|             if (token) { |             console.log(`[Login] User auth for user ${user.username} successful, token is ${token}`); | ||||||
|                 console.log(`[Login] User auth for user ${user.username} successful, token is ${token}`); |             session.store(user.username, token); | ||||||
|                 session.store(user.username, token); |             window.location.href = routes.app; | ||||||
|                 window.location.href = routes.app; |  | ||||||
|             } else { |  | ||||||
|                 console.log(`[Login] User auth for user ${user.username} failed, access denied`); |  | ||||||
|                 setError(t("Login failed: Invalid username or password")); |  | ||||||
|             } |  | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.log(`[Login] User auth for user ${user.username} failed`, e); |             console.log(`[Login] User auth for user ${user.username} failed`, e); | ||||||
|             if (e && e.message) { |             if ((e instanceof UnauthorizedError)) { | ||||||
|  |                 setError(t("Login failed: Invalid username or password")); | ||||||
|  |             } else if (e.message) { | ||||||
|                 setError(e.message); |                 setError(e.message); | ||||||
|             } else { |             } else { | ||||||
|                 setError(t("Unknown error. Check logs for details.")) |                 setError(t("Unknown error. Check logs for details.")) | ||||||
|  |  | ||||||
|  | @ -34,8 +34,9 @@ import DialogActions from "@mui/material/DialogActions"; | ||||||
| import userManager from "../app/UserManager"; | import userManager from "../app/UserManager"; | ||||||
| import {playSound, shuffle, sounds, validTopic, validUrl} from "../app/utils"; | import {playSound, shuffle, sounds, validTopic, validUrl} from "../app/utils"; | ||||||
| import {useTranslation} from "react-i18next"; | import {useTranslation} from "react-i18next"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
|  | import routes from "./routes"; | ||||||
| 
 | 
 | ||||||
| const Preferences = () => { | const Preferences = () => { | ||||||
|     return ( |     return ( | ||||||
|  | @ -72,13 +73,11 @@ const Sound = () => { | ||||||
|     const sound = useLiveQuery(async () => prefs.sound()); |     const sound = useLiveQuery(async () => prefs.sound()); | ||||||
|     const handleChange = async (ev) => { |     const handleChange = async (ev) => { | ||||||
|         await prefs.setSound(ev.target.value); |         await prefs.setSound(ev.target.value); | ||||||
|         if (session.exists()) { |         await maybeUpdateAccountSettings({ | ||||||
|             await api.updateAccountSettings(config.baseUrl, session.token(), { |             notification: { | ||||||
|                 notification: { |                 sound: ev.target.value | ||||||
|                     sound: ev.target.value |             } | ||||||
|                 } |         }); | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if (!sound) { |     if (!sound) { | ||||||
|         return null; // While loading
 |         return null; // While loading
 | ||||||
|  | @ -112,13 +111,11 @@ const MinPriority = () => { | ||||||
|     const minPriority = useLiveQuery(async () => prefs.minPriority()); |     const minPriority = useLiveQuery(async () => prefs.minPriority()); | ||||||
|     const handleChange = async (ev) => { |     const handleChange = async (ev) => { | ||||||
|         await prefs.setMinPriority(ev.target.value); |         await prefs.setMinPriority(ev.target.value); | ||||||
|         if (session.exists()) { |         await maybeUpdateAccountSettings({ | ||||||
|             await api.updateAccountSettings(config.baseUrl, session.token(), { |             notification: { | ||||||
|                 notification: { |                 min_priority: ev.target.value | ||||||
|                     min_priority: ev.target.value |             } | ||||||
|                 } |         }); | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if (!minPriority) { |     if (!minPriority) { | ||||||
|         return null; // While loading
 |         return null; // While loading
 | ||||||
|  | @ -162,13 +159,11 @@ const DeleteAfter = () => { | ||||||
|     const deleteAfter = useLiveQuery(async () => prefs.deleteAfter()); |     const deleteAfter = useLiveQuery(async () => prefs.deleteAfter()); | ||||||
|     const handleChange = async (ev) => { |     const handleChange = async (ev) => { | ||||||
|         await prefs.setDeleteAfter(ev.target.value); |         await prefs.setDeleteAfter(ev.target.value); | ||||||
|         if (session.exists()) { |         await maybeUpdateAccountSettings({ | ||||||
|             await api.updateAccountSettings(config.baseUrl, session.token(), { |             notification: { | ||||||
|                 notification: { |                 delete_after: ev.target.value | ||||||
|                     delete_after: ev.target.value |             } | ||||||
|                 } |         }); | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if (deleteAfter === null || deleteAfter === undefined) { // !deleteAfter will not work with "0"
 |     if (deleteAfter === null || deleteAfter === undefined) { // !deleteAfter will not work with "0"
 | ||||||
|         return null; // While loading
 |         return null; // While loading
 | ||||||
|  | @ -466,11 +461,9 @@ const Language = () => { | ||||||
| 
 | 
 | ||||||
|     const handleChange = async (ev) => { |     const handleChange = async (ev) => { | ||||||
|         await i18n.changeLanguage(ev.target.value); |         await i18n.changeLanguage(ev.target.value); | ||||||
|         if (session.exists()) { |         await maybeUpdateAccountSettings({ | ||||||
|             await api.updateAccountSettings(config.baseUrl, session.token(), { |             language: ev.target.value | ||||||
|                 language: ev.target.value |         }); | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Remember: Flags are not languages. Don't put flags next to the language in the list.
 |     // Remember: Flags are not languages. Don't put flags next to the language in the list.
 | ||||||
|  | @ -670,4 +663,19 @@ const AccessControlDialog = (props) => { | ||||||
| }; | }; | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | const maybeUpdateAccountSettings = async (payload) => { | ||||||
|  |     if (!session.exists()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     try { | ||||||
|  |         await api.updateAccountSettings(config.baseUrl, session.token(), payload); | ||||||
|  |     } catch (e) { | ||||||
|  |         console.log(`[Preferences] Error updating account settings`, e); | ||||||
|  |         if ((e instanceof UnauthorizedError)) { | ||||||
|  |             session.reset(); | ||||||
|  |             window.location.href = routes.login; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export default Preferences; | export default Preferences; | ||||||
|  |  | ||||||
|  | @ -22,11 +22,12 @@ import {basicAuth, formatBytes, maybeWithBasicAuth, topicShortUrl, topicUrl, val | ||||||
| import Box from "@mui/material/Box"; | import Box from "@mui/material/Box"; | ||||||
| import AttachmentIcon from "./AttachmentIcon"; | import AttachmentIcon from "./AttachmentIcon"; | ||||||
| import DialogFooter from "./DialogFooter"; | import DialogFooter from "./DialogFooter"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import userManager from "../app/UserManager"; | import userManager from "../app/UserManager"; | ||||||
| import EmojiPicker from "./EmojiPicker"; | import EmojiPicker from "./EmojiPicker"; | ||||||
| import {Trans, useTranslation} from "react-i18next"; | import {Trans, useTranslation} from "react-i18next"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
|  | import routes from "./routes"; | ||||||
| 
 | 
 | ||||||
| const PublishDialog = (props) => { | const PublishDialog = (props) => { | ||||||
|     const { t } = useTranslation(); |     const { t } = useTranslation(); | ||||||
|  | @ -178,7 +179,12 @@ const PublishDialog = (props) => { | ||||||
|             setAttachFileError(""); |             setAttachFileError(""); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.log(`[PublishDialog] Retrieving attachment limits failed`, e); |             console.log(`[PublishDialog] Retrieving attachment limits failed`, e); | ||||||
|             setAttachFileError(""); // Reset error (rely on server-side checking)
 |             if ((e instanceof UnauthorizedError)) { | ||||||
|  |                 session.reset(); | ||||||
|  |                 window.location.href = routes.login; | ||||||
|  |             } else { | ||||||
|  |                 setAttachFileError(""); // Reset error (rely on server-side checking)
 | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import * as React from 'react'; | ||||||
| import TextField from "@mui/material/TextField"; | import TextField from "@mui/material/TextField"; | ||||||
| import Button from "@mui/material/Button"; | import Button from "@mui/material/Button"; | ||||||
| import Box from "@mui/material/Box"; | import Box from "@mui/material/Box"; | ||||||
| import api, {AccountCreateLimitReachedError, UsernameTakenError} from "../app/Api"; | import api, {AccountCreateLimitReachedError, UnauthorizedError, UsernameTakenError} from "../app/Api"; | ||||||
| import routes from "./routes"; | import routes from "./routes"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
| import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||||
|  | @ -24,14 +24,9 @@ const Signup = () => { | ||||||
|         try { |         try { | ||||||
|             await api.createAccount(config.baseUrl, user.username, user.password); |             await api.createAccount(config.baseUrl, user.username, user.password); | ||||||
|             const token = await api.login(config.baseUrl, user); |             const token = await api.login(config.baseUrl, user); | ||||||
|             if (token) { |             console.log(`[Signup] User signup for user ${user.username} successful, token is ${token}`); | ||||||
|                 console.log(`[Signup] User signup for user ${user.username} successful, token is ${token}`); |             session.store(user.username, token); | ||||||
|                 session.store(user.username, token); |             window.location.href = routes.app; | ||||||
|                 window.location.href = routes.app; |  | ||||||
|             } else { |  | ||||||
|                 console.log(`[Signup] Signup for user ${user.username} failed, access denied`); |  | ||||||
|                 setError(t("Login failed: Invalid username or password")); |  | ||||||
|             } |  | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.log(`[Signup] Signup for user ${user.username} failed`, e); |             console.log(`[Signup] Signup for user ${user.username} failed`, e); | ||||||
|             if ((e instanceof UsernameTakenError)) { |             if ((e instanceof UsernameTakenError)) { | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ import DialogContentText from '@mui/material/DialogContentText'; | ||||||
| import DialogTitle from '@mui/material/DialogTitle'; | import DialogTitle from '@mui/material/DialogTitle'; | ||||||
| import {Autocomplete, Checkbox, FormControlLabel, useMediaQuery} from "@mui/material"; | import {Autocomplete, Checkbox, FormControlLabel, useMediaQuery} from "@mui/material"; | ||||||
| import theme from "./theme"; | import theme from "./theme"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils"; | import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils"; | ||||||
| import userManager from "../app/UserManager"; | import userManager from "../app/UserManager"; | ||||||
| import subscriptionManager from "../app/SubscriptionManager"; | import subscriptionManager from "../app/SubscriptionManager"; | ||||||
|  | @ -16,6 +16,7 @@ import poller from "../app/Poller"; | ||||||
| import DialogFooter from "./DialogFooter"; | import DialogFooter from "./DialogFooter"; | ||||||
| import {useTranslation} from "react-i18next"; | import {useTranslation} from "react-i18next"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
|  | import routes from "./routes"; | ||||||
| 
 | 
 | ||||||
| const publicBaseUrl = "https://ntfy.sh"; | const publicBaseUrl = "https://ntfy.sh"; | ||||||
| 
 | 
 | ||||||
|  | @ -25,14 +26,23 @@ const SubscribeDialog = (props) => { | ||||||
|     const [showLoginPage, setShowLoginPage] = useState(false); |     const [showLoginPage, setShowLoginPage] = useState(false); | ||||||
|     const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); |     const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); | ||||||
|     const handleSuccess = async () => { |     const handleSuccess = async () => { | ||||||
|  |         console.log(`[SubscribeDialog] Subscribing to topic ${topic}`); | ||||||
|         const actualBaseUrl = (baseUrl) ? baseUrl : config.baseUrl; |         const actualBaseUrl = (baseUrl) ? baseUrl : config.baseUrl; | ||||||
|         const subscription = await subscriptionManager.add(actualBaseUrl, topic); |         const subscription = await subscriptionManager.add(actualBaseUrl, topic); | ||||||
|         if (session.exists()) { |         if (session.exists()) { | ||||||
|             const remoteSubscription = await api.addAccountSubscription(config.baseUrl, session.token(), { |             try { | ||||||
|                 base_url: actualBaseUrl, |                 const remoteSubscription = await api.addAccountSubscription(config.baseUrl, session.token(), { | ||||||
|                 topic: topic |                     base_url: actualBaseUrl, | ||||||
|             }); |                     topic: topic | ||||||
|             await subscriptionManager.setRemoteId(subscription.id, remoteSubscription.id); |                 }); | ||||||
|  |                 await subscriptionManager.setRemoteId(subscription.id, remoteSubscription.id); | ||||||
|  |             } catch (e) { | ||||||
|  |                 console.log(`[SubscribeDialog] Subscribing to topic ${topic} failed`, e); | ||||||
|  |                 if ((e instanceof UnauthorizedError)) { | ||||||
|  |                     session.reset(); | ||||||
|  |                     window.location.href = routes.login; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         poller.pollInBackground(subscription); // Dangle!
 |         poller.pollInBackground(subscription); // Dangle!
 | ||||||
|         props.onSuccess(subscription); |         props.onSuccess(subscription); | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ import connectionManager from "../app/ConnectionManager"; | ||||||
| import poller from "../app/Poller"; | import poller from "../app/Poller"; | ||||||
| import pruner from "../app/Pruner"; | import pruner from "../app/Pruner"; | ||||||
| import session from "../app/Session"; | import session from "../app/Session"; | ||||||
| import api from "../app/Api"; | import api, {UnauthorizedError} from "../app/Api"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection |  * Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection | ||||||
|  | @ -64,11 +64,19 @@ export const useAutoSubscribe = (subscriptions, selected) => { | ||||||
|             (async () => { |             (async () => { | ||||||
|                 const subscription = await subscriptionManager.add(baseUrl, params.topic); |                 const subscription = await subscriptionManager.add(baseUrl, params.topic); | ||||||
|                 if (session.exists()) { |                 if (session.exists()) { | ||||||
|                     const remoteSubscription = await api.addAccountSubscription(config.baseUrl, session.token(), { |                     try { | ||||||
|                         base_url: baseUrl, |                         const remoteSubscription = await api.addAccountSubscription(config.baseUrl, session.token(), { | ||||||
|                         topic: params.topic |                             base_url: baseUrl, | ||||||
|                     }); |                             topic: params.topic | ||||||
|                     await subscriptionManager.setRemoteId(subscription.id, remoteSubscription.id); |                         }); | ||||||
|  |                         await subscriptionManager.setRemoteId(subscription.id, remoteSubscription.id); | ||||||
|  |                     } catch (e) { | ||||||
|  |                         console.log(`[App] Auto-subscribing failed`, e); | ||||||
|  |                         if ((e instanceof UnauthorizedError)) { | ||||||
|  |                             session.reset(); | ||||||
|  |                             window.location.href = routes.login; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 poller.pollInBackground(subscription); // Dangle!
 |                 poller.pollInBackground(subscription); // Dangle!
 | ||||||
|             })(); |             })(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue