UNPKG

@app-connect/core

Version:
981 lines (972 loc) 94.2 kB
const express = require('express'); const cors = require('cors') const bodyParser = require('body-parser'); const dynamoose = require('dynamoose'); const axios = require('axios'); const { UserModel } = require('./models/userModel'); const { CallDownListModel } = require('./models/callDownListModel'); const { Op } = require('sequelize'); const { CallLogModel } = require('./models/callLogModel'); const { MessageLogModel } = require('./models/messageLogModel'); const { AdminConfigModel } = require('./models/adminConfigModel'); const { CacheModel } = require('./models/cacheModel'); const jwt = require('./lib/jwt'); const logCore = require('./handlers/log'); const contactCore = require('./handlers/contact'); const authCore = require('./handlers/auth'); const adminCore = require('./handlers/admin'); const userCore = require('./handlers/user'); const dispositionCore = require('./handlers/disposition'); const mock = require('./connector/mock'); const proxyConnector = require('./connector/proxy'); const releaseNotes = require('./releaseNotes.json'); const analytics = require('./lib/analytics'); const util = require('./lib/util'); const connectorRegistry = require('./connector/registry'); const calldown = require('./handlers/calldown'); const { DebugTracer } = require('./lib/debugTracer'); const s3ErrorLogReport = require('./lib/s3ErrorLogReport'); let packageJson = null; try { packageJson = require('./package.json'); } catch (e) { packageJson = require('../package.json'); } // For using dynamodb in local env if (process.env.DYNAMODB_LOCALHOST) { dynamoose.aws.ddb.local(process.env.DYNAMODB_LOCALHOST); } axios.defaults.headers.common['Unified-CRM-Extension-Version'] = packageJson.version; async function initDB() { if (!process.env.DISABLE_SYNC_DB_TABLE) { console.log('creating db tables if not exist...'); await UserModel.sync(); await CallLogModel.sync(); await MessageLogModel.sync(); await AdminConfigModel.sync(); await CacheModel.sync(); await CallDownListModel.sync(); } } function getAnalyticsVariablesInReqHeaders({ headers }) { const hashedExtensionId = headers['rc-extension-id']; const hashedAccountId = headers['rc-account-id']; const ip = headers['x-forwarded-for']?.split(',')?.find(i => !i.startsWith('10.')); const userAgent = headers['user-agent']; const author = headers['developer-author-name']; const eventAddedVia = headers['eventAddedVia']; return { hashedAccountId, hashedExtensionId, ip, userAgent, author, eventAddedVia } } // Create a router with all core routes function createCoreRouter() { const router = express.Router(); // Move all app.get, app.post, etc. to router.get, router.post, etc. router.get('/releaseNotes', async function (req, res) { const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('releaseNotes:start', { query: req.query }); const globalReleaseNotes = releaseNotes; const connectorReleaseNotes = connectorRegistry.getReleaseNotes(); const mergedReleaseNotes = {}; const versions = Object.keys(connectorReleaseNotes); for (const version of versions) { mergedReleaseNotes[version] = { global: globalReleaseNotes[version]?.global ?? {}, ...connectorReleaseNotes[version] ?? {} }; } res.json(tracer ? tracer.wrapResponse(mergedReleaseNotes ?? {}) : (mergedReleaseNotes ?? {})); }); // Obsolete router.get('/crmManifest', (req, res) => { try { const platformName = req.query.platformName || 'default'; const crmManifest = connectorRegistry.getManifest(platformName); if (crmManifest) { // Override app server url for local development if (process.env.OVERRIDE_APP_SERVER) { crmManifest.serverUrl = process.env.OVERRIDE_APP_SERVER; } // Override server side logging server url for local development if (process.env.OVERRIDE_SERVER_SIDE_LOGGING_SERVER && crmManifest.platforms) { Object.keys(crmManifest.platforms).forEach(platformName => { const platform = crmManifest.platforms[platformName]; if (platform.serverSideLogging) { platform.serverSideLogging.url = process.env.OVERRIDE_SERVER_SIDE_LOGGING_SERVER; } }); } if (!crmManifest.author?.name) { throw 'author name is required'; } res.json(crmManifest); } else { res.status(400).send('Platform not found'); } } catch (e) { res.status(400).send('Platform not found'); } }); router.get('/isAlive', (req, res) => { res.send(`OK`); }); router.get('/implementedInterfaces', (req, res) => { const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('implementedInterfaces:start', { query: req.query }); try { const platform = req.query.platform; if (platform) { const platformModule = connectorRegistry.getConnector(platform); const result = {}; const authType = platformModule.getAuthType(); result.getAuthType = !!platformModule.getAuthType; switch (authType) { case 'oauth': result.getOauthInfo = !!platformModule.getOauthInfo; break; case 'apiKey': result.getBasicAuth = !!platformModule.getBasicAuth; break; } result.getUserInfo = !!platformModule.getUserInfo; result.createCallLog = !!platformModule.createCallLog; result.updateCallLog = !!platformModule.updateCallLog; result.getCallLog = !!platformModule.getCallLog; result.createMessageLog = !!platformModule.createMessageLog; result.updateMessageLog = !!platformModule.updateMessageLog; result.createContact = !!platformModule.createContact; result.findContact = !!platformModule.findContact; result.unAuthorize = !!platformModule.unAuthorize; result.upsertCallDisposition = !!platformModule.upsertCallDisposition; result.findContactWithName = !!platformModule.findContactWithName; result.getUserList = !!platformModule.getUserList; result.getLicenseStatus = !!platformModule.getLicenseStatus; result.getLogFormatType = !!platformModule.getLogFormatType; result.cacheCallNote = !!process.env.USE_CACHE; res.status(200).send(tracer ? tracer.wrapResponse({ result }) : { result }); } else { tracer?.trace('implementedInterfaces:noPlatform', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please provide platform.' }) : { error: 'Please provide platform.' }); return; } } catch (e) { tracer?.traceError('implementedInterfaces:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } }); router.get('/licenseStatus', async (req, res) => { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('licenseStatus:start', { query: req.query }); let platformName = null; let success = false; let extraData = {}; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const { id: userId, platform } = jwt.decodeJwt(jwtToken); platformName = platform; if (!userId) { tracer?.trace('licenseStatus:noUserId', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'No user ID' }) : { error: 'No user ID' }); success = true; } const licenseStatus = await authCore.getLicenseStatus({ userId, platform }); res.status(200).send(tracer ? tracer.wrapResponse({ licenseStatus }) : { licenseStatus }); success = true; } else { res.status(200).send(tracer ? tracer.wrapResponse({ isLicenseValid: false, licenseStatus: 'Invalid (Invalid user session)', licenseStatusDescription: '' }) : { isLicenseValid: false, licenseStatus: 'Invalid (Invalid user session)', licenseStatusDescription: '' }); success = true; } } catch (e) { res.status(200).send(tracer ? tracer.wrapResponse({ isLicenseValid: false, licenseStatus: 'Invalid (Connect to get license status)', licenseStatusDescription: '' }) : { isLicenseValid: false, licenseStatus: 'Invalid (Connect to get license status)', licenseStatusDescription: '' }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Check license status', interfaceName: 'checkLicenseStatus', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, extras: { ...extraData }, eventAddedVia }); }); router.get('/authValidation', async (req, res) => { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('authValidation:start', { query: req.query }); let platformName = null; let success = false; let validationPass = false; let reason = ''; let statusCode = 200; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const decodedToken = jwt.decodeJwt(jwtToken); if (!decodedToken) { tracer?.trace('authValidation:invalidJwtToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Invalid JWT token' }) : { error: 'Invalid JWT token' }); return; } const { id: userId, platform } = decodedToken; platformName = platform; const { successful, returnMessage, failReason, status } = await authCore.authValidation({ platform, userId }); success = true; validationPass = successful; reason = failReason; statusCode = status; res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage }); } else { tracer?.trace('authValidation:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('authValidation:error', e); statusCode = e.response?.status ?? 'unknown'; res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Auth validation', interfaceName: 'authValidation', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, extras: { validationPass, reason, statusCode }, eventAddedVia }); }); // Obsolete router.get('/serverVersionInfo', (req, res) => { const defaultCrmManifest = connectorRegistry.getManifest('default'); res.send({ version: defaultCrmManifest?.version ?? 'unknown' }); }); router.post('/admin/settings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('setAdminSettings:start', { body: req.body }); let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken }); const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY); if (isValidated) { await adminCore.upsertAdminSettings({ hashedRcAccountId, adminSettings: req.body.adminSettings }); res.status(200).send(tracer ? tracer.wrapResponse({ message: 'Admin settings updated' }) : { message: 'Admin settings updated' }); success = true; } else { tracer?.trace('setAdminSettings:adminValidationFailed', {}); res.status(401).send(tracer ? tracer.wrapResponse({ error: 'Admin validation failed' }) : { error: 'Admin validation failed' }); success = false; } } catch (e) { console.log(`${e.stack}`); tracer?.traceError('setAdminSettings:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Set admin settings', interfaceName: 'setAdminSettings', accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.get('/admin/settings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('getAdminSettings:start', { query: req.query }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); platformName = unAuthData?.platform ?? 'Unknown'; const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('getAdminSettings:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken }); const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY); if (isValidated) { const adminSettings = await adminCore.getAdminSettings({ hashedRcAccountId }); if (adminSettings) { res.status(200).send(tracer ? tracer.wrapResponse({ adminSettings }) : { adminSettings }); } else { res.status(200).send(tracer ? tracer.wrapResponse({ customConnector: null, userSettings: {} }) : { customConnector: null, userSettings: {} }); } success = true; } else { tracer?.trace('getAdminSettings:adminValidationFailed', {}); res.status(401).send(tracer ? tracer.wrapResponse({ error: 'Admin validation failed' }) : { error: 'Admin validation failed' }); success = true; } } else { tracer?.trace('getAdminSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`${e.stack}`); tracer?.traceError('getAdminSettings:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Get admin settings', interfaceName: 'getAdminSettings', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.post('/admin/userMapping', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('getUserMapping:start', { query: req.query }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); platformName = unAuthData?.platform ?? 'Unknown'; const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('getUserMapping:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken }); const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY); if (isValidated) { const userMapping = await adminCore.getUserMapping({ user, hashedRcAccountId, rcExtensionList: req.body.rcExtensionList }); res.status(200).send(tracer ? tracer.wrapResponse({ userMapping }) : { userMapping }); success = true; } else { tracer?.trace('getUserMapping:adminValidationFailed', {}); res.status(401).send(tracer ? tracer.wrapResponse({ error: 'Admin validation failed' }) : { error: 'Admin validation failed' }); success = true; } } else { tracer?.trace('getUserMapping:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`${e.stack}`); tracer?.traceError('getUserMapping:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Get user mapping', interfaceName: 'getUserMapping', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.get('/admin/serverLoggingSettings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('getServerLoggingSettings:start', { query: req.query }); let platformName = null; let success = false; const jwtToken = req.query.jwtToken; if (!jwtToken) { tracer?.trace('getServerLoggingSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); return; } const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const unAuthData = jwt.decodeJwt(jwtToken); if (!unAuthData?.id) { tracer?.trace('getServerLoggingSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); return; } platformName = unAuthData?.platform ?? 'Unknown'; const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('getServerLoggingSettings:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const serverLoggingSettings = await adminCore.getServerLoggingSettings({ user }); res.status(200).send(tracer ? tracer.wrapResponse({ serverLoggingSettings }) : { serverLoggingSettings }); success = true; } catch (e) { console.log(`${e.stack}`); tracer?.traceError('getServerLoggingSettings:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Get server logging settings', interfaceName: 'getServerLoggingSettings', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.post('/admin/serverLoggingSettings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('setServerLoggingSettings:start', { body: req.body }); let platformName = null; let success = false; const jwtToken = req.query.jwtToken; if (!jwtToken) { tracer?.trace('setServerLoggingSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); return; } if (!req.body.additionalFieldValues) { tracer?.trace('setServerLoggingSettings:missingAdditionalFieldValues', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Missing additionalFieldValues' }) : { error: 'Missing additionalFieldValues' }); return; } const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const unAuthData = jwt.decodeJwt(jwtToken); if (!unAuthData?.id) { tracer?.trace('setServerLoggingSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); return; } platformName = unAuthData?.platform ?? 'Unknown'; const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('setServerLoggingSettings:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const { successful, returnMessage } = await adminCore.updateServerLoggingSettings({ user, additionalFieldValues: req.body.additionalFieldValues }); res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage }); success = true; } catch (e) { console.log(`${e.stack}`); tracer?.traceError('setServerLoggingSettings:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } }) : { successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Set server logging settings', interfaceName: 'setServerLoggingSettings', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }) router.get('/user/preloadSettings', async function (req, res) { const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('getUserSettingsByAdmin:start', { query: req.query }); try { const rcAccessToken = req.query.rcAccessToken; const rcAccountId = req.query.rcAccountId; if (rcAccessToken || rcAccountId) { const userSettings = await userCore.getUserSettingsByAdmin({ rcAccessToken, rcAccountId }); res.status(200).send(tracer ? tracer.wrapResponse({ userSettings }) : { userSettings }); } else { tracer?.trace('getUserSettingsByAdmin:noRcAccessTokenOrRcAccountId', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Cannot find rc user login' }) : { error: 'Cannot find rc user login' }); } } catch (e) { console.log(`${e.stack}`); tracer?.traceError('getUserSettingsByAdmin:error', e); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } } ); router.get('/user/settings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('getUserSettings:start', { query: req.query }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); platformName = unAuthData?.platform ?? 'Unknown'; const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('getUserSettings:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } else { const rcAccessToken = req.query.rcAccessToken; const rcAccountId = req.query.rcAccountId; const userSettings = await userCore.getUserSettings({ user, rcAccessToken, rcAccountId }); success = true; res.status(200).send(tracer ? tracer.wrapResponse({ userSettings }) : { userSettings }); } } else { success = false; tracer?.trace('getUserSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('getUserSettings:error', e, { platform: platformName }); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Get user settings', interfaceName: 'getUserSettings', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.post('/user/settings', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('setUserSettings:start', { body: req.body }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); platformName = unAuthData?.platform; if (!platformName) { tracer?.trace('setUserSettings:unknownPlatform', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Unknown platform' }) : { error: 'Unknown platform' }); return; } const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('setUserSettings:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const { userSettings } = await userCore.updateUserSettings({ user, userSettings: req.body.userSettings, platformName }); res.status(200).send(tracer ? tracer.wrapResponse({ userSettings }) : { userSettings }); success = true; } else { tracer?.trace('setUserSettings:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('setUserSettings:error', e, { platform: platformName }); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Set user settings', interfaceName: 'setUserSettings', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.get('/hostname', async function (req, res) { const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('hostname:start', { query: req.query }); try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); const user = await UserModel.findByPk(unAuthData?.id); if (!user) { tracer?.trace('hostname:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } res.status(200).send(tracer ? tracer.wrapResponse({ hostname: user.hostname }) : { hostname: user.hostname }); } else { tracer?.trace('hostname:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); } } catch (e) { console.log(`${e.stack}`); tracer?.traceError('hostname:error', e); res.status(500).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); } }) router.get('/oauth-callback', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('oauth-callback:start', { query: req.query }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { if (!req.query?.callbackUri || req.query.callbackUri === 'undefined') { tracer?.trace('oauth-callback:missingCallbackUri', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Missing callbackUri' }) : { error: 'Missing callbackUri' }); return; } platformName = req.query.state ? req.query.state.split('platform=')[1] : decodeURIComponent(req.originalUrl).split('state=')[1].split('&')[0].split('platform=')[1]; const hostname = req.query.hostname; const tokenUrl = req.query.tokenUrl; if (!platformName) { tracer?.trace('oauth-callback:missingPlatformName', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Missing platform name' }) : { error: 'Missing platform name' }); return; } const hasAuthCodeInCallbackUri = req.query.callbackUri.includes('code='); if (!hasAuthCodeInCallbackUri) { // eslint-disable-next-line no-param-reassign req.query.callbackUri = `${req.query.callbackUri}&code=${req.query.code}`; } const { userInfo, returnMessage } = await authCore.onOAuthCallback({ platform: platformName, hostname, tokenUrl, callbackUri: req.query.callbackUri, apiUrl: req.query.apiUrl, username: req.query.username, query: req.query, proxyId: req.query.proxyId }); if (userInfo) { const jwtToken = jwt.generateJwt({ id: userInfo.id.toString(), platform: platformName }); res.status(200).send(tracer ? tracer.wrapResponse({ jwtToken, name: userInfo.name, returnMessage }) : { jwtToken, name: userInfo.name, returnMessage }); success = true; } else { res.status(200).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('oauth-callback:error', e, { platform: platformName }); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'OAuth Callback', interfaceName: 'onOAuthCallback', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }) router.post('/apiKeyLogin', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('apiKeyLogin:start', { body: req.body }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const platform = req.body.platform; platformName = platform; const apiKey = req.body.apiKey; const hostname = req.body.hostname; const proxyId = req.body.proxyId; const additionalInfo = req.body.additionalInfo; if (!platform) { tracer?.trace('apiKeyLogin:missingPlatform', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Missing platform name' }) : { error: 'Missing platform name' }); return; } if (!apiKey) { tracer?.trace('apiKeyLogin:missingApiKey', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Missing api key' }) : { error: 'Missing api key' }); return; } const { userInfo, returnMessage } = await authCore.onApiKeyLogin({ platform, hostname, apiKey, proxyId, additionalInfo }); if (userInfo) { const jwtToken = jwt.generateJwt({ id: userInfo.id.toString(), platform: platform }); res.status(200).send(tracer ? tracer.wrapResponse({ jwtToken, name: userInfo.name, returnMessage }) : { jwtToken, name: userInfo.name, returnMessage }); success = true; } else { res.status(400).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('apiKeyLogin:error', e, { platform: platformName }); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'API Key Login', interfaceName: 'onApiKeyLogin', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }) router.post('/unAuthorize', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('unAuthorize:start', { query: req.query }); let platformName = null; let success = false; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const unAuthData = jwt.decodeJwt(jwtToken); platformName = unAuthData?.platform ?? 'Unknown'; const userToLogout = await UserModel.findByPk(unAuthData?.id); if (!userToLogout) { tracer?.trace('unAuthorize:userNotFound', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'User not found' }) : { error: 'User not found' }); return; } const platformModule = connectorRegistry.getConnector(unAuthData?.platform ?? 'Unknown'); const { returnMessage } = await platformModule.unAuthorize({ user: userToLogout }); res.status(200).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage }); success = true; } else { tracer?.trace('unAuthorize:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('unAuthorize:error', e, { platform: platformName }); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Unauthorize', interfaceName: 'unAuthorize', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId, success, requestDuration: (requestEndTime - requestStartTime) / 1000, userAgent, ip, author, eventAddedVia }); }); router.get('/userInfoHash', async function (req, res) { const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; try { tracer?.trace('userInfoHash:start', { query: req.query }); const extensionId = util.getHashValue(req.query.extensionId, process.env.HASH_KEY); const accountId = util.getHashValue(req.query.accountId, process.env.HASH_KEY); res.status(200).send(tracer ? tracer.wrapResponse({ extensionId, accountId }) : { extensionId, accountId }); } catch (e) { console.log(`${e.stack}`); res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); tracer?.traceError('userInfoHash:error', e); } }) router.get('/contact', async function (req, res) { const requestStartTime = new Date().getTime(); const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null; tracer?.trace('findContact:start', { query: req.query }); let platformName = null; let success = false; let resultCount = 0; let extraData = {}; const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers }) try { const jwtToken = req.query.jwtToken; if (jwtToken) { const decodedToken = jwt.decodeJwt(jwtToken); tracer?.trace('findContact:jwtDecoded', { decodedToken }); if (!decodedToken) { tracer?.trace('findContact:invalidToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); return; } const { id: userId, platform } = decodedToken; platformName = platform; const { successful, returnMessage, contact, extraDataTracking } = await contactCore.findContact({ platform, userId, phoneNumber: req.query.phoneNumber.replace(' ', '+'), overridingFormat: req.query.overridingFormat, isExtension: req.query?.isExtension ?? false, tracer }); tracer?.trace('findContact:result', { successful, returnMessage, contact }); res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, contact }) : { successful, returnMessage, contact }); if (successful) { const nonNewContact = contact?.filter(c => !c.isNewContact) ?? []; resultCount = nonNewContact.length; } success = successful; if (extraDataTracking) { extraData = extraDataTracking; } } else { tracer?.trace('findContact:noToken', {}); res.status(400).send(tracer ? tracer.wrapResponse({ error: 'Please go to Settings and authorize CRM platform' }) : { error: 'Please go to Settings and authorize CRM platform' }); success = false; } } catch (e) { console.log(`platform: ${platformName} \n${e.stack}`); tracer?.traceError('findContact:error', e, { platform: platformName }); extraData.statusCode = e.response?.status ?? 'unknown'; res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e }); success = false; } const requestEndTime = new Date().getTime(); analytics.track({ eventName: 'Find contact', interfaceName: 'findContact', connectorName: platformName, accountId: hashedAccountId, extensionId: hashedExtensionId,