basic frontend implementation of new token system
This commit is contained in:
55
src/utils/context/Cookie.ts
Normal file
55
src/utils/context/Cookie.ts
Normal file
@ -0,0 +1,55 @@
|
||||
export interface Token {
|
||||
Token: string;
|
||||
ExpiresAt: number;
|
||||
}
|
||||
|
||||
export namespace cookie {
|
||||
const jwtcookiename = 'jwt';
|
||||
|
||||
export function Store(data: Token): void {
|
||||
const d = new Date();
|
||||
d.setTime(data.ExpiresAt * 1000);
|
||||
const expires = 'expires=' + d.toUTCString();
|
||||
|
||||
document.cookie = jwtcookiename + '=' + JSON.stringify(data) + ';' + expires + ';path=/';
|
||||
}
|
||||
|
||||
export function Load(): Token | null {
|
||||
const datastr = decodeCookie(jwtcookiename);
|
||||
if (datastr === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(datastr);
|
||||
} catch (e) {
|
||||
// if cookie not decodeable delete it and return null
|
||||
Delete();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function Delete(): void {
|
||||
document.cookie = `${jwtcookiename}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode a simple cookie with key specified
|
||||
* @param key cookie key
|
||||
*/
|
||||
function decodeCookie(key: string): string {
|
||||
let name = key + '=';
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
34
src/utils/context/LoginContext.ts
Normal file
34
src/utils/context/LoginContext.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* global context definitions
|
||||
*/
|
||||
|
||||
export enum LoginState {
|
||||
LoggedIn,
|
||||
LoggedOut
|
||||
}
|
||||
|
||||
export enum LoginPerm {
|
||||
Admin,
|
||||
User
|
||||
}
|
||||
|
||||
export interface LoginContextType {
|
||||
logout: () => void;
|
||||
setPerm: (permission: LoginPerm) => void;
|
||||
loginstate: LoginState;
|
||||
setLoginState: (state: LoginState) => void;
|
||||
permission: LoginPerm;
|
||||
}
|
||||
|
||||
/**
|
||||
* A global context providing a way to interact with user login states
|
||||
*/
|
||||
export const LoginContext = React.createContext<LoginContextType>({
|
||||
setLoginState(): void {},
|
||||
setPerm(): void {},
|
||||
logout: () => {},
|
||||
loginstate: LoginState.LoggedOut,
|
||||
permission: LoginPerm.User
|
||||
});
|
105
src/utils/context/LoginContextProvider.tsx
Normal file
105
src/utils/context/LoginContextProvider.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import {LoginContext, LoginPerm, LoginState} from './LoginContext';
|
||||
import React, {FunctionComponent, useContext, useEffect, useState} from 'react';
|
||||
import {useHistory, useLocation} from 'react-router';
|
||||
import {cookie} from './Cookie';
|
||||
import {APINode, callAPI} from '../Api';
|
||||
import {SettingsTypes} from '../../types/ApiTypes';
|
||||
import GlobalInfos from '../GlobalInfos';
|
||||
|
||||
export const LoginContextProvider: FunctionComponent = (props): JSX.Element => {
|
||||
let initialLoginState = LoginState.LoggedIn;
|
||||
let initialUserPerm = LoginPerm.User;
|
||||
|
||||
const t = cookie.Load();
|
||||
// we are already logged in so we can set the token and redirect to dashboard
|
||||
if (t !== null) {
|
||||
initialLoginState = LoginState.LoggedIn;
|
||||
}
|
||||
|
||||
const initialAPICall = (): void => {
|
||||
// this is the first api call so if it fails we know there is no connection to backend
|
||||
callAPI(
|
||||
APINode.Settings,
|
||||
{action: 'loadInitialData'},
|
||||
(result: SettingsTypes.initialApiCallData) => {
|
||||
// set theme
|
||||
GlobalInfos.enableDarkTheme(result.DarkMode);
|
||||
|
||||
GlobalInfos.setVideoPaths(result.VideoPath, result.TVShowPath);
|
||||
|
||||
GlobalInfos.setTVShowsEnabled(result.TVShowEnabled);
|
||||
GlobalInfos.setFullDeleteEnabled(result.FullDeleteEnabled);
|
||||
//
|
||||
// this.setState({
|
||||
// mediacentername: result.MediacenterName
|
||||
// });
|
||||
// set tab title to received mediacenter name
|
||||
document.title = result.MediacenterName;
|
||||
|
||||
setLoginState(LoginState.LoggedIn);
|
||||
},
|
||||
(_) => {
|
||||
setLoginState(LoginState.LoggedOut);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
initialAPICall();
|
||||
}, []);
|
||||
|
||||
const [loginState, setLoginState] = useState<LoginState>(initialLoginState);
|
||||
const [permission, setPermission] = useState<LoginPerm>(initialUserPerm);
|
||||
|
||||
const hist = useHistory();
|
||||
const loc = useLocation();
|
||||
|
||||
// trigger redirect on loginstate change
|
||||
useEffect(() => {
|
||||
if (loginState === LoginState.LoggedIn) {
|
||||
// if we arent already in dashboard tree we want to redirect to default dashboard page
|
||||
console.log('redirecting to dashboard' + loc.pathname);
|
||||
if (!loc.pathname.startsWith('/media')) {
|
||||
hist.replace('/media');
|
||||
}
|
||||
} else {
|
||||
if (!loc.pathname.startsWith('/login')) {
|
||||
hist.replace('/login');
|
||||
}
|
||||
}
|
||||
}, [hist, loc.pathname, loginState]);
|
||||
|
||||
const value = {
|
||||
logout: (): void => {
|
||||
setLoginState(LoginState.LoggedOut);
|
||||
cookie.Delete();
|
||||
},
|
||||
setPerm: (perm: LoginPerm): void => {
|
||||
setPermission(perm);
|
||||
},
|
||||
setLoginState: (state: LoginState): void => {
|
||||
setLoginState(state);
|
||||
},
|
||||
loginstate: loginState,
|
||||
permission: permission
|
||||
};
|
||||
|
||||
return <LoginContext.Provider value={value}>{props.children}</LoginContext.Provider>;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
perm: LoginPerm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper element to render children only if permissions are sufficient
|
||||
*/
|
||||
export const AuthorizedContext: FunctionComponent<Props> = (props): JSX.Element => {
|
||||
const loginctx = useContext(LoginContext);
|
||||
|
||||
if (loginctx.permission <= props.perm) {
|
||||
return props.children as JSX.Element;
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user