UNPKG

sdk-node-apis-efi

Version:

Module for integration with Efi Bank API

272 lines (233 loc) 8.54 kB
// @ts-nocheck import fs from 'fs' import https from 'https' import sdkPackage from '../../package.json' import axios from 'axios' import randomstring from 'randomstring' class Endpoints { constructor(options, constants) { this.options = options this.auth = null this.constants = constants this.authError = null this.axiosInstance = axios.create() } run(name, params, body) { let endpoint if (this.constants.APIS.DEFAULT.ENDPOINTS.hasOwnProperty(name)) { endpoint = this.constants.APIS.DEFAULT.ENDPOINTS[name] this.baseUrl = this.options.sandbox ? this.constants.APIS.DEFAULT.URL.SANDBOX : this.constants.APIS.DEFAULT.URL.PRODUCTION this.authRoute = this.constants.APIS.DEFAULT.ENDPOINTS.authorize } else { Object.keys(this.constants.APIS).forEach((key) => { if (this.constants.APIS[key].ENDPOINTS.hasOwnProperty(name)) { endpoint = this.constants.APIS[key].ENDPOINTS[name] this.baseUrl = this.options.sandbox ? this.constants.APIS[key].URL.SANDBOX : this.constants.APIS[key].URL.PRODUCTION this.authRoute = this.constants.APIS[key].ENDPOINTS.authorize return } }) try { if (this.options.cert_base64 === undefined || this.options.cert_base64 === false) { if (this.options.pemKey) { this.agent = new https.Agent({ cert: fs.readFileSync(this.options.certificate), key: fs.readFileSync(this.options.pemKey), passphrase: '', }) } else { this.agent = new https.Agent({ pfx: fs.readFileSync(this.options.certificate), passphrase: '', }) } } else if (this.options.cert_base64 === true) { if (this.options.pemKey) { this.agent = new https.Agent({ cert: Buffer.from(this.options.certificate, 'base64'), key: Buffer.from(this.options.pemKey, 'base64'), passphrase: '', }) } else { this.agent = new https.Agent({ pfx: Buffer.from(this.options.certificate, 'base64'), passphrase: '', }) } } } catch (error) { if (this.options.pemKey && (this.options.cert_base64 === undefined || this.options.cert_base64 === false)) { console.error(`Falha ao ler o certificado ou a chave, verifique o caminho informado:\nCaminho do certificado: ${this.options.certificate}\nCaminho da chave: ${this.options.pemKey}`); } else if (this.options.cert_base64 === undefined || this.options.cert_base64 === false) { console.error(`Falha ao ler o certificado, verifique o caminho informado: ${this.options.certificate}`); } if (this.options.pemKey && this.options.cert_base64 === true) { console.error(`Falha ao ler o certificado ou a chave, verifique o conteúdo informado do certificado e da chave`); } else if (this.options.cert_base64 === true) { console.error(`Falha ao ler o certificado, verifique o conteúdo informado`); } } } this.params = params return this.req(endpoint, body) } async req(endpoint, body) { let req = await this.createRequest(endpoint, body) // Request interceptor this.axiosInstance.interceptors.request.use( async (config) => { if (!this.auth || this.isExpired()) { this.authError = await this.authenticate() } config.headers = { Authorization: `Bearer ${this.auth.access_token}`, 'x-skip-mtls-checking': !this.options.validateMtls } if (this.options.partner_token) { config.headers['partner-token'] = this.options.partner_token } if (this.baseUrl == this.constants.APIS.OPENFINANCE.URL.PRODUCTION || this.baseUrl == this.constants.APIS.OPENFINANCE.URL.SANDBOX) { config.headers['x-idempotency-key'] = randomstring.generate({ length: 72, charset: 'alphanumeric' }) } return config }, (error) => { Promise.reject(error) }, ) return this.axiosInstance(req) .then((res) => { return res.data }) .catch((error) => { if (this.authError) { const error = this.authError?.response?.data || this.authError?.cause || this.authError; switch (error.message) { case 'socket hang up': throw 'Verifique o atributo sandbox e certificate, e garanta que eles estejam corretamente atribuidos para o ambiente desejado' case 'header too long': throw 'Verifique se o certificado foi enviado no formato correto' case 'wrong tag': case 'error:0909006C:PEM routines:get_name:no start line': throw 'Foi enviando um certificado .pem porém não foi enviado o atributo pemKey corretamente, tente enviar o mesmo valor para ambos' default: throw error } } else { switch (this.baseUrl) { case this.constants.APIS.DEFAULT.URL.PRODUCTION: case this.constants.APIS.DEFAULT.URL.SANDBOX: throw error.response.data case this.constants.APIS.PIX.URL.PRODUCTION: case this.constants.APIS.PIX.URL.SANDBOX: throw error.response.data case this.constants.APIS.OPENFINANCE.URL.PRODUCTION: case this.constants.APIS.OPENFINANCE.URL.SANDBOX: throw error.response.data case this.constants.APIS.PAGAMENTOS.URL.PRODUCTION: case this.constants.APIS.PAGAMENTOS.URL.SANDBOX: throw error.response.data case this.constants.APIS.CONTAS.URL.PRODUCTION: case this.constants.APIS.CONTAS.URL.SANDBOX: throw error.response.data default: throw error.response.data } } }) } isExpired() { if (!this.options.cache) { return true } let current_time = new Date().getTime() / 1000 if (current_time > this.auth.authDate + this.auth.expires_in) { return true } return false } async authenticate() { let authParams = { method: 'POST', url: this.baseUrl + this.authRoute.route, headers: { 'api-sdk': 'efi-node-' + sdkPackage.version, }, data: { grant_type: 'client_credentials', }, } if (this.constants.APIS.DEFAULT.URL.PRODUCTION == this.baseUrl || this.constants.APIS.DEFAULT.URL.SANDBOX == this.baseUrl) { authParams.auth = { username: this.options.client_id, password: this.options.client_secret, } } else { let token = Buffer.from(this.options.client_id + ':' + this.options.client_secret).toString('base64') authParams.headers['Authorization'] = 'Basic ' + token authParams.headers['Content-Type'] = 'application/json' authParams.httpsAgent = this.agent } return axios(authParams) .then((res) => { this.auth = res.data this.auth.authDate = new Date().getTime() / 1000 }) .catch((error) => { return error }) } async createRequest(endpoint, body) { let { route, method } = endpoint let regex = /\:(\w+)/g let query = '' let placeholders = route.match(regex) || [] let params = {} for (let prop in this.params) { params[prop] = this.params[prop] } let getVariables = function () { return placeholders.map(function (item) { return item.replace(':', '') }) } let updateRoute = function () { let variables = getVariables() variables.forEach(function (value, index) { if (params[value]) { route = route.replace(placeholders[index], params[value]) delete params[value] } }) } let getQueryString = function () { let keys = Object.keys(params) let initial = keys.length >= 1 ? '?' : '' return keys.reduce(function (previous, current, index, array) { let next = index === array.length - 1 ? '' : '&' return [previous, current, '=', params[current], next].join('') }, initial) } updateRoute() query = getQueryString() let headers = new Object() if (endpoint.route === this.constants.APIS.PIX.ENDPOINTS.pixConfigWebhook.route && endpoint.method === this.constants.APIS.PIX.ENDPOINTS.pixConfigWebhook.method) { this.options.validateMtls = this.options.validateMtls || this.options.validate_mtls headers['x-skip-mtls-checking'] = !this.options.validateMtls } if (this.options.partner_token) { headers['partner-token'] = this.options.partner_token } if (this.baseUrl == this.constants.APIS.OPENFINANCE.URL.PRODUCTION || this.baseUrl == this.constants.APIS.OPENFINANCE.URL.SANDBOX) { headers['x-idempotency-key'] = randomstring.generate({ length: 72, charset: 'alphanumeric' }) } let req = { method, url: String([this.baseUrl, route, query].join('')), headers, data: body, } if (this.baseUrl != this.constants.APIS.DEFAULT.URL.PRODUCTION && this.baseUrl != this.constants.APIS.DEFAULT.URL.SANDBOX) { req['httpsAgent'] = this.agent } return req } } export default Endpoints