From 9688f56c43b26e0d31ab0089756d198eca7417c3 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Thu, 27 Jul 2023 17:54:06 +0300 Subject: [PATCH] Added useId hook for id retrival from token --- front/package-lock.json | 6 +++ front/package.json | 1 + front/src/hooks/index.ts | 1 + front/src/hooks/useId.ts | 16 ++++++++ front/src/pages/LoginPage.tsx | 6 ++- front/src/utils/auth.ts | 75 ++++++++++++++++++++++++++++++++--- 6 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 front/src/hooks/useId.ts diff --git a/front/package-lock.json b/front/package-lock.json index 52f0739..2b86f66 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@types/leaflet": "^1.9.3", "bootstrap": "^5.3.0", + "jwt-decode": "^3.1.2", "leaflet": "^1.9.4", "react": "^18.2.0", "react-bootstrap": "^2.8.0", @@ -2378,6 +2379,11 @@ "node": ">=6" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/leaflet": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", diff --git a/front/package.json b/front/package.json index e848a0c..163e525 100644 --- a/front/package.json +++ b/front/package.json @@ -14,6 +14,7 @@ "dependencies": { "@types/leaflet": "^1.9.3", "bootstrap": "^5.3.0", + "jwt-decode": "^3.1.2", "leaflet": "^1.9.4", "react": "^18.2.0", "react-bootstrap": "^2.8.0", diff --git a/front/src/hooks/index.ts b/front/src/hooks/index.ts index 5a757f7..4d42417 100644 --- a/front/src/hooks/index.ts +++ b/front/src/hooks/index.ts @@ -4,3 +4,4 @@ export { default as useFetch } from './useFetch' export { default as useStoryIndex } from './useStoryIndex' export { default as useFilters } from './useFilters' export { default as useSendWithButton } from './useSendWithButton' +export { default as useId } from './useId' diff --git a/front/src/hooks/useId.ts b/front/src/hooks/useId.ts new file mode 100644 index 0000000..f3f2e0a --- /dev/null +++ b/front/src/hooks/useId.ts @@ -0,0 +1,16 @@ +import { useNavigate } from 'react-router-dom' +import { getId } from '../utils/auth' + +function useId() { + const navigate = useNavigate() + + const id = getId() + + if (id < 0) { + navigate('/login') + } + + return id +} + +export default useId diff --git a/front/src/pages/LoginPage.tsx b/front/src/pages/LoginPage.tsx index fd1a8cb..3ef08a5 100644 --- a/front/src/pages/LoginPage.tsx +++ b/front/src/pages/LoginPage.tsx @@ -24,7 +24,11 @@ function LoginPage() { password: formData.get('password') as string } - const token = import.meta.env.PROD ? await doAuth(data, newAccount) : 'a' + const token = import.meta.env.PROD ? ( + await doAuth(data, newAccount) + ) : ( + 'eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjUifQ.1S46AuB9E4JN9yLkqs30yl3sLlGLbgbrOCNKXiNK8IM' + ) if (token) { setToken(token) diff --git a/front/src/utils/auth.ts b/front/src/utils/auth.ts index a380ee4..0f37b67 100644 --- a/front/src/utils/auth.ts +++ b/front/src/utils/auth.ts @@ -1,13 +1,76 @@ -const getToken = () => { - const token = localStorage.getItem('Token') +import jwt_decode, { JwtPayload } from 'jwt-decode' - /* check expirity */ +import { isInt, isObject } from './types' - return token +const TOKEN_KEY = 'Token' + +function getToken() { + const token = localStorage.getItem(TOKEN_KEY) + + if (token === null) { + return null + } + + const payload = jwt_decode(token) + + // Checks only expiration, not validity + if ( + payload.exp && + (Date.now() >= payload.exp * 1000) + ) { + return null + } + + return token } function setToken(token: string) { - localStorage.setItem('Token', token) + localStorage.setItem(TOKEN_KEY, token) } -export { getToken, setToken } +function clearToken() { + localStorage.removeItem(TOKEN_KEY) +} + +type TokenPayload = { + id: string +} + +const isTokenPayload = (data: unknown): data is TokenPayload => isObject(data, { + 'id': 'string' +}) + +function getId() { + try { + const token = getToken() + + if (token === null) { + return -1 + } + + const payload = jwt_decode(token) + + if (!isTokenPayload(payload)) { + throw new Error('Malformed token payload') + } + + const id = Number.parseInt(payload.id) + + if (!isInt(id) || id < 0) { + throw new Error(`Not valid id: ${id}`) + } + + return id + } + catch (err) { + if (import.meta.env.DEV) { + console.error(err) + } + + clearToken() + + return -1 + } +} + +export { getToken, setToken, getId }