import * as jwt from 'jsonwebtoken'; import User from '../sharedByClients/models/User'; import LocalConfig from '../config/LocalConfig'; import LocalConfigKeys from '../types/LocalConfigKeys'; import axios, { AxiosError } from 'axios'; import HttpManager from './HttpManager'; import ora from 'ora'; import Permissions from '../types/Permissions'; import ApiRoutes from '../sharedByClients/types/ApiRoutes'; import DojoBackendManager from './DojoBackendManager'; import { StatusCodes } from 'http-status-codes'; class SessionManager { private _token: string | null = null; public profile: User | undefined = undefined; get isLogged(): boolean { return this._token !== null; } get token(): string { return this._token || ''; } set token(token: string) { this._token = token; try { const payload = jwt.decode(token); if ( payload && typeof payload === 'object' && payload.profile ) { this.profile = payload.profile as User; } } catch ( error ) { this.profile = undefined; } LocalConfig.updateConfig(LocalConfigKeys.API_TOKEN, token); } async login(user: string, password: string) { const spinner: ora.Ora = ora('Logging in').start(); try { this.profile = undefined; const response = await axios.post(DojoBackendManager.getApiUrl(ApiRoutes.LOGIN), { user : user, password: password }); spinner.succeed('Logged in'); } catch ( error ) { if ( error instanceof AxiosError ) { if ( error.response ) { if ( error.response.status === StatusCodes.NOT_FOUND ) { spinner.fail('User not found or password incorrect'); } else { spinner.fail(`Login error: ${ error.response.statusText }`); } } } else { spinner.fail(`Login error: ${ error }`); } } } logout() { this.token = ''; } checkPermissions(verbose: boolean = true, indent: number = 8, checkPermissions: Array<string> | null = []): Permissions { const hasPermission = (permissionPredicate: () => boolean, verboseText: string): boolean => { let isAllowed: boolean = this.profile !== undefined && permissionPredicate(); if ( verbose ) { const spinner: ora.Ora = ora({ text : verboseText, indent: indent }).start(); isAllowed ? spinner.succeed() : spinner.fail(); } return isAllowed; }; return { teachingStaff: checkPermissions && (checkPermissions.length == 0 || checkPermissions.includes('teachingStaff')) ? hasPermission(() => this.profile?.isTeachingStaff ?? false, 'Teaching staff permissions') : false, student : checkPermissions && (checkPermissions.length == 0 || checkPermissions.includes('student')) ? hasPermission(() => true, 'Student permissions') : false }; } async testSession(verbose: boolean = true, checkPermissions: Array<string> | null = []): Promise<false | Permissions> { if ( verbose ) { ora('Checking Dojo session: ').start().info(); } HttpManager.handleCommandErrors = false; const spinner: ora.Ora = ora({ text : `Testing Dojo session`, indent: 4 }); if ( verbose ) { spinner.start(); } try { await axios.get(DojoBackendManager.getApiUrl(ApiRoutes.TEST_SESSION), {}); if ( verbose ) { spinner.succeed(`The session is valid`); } } catch ( error ) { if ( verbose ) { spinner.fail(`The session is invalid`); } return false; } return this.checkPermissions(verbose, 8, checkPermissions); } } export default new SessionManager();