From bed8aec44f19dd98fa2b0c741d417f0979e27980 Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Mon, 12 Dec 2022 02:32:47 +0200 Subject: [PATCH] add token for secured resources --- src/api/useHttpRequest.js | 2 +- src/components/App.js | 4 ++-- src/components/Header/Header.js | 4 ++-- src/components/Layout/Content.js | 2 +- src/components/Sidebar/Sidebar.js | 2 +- src/{context => contexts}/LayoutContext.js | 0 src/{context => contexts}/ToastContext.js | 0 src/{context => contexts}/UserContext.js | 6 ++++-- .../resources/components/ResourcesContainer.js | 11 +++++++---- src/hooks/index.js | 5 ++++- src/hooks/useResourceSecurity.js | 13 +++++++++++++ src/index.js | 6 +++--- src/pages/login/Login.js | 2 +- src/pages/notifications/Notifications.js | 2 +- src/utils/identity.js | 7 ++++--- 15 files changed, 44 insertions(+), 22 deletions(-) rename src/{context => contexts}/LayoutContext.js (100%) rename src/{context => contexts}/ToastContext.js (100%) rename src/{context => contexts}/UserContext.js (94%) create mode 100644 src/hooks/useResourceSecurity.js diff --git a/src/api/useHttpRequest.js b/src/api/useHttpRequest.js index 94d2698..8a523e5 100644 --- a/src/api/useHttpRequest.js +++ b/src/api/useHttpRequest.js @@ -1,5 +1,5 @@ import { useCallback, useMemo } from "react"; -import { useToast } from "../context/ToastContext"; +import { useToast } from "../contexts/ToastContext"; const useHttpRequest = () => { const { error } = useToast(); diff --git a/src/components/App.js b/src/components/App.js index 0e8e394..b7dc386 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -9,8 +9,8 @@ import Error from "../pages/error"; import Login from "../pages/login"; // context -import { useUserState } from "../context/UserContext"; -import { useToast } from "../context/ToastContext"; +import { useUserState } from "../contexts/UserContext"; +import { useToast } from "../contexts/ToastContext"; import { useTranslation } from "react-i18next"; export default function App() { diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index b90c577..d6fedbc 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -32,8 +32,8 @@ import { useLayoutState, useLayoutDispatch, toggleSidebar -} from "../../context/LayoutContext"; -import { useUserDispatch, signOut } from "../../context/UserContext"; +} from "../../contexts/LayoutContext"; +import { useUserDispatch, signOut } from "../../contexts/UserContext"; const messages = [ { diff --git a/src/components/Layout/Content.js b/src/components/Layout/Content.js index 138f563..1dddbe9 100644 --- a/src/components/Layout/Content.js +++ b/src/components/Layout/Content.js @@ -17,7 +17,7 @@ import ContentFooter from "./ContentFooter"; import ResourcesContainer from "../../features/resources/components/ResourcesContainer"; // context -import { useLayoutState } from "../../context/LayoutContext"; +import { useLayoutState } from "../../contexts/LayoutContext"; // styles import useStyles from "./styles"; diff --git a/src/components/Sidebar/Sidebar.js b/src/components/Sidebar/Sidebar.js index 7dd0ee2..59f3539 100644 --- a/src/components/Sidebar/Sidebar.js +++ b/src/components/Sidebar/Sidebar.js @@ -16,7 +16,7 @@ import { useLayoutState, useLayoutDispatch, toggleSidebar -} from "../../context/LayoutContext"; +} from "../../contexts/LayoutContext"; import menu from "./menu"; diff --git a/src/context/LayoutContext.js b/src/contexts/LayoutContext.js similarity index 100% rename from src/context/LayoutContext.js rename to src/contexts/LayoutContext.js diff --git a/src/context/ToastContext.js b/src/contexts/ToastContext.js similarity index 100% rename from src/context/ToastContext.js rename to src/contexts/ToastContext.js diff --git a/src/context/UserContext.js b/src/contexts/UserContext.js similarity index 94% rename from src/context/UserContext.js rename to src/contexts/UserContext.js index ab0b601..ac0bab0 100644 --- a/src/context/UserContext.js +++ b/src/contexts/UserContext.js @@ -7,7 +7,7 @@ var UserDispatchContext = React.createContext(); function userReducer(state, action) { switch (action.type) { case "LOGIN_SUCCESS": - return { ...state, authenticated: true }; + return { ...state, ...action.payload, authenticated: true }; case "SIGN_OUT_SUCCESS": return { ...state, authenticated: false }; case "LOGIN_FAILURE": @@ -23,8 +23,10 @@ function userReducer(state, action) { } function UserProvider({ children }) { + const { valid, token } = validateToken(); var [state, dispatch] = React.useReducer(userReducer, { - authenticated: validateToken() === true + authenticated: valid === true, + token }); return ( diff --git a/src/features/resources/components/ResourcesContainer.js b/src/features/resources/components/ResourcesContainer.js index 46e1184..4ba9cbe 100644 --- a/src/features/resources/components/ResourcesContainer.js +++ b/src/features/resources/components/ResourcesContainer.js @@ -13,7 +13,7 @@ import { FileCopyOutlined, OpenInNewOutlined } from "@material-ui/icons"; -import { useToast } from "../../../context/ToastContext"; +import { useToast, useResourceSecurity } from "../../../hooks"; const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100]; const __RESOURCE_NAME_MAX_LENGTH = 35; @@ -32,6 +32,7 @@ const ResourcesContainer = () => { const { info } = useToast(); const { getResources } = useResourcesApi(); const { getResourceCategories } = useDictionariesApi(); + const { secureUrl } = useResourceSecurity(); useEffect(() => { getResourceCategories().then((r) => setResourceCategories(r)); @@ -81,7 +82,8 @@ const ResourcesContainer = () => { { code: "copy-url", effect: (_event, resource) => { - navigator.clipboard.writeText(resource.url); + const url = resource.secured ? secureUrl(resource.url) : resource.url; + navigator.clipboard.writeText(url); info(t("Resource.List.Actions.LinkCopiedToClipboard")); }, icon: FileCopyOutlined, @@ -91,7 +93,8 @@ const ResourcesContainer = () => { { code: "open-in-new-tab", effect: (event, resource) => { - window.open(resource.url, "_blank"); + const url = resource.secured ? secureUrl(resource.url) : resource.url; + window.open(url, "_blank"); event.preventDefault(); }, icon: OpenInNewOutlined, @@ -99,7 +102,7 @@ const ResourcesContainer = () => { top: false } ], - [t, info] + [t, info, secureUrl] ); const columns = useMemo( diff --git a/src/hooks/index.js b/src/hooks/index.js index 356f966..51d6f91 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -1 +1,4 @@ -//export { useAuthorizationToken } from "./useAuthorizationToken"; +import { useToast } from "../contexts/ToastContext"; +import useResourceSecurity from "./useResourceSecurity"; + +export { useToast, useResourceSecurity }; diff --git a/src/hooks/useResourceSecurity.js b/src/hooks/useResourceSecurity.js new file mode 100644 index 0000000..3dc13aa --- /dev/null +++ b/src/hooks/useResourceSecurity.js @@ -0,0 +1,13 @@ +import { useUserState } from "../contexts/UserContext"; +import { useCallback } from "react"; + +const useResourceSecurity = () => { + const { token } = useUserState(); + const secureUrl = useCallback((url) => `${url}?token=${token.raw}`, [ + token.raw + ]); + + return { secureUrl }; +}; + +export default useResourceSecurity; diff --git a/src/index.js b/src/index.js index 38be7a5..a6e4b72 100644 --- a/src/index.js +++ b/src/index.js @@ -5,9 +5,9 @@ import { CssBaseline } from "@material-ui/core"; import Themes from "./themes"; import App from "./components/App"; import * as serviceWorker from "./serviceWorker"; -import { LayoutProvider } from "./context/LayoutContext"; -import { UserProvider } from "./context/UserContext"; -import { ToastProvider } from "./context/ToastContext"; +import { LayoutProvider } from "./contexts/LayoutContext"; +import { UserProvider } from "./contexts/UserContext"; +import { ToastProvider } from "./contexts/ToastContext"; import "./utils/i18n"; ReactDOM.render( diff --git a/src/pages/login/Login.js b/src/pages/login/Login.js index 66ea40a..35e26d0 100644 --- a/src/pages/login/Login.js +++ b/src/pages/login/Login.js @@ -20,7 +20,7 @@ import logo from "./logo.svg"; import google from "../../images/google.svg"; // context -import { useUserDispatch, loginUser } from "../../context/UserContext"; +import { useUserDispatch, loginUser } from "../../contexts/UserContext"; function Login(props) { var classes = useStyles(); diff --git a/src/pages/notifications/Notifications.js b/src/pages/notifications/Notifications.js index a455c04..9c7c306 100644 --- a/src/pages/notifications/Notifications.js +++ b/src/pages/notifications/Notifications.js @@ -16,7 +16,7 @@ import Notification from "../../components/Notification"; import { Typography, Button } from "../../components/Wrappers/Wrappers"; // context -import { useToast, useToastState } from "../../context/ToastContext"; +import { useToast, useToastState } from "../../contexts/ToastContext"; export default function NotificationsPage(props) { const classes = useStyles(); diff --git a/src/utils/identity.js b/src/utils/identity.js index 14912c5..5755486 100644 --- a/src/utils/identity.js +++ b/src/utils/identity.js @@ -33,17 +33,18 @@ const invalidate = () => { }; const validateToken = () => { - const token = getItem(storageKeys.TOKEN); + let token = getItem(storageKeys.TOKEN); if (!token) { - return false; + return { valid: false }; } const valid = new Date(token.validUntil) >= new Date(); if (!valid) { invalidate(); + token = null; } - return valid; + return { valid, token }; }; export { storageKeys, authenticate, invalidate, validateToken };