basic frontend implementation of new token system

This commit is contained in:
2021-09-19 23:20:37 +02:00
parent e985eb941c
commit f17bac399a
17 changed files with 436 additions and 460 deletions

View 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 '';
}
}

View 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
});

View 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 <></>;
}
};