UNPKG

pink-bears

Version:

Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications

402 lines (374 loc) 11.1 kB
const { Storage, Fetch, File, Next, Batch, Status, Email, Schedule, Iparams, Webhook, Redis, } = require("../sparrowapps-message-dispatcher/index.js"); const $Status = new Status(); const axios = require('axios'); const { setContext} = require('../sparrowapps-message-dispatcher/context.js'); class App { constructor( sparrowAppsDomain, authToken, iframeUrl, productId, traceId, appVersion, userInstalledId, accountId, userId, appId ) { this.sparrowAppsDomain = sparrowAppsDomain; this.authToken = authToken; this.iframeUrl = iframeUrl; this.productId = productId; this.traceId = traceId; this.appVersion = appVersion; this.appId = appId; this.userInstalledId = userInstalledId; this.accountId = accountId; this.userId = userId; } initiateInstanceObject(InstanceClass, constructorKeys) { const client = {}; const instanceObject = new InstanceClass(); Object.getOwnPropertyNames(instanceObject).forEach((key) => { if (typeof instanceObject[key] === "function" && key !== "constructor") { client[key] = (...args) => { const constructorArgs = constructorKeys.map( (cKey) => this[cKey] || cKey ); return new InstanceClass(...constructorArgs)[key](...args); }; } }); Object.getOwnPropertyNames(InstanceClass.prototype).forEach((key) => { if ( typeof InstanceClass.prototype[key] === "function" && key !== "constructor" ) { client[key] = (...args) => { const constructorArgs = constructorKeys.map( (cKey) => this[cKey] || cKey ); return new InstanceClass(...constructorArgs)[key](...args); }; } }); return client; } getFetch() { return this.initiateInstanceObject(Fetch, [ "sparrowAppsDomain", "authToken", "iframeUrl", "productId", "userId", ]); } getFile() { return this.initiateInstanceObject(File, [process.env.bucketName]); } getEmail() { return this.initiateInstanceObject(Email, [ "sparrowAppsDomain", "authToken", "userId", ]); } getSchedule() { return this.initiateInstanceObject(Schedule, [ "sparrowAppsDomain", "authToken", "iframeUrl", "productId", "traceId", "appVersion", "userInstalledId", "accountId", "userId", ]); } getNext() { return this.initiateInstanceObject(Next, [process.env.rabbitMQurl]); } getStorage() { return this.initiateInstanceObject(Storage, [ "accountId", "productId", "appId", "sparrowAppsDomain", "userId", ]); } getIparams() { return this.initiateInstanceObject(Iparams, [ "accountId", "productId", "appId", "sparrowAppsDomain", "userId", ]); } getWebhook() { return this.initiateInstanceObject(Webhook, [ "sparrowAppsDomain", "authToken", "productId", "traceId", "userInstalledId", "accountId", "userId", ]); } getRedis() { console.log(`Inside getRedis() index`); return this.initiateInstanceObject(Redis, [ "accountId", "productId", "appId", "sparrowAppsDomain", "traceId", "userInstalledId", "authToken", "userId", ]); } getBatch() { return new Batch(); } } const app = new App(); exports.initHandlers = () => { return { $Fetch: app.getFetch(), $File: app.getFile(), $Email: app.getEmail(), $Schedule: app.getSchedule(), $Next: app.getNext(), $Storage: app.getStorage(), $Batch: app.getBatch(), $Iparams: app.getIparams(), $Status, $Webhook: app.getWebhook(), $Redis: app.getRedis() }; }; const decodeJwt = (token) => { try { const [header, payload, signature] = token.split('.'); const decodedHeader = Buffer.from(header, 'base64').toString('utf-8'); const decodedPayload = Buffer.from(payload, 'base64').toString('utf-8'); return { header: JSON.parse(decodedHeader), payload: JSON.parse(decodedPayload), signature, }; } catch (error) { console.error('Error decoding the JWT:', error.message); return null; } }; const isTokenExpired = (decodedToken) => { if (!decodedToken || !decodedToken.payload || !decodedToken.payload.exp) { return false; // Token is considered not expired if there's no expiration claim } const expirationTime = decodedToken.payload.exp * 1000; // Convert seconds to milliseconds return expirationTime < Date.now(); }; exports.handler = async (event, context) => { setContext(context); if ( event?.path?.split("/")?.[event?.path.split("/").length - 1] === "testing" ) { return { statusCode: 200, body: JSON.stringify({ message: "success", }), }; } let parentLayer; if (!event.body) { parentLayer = event; } else { parentLayer = event.body && JSON.parse(event.body); } try { if (event) { const eventPayloadConfig = parentLayer?.appConfig?.extraPayload?.parentLayerConfigObject; const { appId, userInstalledId } = eventPayloadConfig; const consoleMethods = ["log", "info", "error", "warn"]; consoleMethods.forEach((method) => { if (!console[`old${method}`]) { console[`old${method}`] = console[method]; } console[method] = function (...args) { const forbiddenWords = args.filter((str) => { if (typeof str == "string") { return str.includes(process.env.rabbitMQurl); } return; }); let message = "SparrowApps---AppId---" + appId + "---UserInstalledId---" + userInstalledId + "---TraceId---" + parentLayer.traceId + " "; if (forbiddenWords.length) { message += `print statement forbidden`; } else { message += `${args.join(" ")}`; } console[`old${method}`](message); }; }); app.accountId = eventPayloadConfig.accountId; app.appVersion = eventPayloadConfig.appVersion; app.authToken = eventPayloadConfig.authToken; app.iframeUrl = eventPayloadConfig.iframeUrl; app.productId = eventPayloadConfig.productId; app.sparrowAppsDomain = eventPayloadConfig.sparrowAppsDomain; app.traceId = parentLayer.traceId; app.userInstalledId = eventPayloadConfig.userInstalledId; app.userId = eventPayloadConfig.userId; app.appId = eventPayloadConfig.appId; const expired = isTokenExpired(decodeJwt(eventPayloadConfig.authToken)); if (expired) { try { const response = await axios.post( `${eventPayloadConfig.sparrowAppsDomain}/api/authenticate`, { productKey: eventPayloadConfig.userId, productId: eventPayloadConfig.productId, }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.productToken}` }, } ); app.authToken = response.data.Access_Token; } catch (error) { console.error('Error:', error.message); throw error; } } const appName = eventPayloadConfig.appName?.toLowerCase(); const fileName = `./${appName}/server.js`; const appServer = require(fileName); let eventPayload; const isBackendEvent = [ "onSubmissionComplete", "onContactCreate", "onContactUpdate", "onContactDelete", "onTicketCommentCreate", "onTicketCreate", "onTicketUpdate", "onTicketDelete", "onWidgetCreate", "onWidgetUpdate", "onWidgetDelete", "onDashboardCreate", "onDashboardUpdate", "onDashboardDelete", "onReputationReviewCreate", "onReputationAppPlatformCreate", "onEmployeeCreate", "onContactListCreate", "onContactListDelete", "onContactListUpdate", "onQuestionCreate", "onQuestionUpdate", "onQuestionDelete", "onQuestionTypeChanged", "onSectionCreate", "onSectionUpdate", "onSectionDelete", "onChannelCreate", "onChannelUpdate", "onChannelDelete", "onCXChannelCreate", "onCXChannelUpdate", "onCXChannelDelete", "onSurveyCreate", "onSurveyEdit", "onSurveyDelete", "onSurveyMove", "onSurveyClose", "onSurveyRestore", "onSurveyDuplicate", "onSubmissionCreate", "onSubmissionUpdate", "onSubmissionDelete", "onAppInstall", "onAppUninstall", "onExternalEvent", "onIndividualExternalEvent" ].includes(eventPayloadConfig.event) if (isBackendEvent) { eventPayload = parentLayer.payload; } else { eventPayload = { data: parentLayer.payload, iparams: eventPayloadConfig.iparams, }; } const message = { 200: "Success", 401: "UnAuthorized", 500: "Something went wrong", }; const data1 = await appServer[eventPayloadConfig.event]( eventPayload, parentLayer ); if (isBackendEvent) { return { statusCode: 200, body: JSON.stringify({ data: data1 || {}, }), }; } const data = { statusCode: data1?.status || 200, body: JSON.stringify({ data: data1?.data, message: data1?.status ? message[data1.status] : "", }), }; return data; } return { statusCode: 500, body: JSON.stringify({ data: { message: "something went wrong" }, }), }; } catch (error) { const data = { statusCode: 500, body: JSON.stringify({ error, }), }; await $Status.changeStatus(JSON.stringify(error), parentLayer.traceId); return data; } };