diff --git a/package-lock.json b/package-lock.json index e50a980..3441122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@heroicons/react": "^2.0.14", "@loadable/component": "^5.15.3", "@tanstack/react-table": "^8.7.9", + "buffer": "^6.0.3", "date-fns": "^2.29.3", "dotenv": "^16.0.3", "formik": "^2.2.9", @@ -3832,6 +3833,25 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -3891,6 +3911,29 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -5851,6 +5894,25 @@ "react-is": "^16.7.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -10717,6 +10779,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -10754,6 +10821,15 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -12172,6 +12248,11 @@ "react-is": "^16.7.0" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", diff --git a/package.json b/package.json index 4cc17e8..17322c2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@heroicons/react": "^2.0.14", "@loadable/component": "^5.15.3", "@tanstack/react-table": "^8.7.9", + "buffer": "^6.0.3", "date-fns": "^2.29.3", "dotenv": "^16.0.3", "formik": "^2.2.9", diff --git a/src/app/auth/Login.tsx b/src/app/auth/Login.tsx index 5a73539..c6641c6 100644 --- a/src/app/auth/Login.tsx +++ b/src/app/auth/Login.tsx @@ -97,7 +97,7 @@ export default function Login() { loadProviders(); }, [setProviders, setError]); - if (session) { + if (session && (!session.required || session.authenticated)) { return ; } diff --git a/src/components/SessionProvider.tsx b/src/components/SessionProvider.tsx index 66db3f6..e13b15f 100644 --- a/src/components/SessionProvider.tsx +++ b/src/components/SessionProvider.tsx @@ -2,16 +2,17 @@ import { createContext, useEffect, useMemo } from 'react'; import { getAuthSelf, getInfo } from '~/data/api'; import { useStorage } from '~/data/hooks/storage'; import { AuthMethodOIDCSelf } from '~/types/Auth'; -import { Info } from '~/types/Meta'; type Session = { - info: Info; - self: AuthMethodOIDCSelf; + required: boolean; + authenticated: boolean; + self?: AuthMethodOIDCSelf; }; interface SessionContextType { session?: Session; setSession: (data: any) => void; + clearSession: () => void; } export const SessionContext = createContext({} as SessionContextType); @@ -21,17 +22,17 @@ export default function SessionProvider({ }: { children: React.ReactNode; }) { - const [session, setSession, clearSession] = useStorage('flipt', null); + const [session, setSession, clearSession] = useStorage('session', null); useEffect(() => { const loadSession = async () => { - let data = null; + let session = { + required: true, + authenticated: false + } as Session; try { - const info = await getInfo(); - data = { - info: info - }; + await getInfo(); } catch (err) { // if we can't get the info, we're not logged in // or there was an error, either way, clear the session so we redirect @@ -42,16 +43,22 @@ export default function SessionProvider({ try { const self = await getAuthSelf(); - data = { - ...data, + session = { + authenticated: true, + required: true, self: self }; } catch (err) { // if we can't get the self info and we got here then auth is likely not enabled // so we can just return - return; + session = { + authenticated: false, + required: false + }; } finally { - setSession(data); + if (session) { + setSession(session); + } } }; if (!session) loadSession(); @@ -61,9 +68,10 @@ export default function SessionProvider({ const value = useMemo( () => ({ session, - setSession + setSession, + clearSession }), - [session, setSession] + [session, setSession, clearSession] ); return ( diff --git a/src/components/UserProfile.tsx b/src/components/UserProfile.tsx index d387c38..6dfa0ae 100644 --- a/src/components/UserProfile.tsx +++ b/src/components/UserProfile.tsx @@ -15,12 +15,12 @@ export default function UserProfile(props: UserProfileProps) { const { name, imgURL } = props; const { setError } = useError(); - const { setSession } = useSession(); + const { clearSession } = useSession(); const logout = async () => { expireAuthSelf() .then(() => { - setSession(null); + clearSession(); window.location.href = '/'; }) .catch((err) => { diff --git a/src/data/hooks/storage.ts b/src/data/hooks/storage.ts index d9e5631..b2d94a1 100644 --- a/src/data/hooks/storage.ts +++ b/src/data/hooks/storage.ts @@ -1,10 +1,12 @@ +import { Buffer } from 'buffer'; import { useState } from 'react'; export const useStorage = (key: string, initialValue: any) => { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); - return item ? JSON.parse(item) : initialValue; + const buffer = item ? Buffer.from(item, 'base64') : null; + return buffer ? JSON.parse(buffer.toLocaleString()) : initialValue; } catch (error) { console.error(error); return initialValue; @@ -16,7 +18,8 @@ export const useStorage = (key: string, initialValue: any) => { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); - window.localStorage.setItem(key, JSON.stringify(valueToStore)); + const buffer = Buffer.from(JSON.stringify(valueToStore)); + window.localStorage.setItem(key, buffer.toString('base64')); } catch (error) { console.error(error); }