UNPKG

@3kles/3kles-coreion

Version:
146 lines (129 loc) 5.32 kB
import { AuthToken, HttpApi, JSONParser } from '@3kles/3kles-corebe'; import { Request, Response, NextFunction } from 'express'; import { Mutex, MutexInterface } from 'async-mutex'; import * as jwt from 'jsonwebtoken'; import * as base64 from 'base-64'; export class AuthService extends AuthToken { protected httpAPI: HttpApi; private token: { token_type: string, access_token: string }; private mutex: Mutex; private deltaTime: number = +process.env.DELTA_TIME || 1000; constructor(params: any) { super(params); this.mutex = new Mutex(); this.secretKey = process.env.cs; this.httpAPI = new HttpApi('https'); this.httpAPI.setResponseParser(new JSONParser()); this.httpAPI.setErrorParser(new JSONParser()); } public async authenticate(req: Request, res: Response, next: NextFunction): Promise<any> { try { const response = await this.getIONBEServiceToken(); return res.status(200).json(response); } catch (err) { res.status(404).json(err); return next(err); } } public async checkAuth(req: Request, res: Response, next: NextFunction): Promise<void> { try { if (req.headers['authorization']) { const token = (req.headers['authorization'].split(' ').length > 1) ? req.headers['authorization'].split(' ')[1] : req.headers['authorization']; const decodedToken: any = jwt.decode(token, { complete: true }); const expired = Date.now() >= +(decodedToken?.payload?.exp) * 1000; if (expired) { const authTokenObj = await this.getIONBEServiceToken(); const authToken = this.formatAuthToken(authTokenObj); res.set('authorization', authToken); next(); } else { next(); } } else { const authTokenObj = await this.getIONBEServiceToken(); const token = this.formatAuthToken(authTokenObj); res.set('authorization', token); next(); } } catch (err) { console.error('[Ion Service]: An error occurred while retrieving the token'); console.error(err); res.status(err.statusCode || 500).json({ error: 'An error occurred while retrieving the token' }); } } public async getIONBEServiceToken(): Promise<{ token_type: string, access_token: string }> { try { await this.mutex.acquire(); if (!this.token || this.isTokenExpired(this.token)) { try { this.token = await this.loadIONBEServiceToken(); } catch (err) { console.error('[Ion Service]: Error authentication=', err); this.token = null; } } return this.token; } catch (err) { throw err; } finally { await this.mutex.release(); } } public isTokenExpired(token: any): boolean { const decodedToken: any = jwt.decode(this.formatToken(token), { complete: true }); if (!decodedToken?.payload) { if (+token?.expireTime > 0) { return Date.now() >= +token.expireTime; } return true; } return Date.now() >= +(decodedToken?.payload?.exp) * 1000; } public formatAuthToken(tokenObj: any): string { if (tokenObj.token_type && tokenObj.access_token) { return tokenObj.token_type + ' ' + tokenObj.access_token; } return tokenObj; } public formatToken(tokenObj: any): string { if (tokenObj.token_type && tokenObj.access_token) { return tokenObj.access_token; } return tokenObj; } public async loadIONBEServiceToken(): Promise<any> { console.log('[Ion Service]: Loading ION Token'); const ci = process.env.ci; const cs = process.env.cs; const combine = ci + ":" + cs; const cicsbase64 = base64.encode(`${combine}`); const saak = encodeURIComponent(process.env.saak); const sask = encodeURIComponent(process.env.sask); const url = new URL(process.env.pu); const hostname = url.hostname; const port = (url.host.split(':').length > 1) ? +url.host.split(':')[1] : 443; const path = url.pathname + process.env.ot; const options1 = { method: 'POST', hostname, port, path, headers: { 'Cache-Control': 'no-cache', 'Authorization': `Basic ${cicsbase64}`, 'Content-Type': 'application/x-www-form-urlencoded' }, form: false, data: `grant_type=password&username=${saak}&password=${sask}`, rejectUnauthorized: false }; const response = await this.httpAPI.executeRequest(options1); const body = response?.body || {}; body.expireTime = Date.now() + ((~~response?.body?.expires_in - this.deltaTime) * 1000); return response?.body; } }