From 99117de72727892e7688e9454a18f06d9fd6c6dd Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Sat, 18 Sep 2021 17:49:18 +1000 Subject: [PATCH] insure jwt token is fresh --- package.json | 1 + src/components/Setup/Step3ProjectOwner.tsx | 3 +- .../Table/TableHeader/Extensions/utils.ts | 62 +++++-------------- src/contexts/AppContext.tsx | 25 ++++++-- src/contexts/ProjectContext.tsx | 9 +-- src/pages/Auth/ImpersonatorAuth.tsx | 4 -- yarn.lock | 5 ++ 7 files changed, 46 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index 359a7f47..e8f88de6 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "json-format": "^1.0.1", "json2csv": "^5.0.6", "jszip": "^3.6.0", + "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "moment": "^2.29.1", "notistack": "^1.0.6-next.3", diff --git a/src/components/Setup/Step3ProjectOwner.tsx b/src/components/Setup/Step3ProjectOwner.tsx index dbe26fd3..c12f7fef 100644 --- a/src/components/Setup/Step3ProjectOwner.tsx +++ b/src/components/Setup/Step3ProjectOwner.tsx @@ -17,7 +17,7 @@ export default function Step3ProjectOwner({ completion, setCompletion, }: ISetupStepBodyProps) { - const { projectId, currentUser, authToken } = useAppContext(); + const { projectId, currentUser, getAuthToken } = useAppContext(); const [email, setEmail] = useState(""); useEffect(() => { @@ -37,6 +37,7 @@ export default function Step3ProjectOwner({ const setRoles = async () => { setHasRoles("LOADING"); try { + const authToken = await getAuthToken(); const res = await rowyRun({ route: runRoutes.setOwnerRoles, rowyRunUrl, diff --git a/src/components/Table/TableHeader/Extensions/utils.ts b/src/components/Table/TableHeader/Extensions/utils.ts index d0f9b412..590f358e 100644 --- a/src/components/Table/TableHeader/Extensions/utils.ts +++ b/src/components/Table/TableHeader/Extensions/utils.ts @@ -176,37 +176,6 @@ function emptyExtensionObject( lastEditor: user, }; } - -/* Convert extension objects into a single ft-build readable string */ -function serialiseExtension(extensions: IExtension[]): string { - const serialisedExtension = - "[" + - extensions - .filter((extension) => extension.active) - .map( - (extension) => `{ - name: "${extension.name}", - type: "${extension.type}", - triggers: [${extension.triggers - .map((trigger) => `"${trigger}"`) - .join(", ")}], - conditions: ${extension.conditions - .replace(/^.*:\s*Condition\s*=/, "") - .replace(/\s*;\s*$/, "")}, - requiredFields: [${extension.requiredFields - .map((field) => `"${field}"`) - .join(", ")}], - extensionBody: ${extension.extensionBody - .replace(/^.*:\s*\w*Body\s*=/, "") - .replace(/\s*;\s*$/, "")} - }` - ) - .join(",") + - "]"; - console.log("serialisedExtension", serialisedExtension); - return serialisedExtension; -} - function sparkToExtensionObjects( sparkConfig: string, user: IExtensionEditor @@ -248,28 +217,25 @@ function sparkToExtensionObjects( sparkBody, }; }); - const extensionObjects = sparks?.map( - (spark, index): IExtension => { - return { - // rowy meta fields - name: `Migrated spark ${index}`, - active: true, - lastEditor: user, + const extensionObjects = sparks?.map((spark, index): IExtension => { + return { + // rowy meta fields + name: `Migrated spark ${index}`, + active: true, + lastEditor: user, - // ft build fields - triggers: (spark.triggers ?? []) as IExtensionTrigger[], - type: spark.type as IExtensionType, - requiredFields: spark.requiredFields ?? [], - extensionBody: spark.sparkBody, - conditions: spark.shouldRun ?? "", - }; - } - ); + // ft build fields + triggers: (spark.triggers ?? []) as IExtensionTrigger[], + type: spark.type as IExtensionType, + requiredFields: spark.requiredFields ?? [], + extensionBody: spark.sparkBody, + conditions: spark.shouldRun ?? "", + }; + }); return extensionObjects ?? []; } export { - serialiseExtension, extensionTypes, triggerTypes, emptyExtensionObject, diff --git a/src/contexts/AppContext.tsx b/src/contexts/AppContext.tsx index d4af5073..354ddd7a 100644 --- a/src/contexts/AppContext.tsx +++ b/src/contexts/AppContext.tsx @@ -3,7 +3,7 @@ import firebase from "firebase/app"; import createPersistedState from "use-persisted-state"; import _merge from "lodash/merge"; import Helmet from "react-helmet"; - +import jwt_decode from "jwt-decode"; import { useMediaQuery, ThemeProvider, CssBaseline } from "@mui/material"; import ErrorBoundary from "components/ErrorBoundary"; @@ -25,7 +25,7 @@ interface IAppContext { currentUser: firebase.User | null | undefined; userClaims: Record | undefined; userRoles: null | string[]; - authToken: string; + getAuthToken: () => Promise; userDoc: any; theme: keyof typeof themes; themeOverridden: boolean; @@ -38,7 +38,7 @@ export const AppContext = React.createContext({ currentUser: undefined, userClaims: undefined, userRoles: [], - authToken: "", + getAuthToken: async () => await "", userDoc: undefined, theme: "light", themeOverridden: false, @@ -57,13 +57,26 @@ export const AppProvider: React.FC = ({ children }) => { const [userClaims, setUserClaims] = useState(undefined); const [userRoles, setUserRoles] = useState([]); - const [authToken, setAuthToken] = useState(""); + const [authToken, setAuthToken] = useState(""); // Get user data from Firebase Auth event + + const getAuthToken = async () => { + // check if token is expired + if (currentUser) { + const token: any = jwt_decode(authToken); + if (token && token.exp * 1000 < Date.now()) { + // token is expired + console.log("token is expired,getting new token"); + const res = await currentUser.getIdTokenResult(true); + setAuthToken(res.token as string); + return res.token; + } else return authToken; + } else return ""; + }; useEffect(() => { auth.onAuthStateChanged((auth) => { setCurrentUser(auth); - if (auth) auth.getIdTokenResult(true).then((results) => { setAuthToken(results.token); @@ -151,7 +164,7 @@ export const AppProvider: React.FC = ({ children }) => { currentUser, userClaims, userRoles, - authToken, + getAuthToken, userDoc: { state: userDoc, dispatch: dispatchUserDoc }, theme, themeOverridden, diff --git a/src/contexts/ProjectContext.tsx b/src/contexts/ProjectContext.tsx index 6200a029..52e2bbf0 100644 --- a/src/contexts/ProjectContext.tsx +++ b/src/contexts/ProjectContext.tsx @@ -91,7 +91,7 @@ export const rowyUser = (currentUser) => { export const useProjectContext = () => useContext(ProjectContext); export const ProjectContextProvider: React.FC = ({ children }) => { - const { currentUser, userRoles, authToken } = useAppContext(); + const { currentUser, userRoles, getAuthToken } = useAppContext(); const { enqueueSnackbar } = useSnackbar(); const { tableState, tableActions } = useTable(); @@ -165,10 +165,11 @@ export const ProjectContextProvider: React.FC = ({ children }) => { } ); }; - // rowyRun access - const _rowyRun: IProjectContext["rowyRun"] = async (args) => - rowyRun({ rowyRunUrl: settings.doc.rowyRunUrl, authToken, ...args }); + const _rowyRun: IProjectContext["rowyRun"] = async (args) => { + const authToken = await getAuthToken(); + return rowyRun({ rowyRunUrl: settings.doc.rowyRunUrl, authToken, ...args }); + }; // A ref to the data grid. Contains data grid functions const dataGridRef = useRef(null); diff --git a/src/pages/Auth/ImpersonatorAuth.tsx b/src/pages/Auth/ImpersonatorAuth.tsx index b2ad6dcf..e5e074a6 100644 --- a/src/pages/Auth/ImpersonatorAuth.tsx +++ b/src/pages/Auth/ImpersonatorAuth.tsx @@ -26,16 +26,12 @@ export default function ImpersonatorAuthPage() { const [email, setEmail] = useState(""); const handleAuth = async (email: string) => { - console.log("!rowyRun"); - if (!rowyRun) return; - console.log("rowyRun"); setLoading(true); const resp = await rowyRun({ route: runRoutes.impersonateUser, params: [email], }); - console.log(resp); setLoading(false); if (resp.success) { enqueueSnackbar(resp.message, { variant: "success" }); diff --git a/yarn.lock b/yarn.lock index f5b486ee..2c9453e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10243,6 +10243,11 @@ jws@^4.0.0: jwa "^2.0.0" safe-buffer "^5.0.1" +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"