@3kles/3kles-coreion
Version:
3Kles Generic Ion Service
146 lines (129 loc) • 5.32 kB
text/typescript
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;
}
}