Fix stale user permissions in UI by refreshing user data on app load (#4751)
* add refresh user functionality * prettier * add eslint disable comment for exhaustive-deps warning in AuthContext to stop nagging about navigate func * remove unused imports and fix typo * handle unsafe parse of undefined for in-session user deleted --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
parent
b620ca40ce
commit
8e0186f9ac
@ -1,20 +1,31 @@
|
||||
import React, { useState, createContext } from "react";
|
||||
import React, { useState, createContext, useEffect } from "react";
|
||||
import {
|
||||
AUTH_TIMESTAMP,
|
||||
AUTH_TOKEN,
|
||||
AUTH_USER,
|
||||
USER_PROMPT_INPUT_MAP,
|
||||
} from "@/utils/constants";
|
||||
import System from "./models/system";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { safeJsonParse } from "@/utils/request";
|
||||
|
||||
export const AuthContext = createContext(null);
|
||||
export function AuthProvider(props) {
|
||||
const localUser = localStorage.getItem(AUTH_USER);
|
||||
const localAuthToken = localStorage.getItem(AUTH_TOKEN);
|
||||
const [store, setStore] = useState({
|
||||
user: localUser ? JSON.parse(localUser) : null,
|
||||
user: localUser ? safeJsonParse(localUser, null) : null,
|
||||
authToken: localAuthToken ? localAuthToken : null,
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
/* NOTE:
|
||||
* 1. There's no reason for these helper functions to be stateful. They could
|
||||
* just be regular funcs or methods on a basic object.
|
||||
* 2. These actions are not being invoked anywhere in the
|
||||
* codebase, dead code.
|
||||
*/
|
||||
const [actions] = useState({
|
||||
updateUser: (user, authToken = "") => {
|
||||
localStorage.setItem(AUTH_USER, JSON.stringify(user));
|
||||
@ -30,6 +41,29 @@ export function AuthProvider(props) {
|
||||
},
|
||||
});
|
||||
|
||||
// On initial mount and whenever the token changes fetch a new user object
|
||||
useEffect(() => {
|
||||
if (store.authToken) {
|
||||
System.refreshUser()
|
||||
.then(({ user }) => {
|
||||
localStorage.setItem(AUTH_USER, JSON.stringify(user));
|
||||
setStore((prev) => ({
|
||||
...prev,
|
||||
user,
|
||||
}));
|
||||
})
|
||||
.catch(() => {
|
||||
localStorage.removeItem(AUTH_USER);
|
||||
localStorage.removeItem(AUTH_TOKEN);
|
||||
localStorage.removeItem(AUTH_TIMESTAMP);
|
||||
localStorage.removeItem(USER_PROMPT_INPUT_MAP);
|
||||
setStore({ user: null, authToken: null });
|
||||
navigate("/login");
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [store.authToken]);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ store, actions }}>
|
||||
{props.children}
|
||||
|
||||
@ -83,6 +83,14 @@ const System = {
|
||||
return { valid: false, message: e.message };
|
||||
});
|
||||
},
|
||||
refreshUser: () => {
|
||||
return fetch(`${API_BASE}/system/refresh-user`, { headers: baseHeaders() })
|
||||
.then((res) => res.json())
|
||||
.then((data) => data)
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
},
|
||||
recoverAccount: async function (username, recoveryCodes) {
|
||||
return await fetch(`${API_BASE}/system/recover-account`, {
|
||||
method: "POST",
|
||||
|
||||
@ -114,6 +114,35 @@ function systemEndpoints(app) {
|
||||
}
|
||||
);
|
||||
|
||||
app.get("/system/refresh-user", [validatedRequest], async (req, res) => {
|
||||
try {
|
||||
if (multiUserMode(res)) {
|
||||
const user = await userFromSession(req, res);
|
||||
if (!user || user.suspended) {
|
||||
res.sendStatus(403).end();
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
valid: true,
|
||||
user: User.filterFields(user),
|
||||
message: null,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "Multi-User Mode is not enabled.",
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: "Failed to retrieve the user from session.",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/request-token", async (request, response) => {
|
||||
try {
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user