@app-connect/core 1.7.20 → 1.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +8 -1
  2. package/connector/developerPortal.js +4 -4
  3. package/docs/README.md +50 -0
  4. package/docs/architecture.md +93 -0
  5. package/docs/connectors.md +117 -0
  6. package/docs/handlers.md +125 -0
  7. package/docs/libraries.md +101 -0
  8. package/docs/models.md +144 -0
  9. package/docs/routes.md +115 -0
  10. package/docs/tests.md +73 -0
  11. package/handlers/admin.js +22 -2
  12. package/handlers/auth.js +51 -10
  13. package/handlers/contact.js +7 -2
  14. package/handlers/log.js +4 -4
  15. package/handlers/managedAuth.js +446 -0
  16. package/index.js +263 -38
  17. package/lib/jwt.js +1 -1
  18. package/mcp/tools/createCallLog.js +5 -1
  19. package/mcp/tools/createContact.js +5 -1
  20. package/mcp/tools/createMessageLog.js +5 -1
  21. package/mcp/tools/findContactByName.js +5 -1
  22. package/mcp/tools/findContactByPhone.js +6 -2
  23. package/mcp/tools/getCallLog.js +5 -1
  24. package/mcp/tools/rcGetCallLogs.js +6 -2
  25. package/mcp/tools/updateCallLog.js +5 -1
  26. package/mcp/ui/App/lib/developerPortal.ts +1 -1
  27. package/package.json +1 -1
  28. package/releaseNotes.json +20 -0
  29. package/test/handlers/admin.test.js +34 -0
  30. package/test/handlers/auth.test.js +402 -6
  31. package/test/handlers/contact.test.js +162 -0
  32. package/test/handlers/managedAuth.test.js +458 -0
  33. package/test/index.test.js +105 -0
  34. package/test/lib/jwt.test.js +15 -0
  35. package/test/mcp/tools/createCallLog.test.js +11 -0
  36. package/test/mcp/tools/createContact.test.js +58 -0
  37. package/test/mcp/tools/createMessageLog.test.js +15 -0
  38. package/test/mcp/tools/findContactByName.test.js +12 -0
  39. package/test/mcp/tools/findContactByPhone.test.js +12 -0
  40. package/test/mcp/tools/getCallLog.test.js +12 -0
  41. package/test/mcp/tools/rcGetCallLogs.test.js +56 -0
  42. package/test/mcp/tools/updateCallLog.test.js +14 -0
  43. package/test/routes/managedAuthRoutes.test.js +132 -0
  44. package/test/setup.js +2 -0
package/index.js CHANGED
@@ -35,6 +35,7 @@ const s3ErrorLogReport = require('./lib/s3ErrorLogReport');
35
35
  const pluginCore = require('./handlers/plugin');
36
36
  const { handleDatabaseError } = require('./lib/errorHandler');
37
37
  const { updateAuthSession } = require('./lib/authSession');
38
+ const managedAuthCore = require('./handlers/managedAuth');
38
39
 
39
40
  let packageJson = null;
40
41
  try {
@@ -108,9 +109,79 @@ function getAnalyticsVariablesInReqHeaders({ headers }) {
108
109
  }
109
110
  }
110
111
 
112
+ const JWT_REFRESH_THRESHOLD_SECONDS = 7 * 24 * 60 * 60; // 1 week
113
+ const JWT_LEGACY_LONG_LIVED_THRESHOLD_SECONDS = 365 * 24 * 60 * 60; // 1 year
114
+
115
+ function getBearerTokenFromRequest(req) {
116
+ const authHeader = req.headers?.authorization || req.headers?.Authorization;
117
+ if (!authHeader || typeof authHeader !== 'string') {
118
+ return null;
119
+ }
120
+ const [scheme, token] = authHeader.split(' ');
121
+ if (!scheme || scheme.toLowerCase() !== 'bearer' || !token) {
122
+ return null;
123
+ }
124
+ return token;
125
+ }
126
+
127
+ function normalizeJwtFromRequest(req, res, next) {
128
+ if (req.path?.startsWith('/mcp')) {
129
+ return next();
130
+ }
131
+ const originalBearerToken = getBearerTokenFromRequest(req);
132
+ const queryToken = req.query?.jwtToken;
133
+ let bearerToken = originalBearerToken;
134
+
135
+ // Backward compatibility: promote query jwtToken to Authorization Bearer.
136
+ if (!bearerToken && queryToken) {
137
+ req.headers.authorization = `Bearer ${queryToken}`;
138
+ bearerToken = queryToken;
139
+ // Don't refresh JWT because old version cannot update its local token storage to support refreshed token.
140
+ return next();
141
+ }
142
+
143
+ const token = bearerToken;
144
+
145
+ if (!token) {
146
+ return next();
147
+ }
148
+
149
+ const decodedToken = jwt.decodeJwt(token);
150
+ if (!decodedToken?.id) {
151
+ req.invalidJwtToken = true;
152
+ if (req.query?.jwtToken) {
153
+ delete req.query.jwtToken;
154
+ }
155
+ return next();
156
+ }
157
+
158
+ req.jwtToken = token;
159
+ req.jwtAuth = decodedToken;
160
+
161
+ if (typeof decodedToken.exp === 'number') {
162
+ const now = Math.floor(Date.now() / 1000);
163
+ const timeLeft = decodedToken.exp - now;
164
+ const isBearerAuth = !!originalBearerToken;
165
+ const shouldRefreshNearExpiry = timeLeft <= JWT_REFRESH_THRESHOLD_SECONDS;
166
+ // Rotate legacy 120y tokens only for Bearer auth clients (they can persist refreshed headers).
167
+ const shouldRefreshLegacyLongLivedBearer = isBearerAuth && timeLeft > JWT_LEGACY_LONG_LIVED_THRESHOLD_SECONDS;
168
+ if (shouldRefreshNearExpiry || shouldRefreshLegacyLongLivedBearer) {
169
+ const refreshedToken = jwt.generateJwt({
170
+ id: decodedToken.id.toString(),
171
+ platform: decodedToken.platform
172
+ });
173
+ res.setHeader('x-refreshed-jwt-token', refreshedToken);
174
+ req.jwtToken = refreshedToken;
175
+ req.jwtAuth = jwt.decodeJwt(refreshedToken) || decodedToken;
176
+ }
177
+ }
178
+ return next();
179
+ }
180
+
111
181
  // Create a router with all core routes
112
182
  function createCoreRouter() {
113
183
  const router = express.Router();
184
+ router.use(normalizeJwtFromRequest);
114
185
 
115
186
  // Move all app.get, app.post, etc. to router.get, router.post, etc.
116
187
  router.get('/releaseNotes', async function (req, res) {
@@ -219,9 +290,16 @@ function createCoreRouter() {
219
290
  let extraData = {};
220
291
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
221
292
  try {
222
- const jwtToken = req.query.jwtToken;
293
+ const jwtToken = req.jwtToken || req.query.jwtToken;
223
294
  if (jwtToken) {
224
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
295
+ const decodedToken = jwt.decodeJwt(jwtToken);
296
+ if (!decodedToken) {
297
+ tracer?.trace('licenseStatus:invalidJwtToken', {});
298
+ res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
299
+ success = false;
300
+ return;
301
+ }
302
+ const { id: userId, platform } = decodedToken;
225
303
  platformName = platform;
226
304
  if (!userId) {
227
305
  tracer?.trace('licenseStatus:noUserId', {});
@@ -286,7 +364,7 @@ function createCoreRouter() {
286
364
  let statusCode = 200;
287
365
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
288
366
  try {
289
- const jwtToken = req.query.jwtToken;
367
+ const jwtToken = req.jwtToken || req.query.jwtToken;
290
368
  if (jwtToken) {
291
369
  const decodedToken = jwt.decodeJwt(jwtToken);
292
370
  if (!decodedToken) {
@@ -336,6 +414,36 @@ function createCoreRouter() {
336
414
  eventAddedVia
337
415
  });
338
416
  });
417
+ router.get('/apiKeyManagedAuthState', async function (req, res) {
418
+ const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
419
+ tracer?.trace('apiKeyManagedAuthState:start', { query: req.query });
420
+ try {
421
+ const platform = req.query.platform;
422
+ const rcAccessToken = req.query.rcAccessToken;
423
+ if (!platform) {
424
+ res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
425
+ return;
426
+ }
427
+ if (!rcAccessToken) {
428
+ res.status(400).send(tracer ? tracer.wrapResponse('Missing RingCentral access token') : 'Missing RingCentral access token');
429
+ return;
430
+ }
431
+ const { rcAccountId, rcExtensionId } = await adminCore.validateRcUserToken({ rcAccessToken });
432
+ const managedAuthState = await managedAuthCore.getManagedAuthState({
433
+ platform,
434
+ rcAccountId,
435
+ rcExtensionId,
436
+ connectorId: req.query.connectorId,
437
+ isPrivate: req.query.isPrivate === 'true'
438
+ });
439
+ res.status(200).send(tracer ? tracer.wrapResponse(managedAuthState) : managedAuthState);
440
+ }
441
+ catch (e) {
442
+ logger.error('Get API key managed auth state failed', { stack: e.stack });
443
+ tracer?.traceError('apiKeyManagedAuthState:error', e);
444
+ res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
445
+ }
446
+ });
339
447
  // Obsolete
340
448
  router.get('/serverVersionInfo', (req, res) => {
341
449
  const defaultCrmManifest = connectorRegistry.getManifest('default');
@@ -389,7 +497,7 @@ function createCoreRouter() {
389
497
  let success = false;
390
498
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
391
499
  try {
392
- const jwtToken = req.query.jwtToken;
500
+ const jwtToken = req.jwtToken || req.query.jwtToken;
393
501
  if (jwtToken) {
394
502
  const unAuthData = jwt.decodeJwt(jwtToken);
395
503
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -449,6 +557,86 @@ function createCoreRouter() {
449
557
  eventAddedVia
450
558
  });
451
559
  });
560
+ router.get('/admin/managedAuth', async function (req, res) {
561
+ const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
562
+ tracer?.trace('getAdminManagedAuth:start', { query: req.query });
563
+ try {
564
+ const jwtToken = req.jwtToken || req.query.jwtToken;
565
+ if (!jwtToken) {
566
+ res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
567
+ return;
568
+ }
569
+ const unAuthData = jwt.decodeJwt(jwtToken);
570
+ const user = await UserModel.findByPk(unAuthData?.id);
571
+ if (!user) {
572
+ res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
573
+ return;
574
+ }
575
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
576
+ if (!isValidated) {
577
+ res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
578
+ return;
579
+ }
580
+ const managedAuthSettings = await managedAuthCore.getManagedAuthAdminSettings({
581
+ platform: user.platform,
582
+ rcAccountId,
583
+ connectorId: req.query.connectorId,
584
+ isPrivate: req.query.isPrivate === 'true'
585
+ });
586
+ res.status(200).send(tracer ? tracer.wrapResponse(managedAuthSettings) : managedAuthSettings);
587
+ }
588
+ catch (e) {
589
+ logger.error('Get managed auth settings failed', { stack: e.stack });
590
+ tracer?.traceError('getAdminManagedAuth:error', e);
591
+ res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
592
+ }
593
+ });
594
+ router.post('/admin/managedAuth', async function (req, res) {
595
+ const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
596
+ tracer?.trace('setAdminManagedAuth:start', { body: { scope: req.body?.scope, rcExtensionId: req.body?.rcExtensionId } });
597
+ try {
598
+ const jwtToken = req.jwtToken || req.query.jwtToken;
599
+ if (!jwtToken) {
600
+ res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
601
+ return;
602
+ }
603
+ const unAuthData = jwt.decodeJwt(jwtToken);
604
+ const user = await UserModel.findByPk(unAuthData?.id);
605
+ if (!user) {
606
+ res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
607
+ return;
608
+ }
609
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
610
+ if (!isValidated) {
611
+ res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
612
+ return;
613
+ }
614
+ if (req.body?.scope === 'user') {
615
+ await managedAuthCore.upsertUserManagedAuthValues({
616
+ rcAccountId,
617
+ platform: user.platform,
618
+ rcExtensionId: req.body?.rcExtensionId,
619
+ rcUserName: req.body?.rcUserName,
620
+ values: req.body?.values ?? {},
621
+ fieldsToRemove: req.body?.fieldsToRemove ?? []
622
+ });
623
+ }
624
+ else {
625
+ await managedAuthCore.upsertOrgManagedAuthValues({
626
+ rcAccountId,
627
+ platform: user.platform,
628
+ values: req.body?.values ?? {},
629
+ fieldsToRemove: req.body?.fieldsToRemove ?? []
630
+ });
631
+ }
632
+ res.status(200).send(tracer ? tracer.wrapResponse('Shared authentication updated') : 'Shared authentication updated');
633
+ }
634
+ catch (e) {
635
+ logger.error('Set managed auth settings failed', { stack: e.stack });
636
+ tracer?.traceError('setAdminManagedAuth:error', e);
637
+ res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
638
+ }
639
+ });
452
640
  router.post('/admin/userMapping', async function (req, res) {
453
641
  const requestStartTime = new Date().getTime();
454
642
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -457,7 +645,7 @@ function createCoreRouter() {
457
645
  let success = false;
458
646
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
459
647
  try {
460
- const jwtToken = req.query.jwtToken;
648
+ const jwtToken = req.jwtToken || req.query.jwtToken;
461
649
  if (jwtToken) {
462
650
  const unAuthData = jwt.decodeJwt(jwtToken);
463
651
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -520,7 +708,7 @@ function createCoreRouter() {
520
708
  let success = false;
521
709
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
522
710
  try {
523
- const jwtToken = req.query.jwtToken;
711
+ const jwtToken = req.jwtToken || req.query.jwtToken;
524
712
  if (jwtToken) {
525
713
  const unAuthData = jwt.decodeJwt(jwtToken);
526
714
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -581,7 +769,7 @@ function createCoreRouter() {
581
769
  tracer?.trace('getServerLoggingSettings:start', { query: req.query });
582
770
  let platformName = null;
583
771
  let success = false;
584
- const jwtToken = req.query.jwtToken;
772
+ const jwtToken = req.jwtToken || req.query.jwtToken;
585
773
  if (!jwtToken) {
586
774
  tracer?.trace('getServerLoggingSettings:noToken', {});
587
775
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -632,7 +820,7 @@ function createCoreRouter() {
632
820
  tracer?.trace('setServerLoggingSettings:start', { body: req.body });
633
821
  let platformName = null;
634
822
  let success = false;
635
- const jwtToken = req.query.jwtToken;
823
+ const jwtToken = req.jwtToken || req.query.jwtToken;
636
824
  if (!jwtToken) {
637
825
  tracer?.trace('setServerLoggingSettings:noToken', {});
638
826
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -713,7 +901,7 @@ function createCoreRouter() {
713
901
  let success = false;
714
902
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
715
903
  try {
716
- const jwtToken = req.query.jwtToken;
904
+ const jwtToken = req.jwtToken || req.query.jwtToken;
717
905
  if (jwtToken) {
718
906
  const unAuthData = jwt.decodeJwt(jwtToken);
719
907
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -765,7 +953,7 @@ function createCoreRouter() {
765
953
  let success = false;
766
954
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
767
955
  try {
768
- const jwtToken = req.query.jwtToken;
956
+ const jwtToken = req.jwtToken || req.query.jwtToken;
769
957
  if (jwtToken) {
770
958
  const unAuthData = jwt.decodeJwt(jwtToken);
771
959
  platformName = unAuthData?.platform;
@@ -814,7 +1002,7 @@ function createCoreRouter() {
814
1002
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
815
1003
  tracer?.trace('hostname:start', { query: req.query });
816
1004
  try {
817
- const jwtToken = req.query.jwtToken;
1005
+ const jwtToken = req.jwtToken || req.query.jwtToken;
818
1006
  if (jwtToken) {
819
1007
  const unAuthData = jwt.decodeJwt(jwtToken);
820
1008
  const user = await UserModel.findByPk(unAuthData?.id);
@@ -951,7 +1139,14 @@ function createCoreRouter() {
951
1139
  router.post('/apiKeyLogin', async function (req, res) {
952
1140
  const requestStartTime = new Date().getTime();
953
1141
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
954
- tracer?.trace('apiKeyLogin:start', { body: req.body });
1142
+ tracer?.trace('apiKeyLogin:start', {
1143
+ body: {
1144
+ platform: req.body?.platform,
1145
+ hostname: req.body?.hostname,
1146
+ proxyId: req.body?.proxyId,
1147
+ hasAdditionalInfo: !!req.body?.additionalInfo
1148
+ }
1149
+ });
955
1150
  let platformName = null;
956
1151
  let success = false;
957
1152
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
@@ -962,17 +1157,33 @@ function createCoreRouter() {
962
1157
  const hostname = req.body.hostname;
963
1158
  const proxyId = req.body.proxyId;
964
1159
  const additionalInfo = req.body.additionalInfo;
1160
+ const rcAccessToken = req.body.rcAccessToken;
1161
+ const connectorId = req.body.connectorId;
1162
+ const isPrivate = !!req.body.isPrivate;
965
1163
  if (!platform) {
966
1164
  tracer?.trace('apiKeyLogin:missingPlatform', {});
967
1165
  res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
968
1166
  return;
969
1167
  }
970
- if (!apiKey) {
971
- tracer?.trace('apiKeyLogin:missingApiKey', {});
972
- res.status(400).send(tracer ? tracer.wrapResponse('Missing api key') : 'Missing api key');
973
- return;
1168
+ let rcAccountId = null;
1169
+ let rcExtensionId = null;
1170
+ if (rcAccessToken) {
1171
+ const rcUserTokenResult = await adminCore.validateRcUserToken({ rcAccessToken });
1172
+ rcAccountId = rcUserTokenResult.rcAccountId;
1173
+ rcExtensionId = rcUserTokenResult.rcExtensionId;
974
1174
  }
975
- const { userInfo, returnMessage } = await authCore.onApiKeyLogin({ platform, hostname, apiKey, proxyId, rcAccountId: query.rcAccountId, hashedRcExtensionId: hashedExtensionId, additionalInfo });
1175
+ const { userInfo, returnMessage } = await authCore.onApiKeyLogin({
1176
+ platform,
1177
+ hostname,
1178
+ apiKey,
1179
+ proxyId,
1180
+ rcAccountId,
1181
+ rcExtensionId,
1182
+ connectorId,
1183
+ isPrivate,
1184
+ hashedRcExtensionId: hashedExtensionId,
1185
+ additionalInfo
1186
+ });
976
1187
  if (userInfo) {
977
1188
  const jwtToken = jwt.generateJwt({
978
1189
  id: userInfo.id.toString(),
@@ -1015,7 +1226,7 @@ function createCoreRouter() {
1015
1226
  let success = false;
1016
1227
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1017
1228
  try {
1018
- const jwtToken = req.query.jwtToken;
1229
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1019
1230
  if (jwtToken) {
1020
1231
  const unAuthData = jwt.decodeJwt(jwtToken);
1021
1232
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -1082,7 +1293,7 @@ function createCoreRouter() {
1082
1293
  let extraData = {};
1083
1294
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1084
1295
  try {
1085
- const jwtToken = req.query.jwtToken;
1296
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1086
1297
  if (jwtToken) {
1087
1298
  const decodedToken = jwt.decodeJwt(jwtToken);
1088
1299
  tracer?.trace('findContact:jwtDecoded', { decodedToken });
@@ -1160,7 +1371,7 @@ function createCoreRouter() {
1160
1371
  let extraData = {};
1161
1372
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1162
1373
  try {
1163
- const jwtToken = req.query.jwtToken;
1374
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1164
1375
  if (jwtToken) {
1165
1376
  const decodedToken = jwt.decodeJwt(jwtToken);
1166
1377
  if (!decodedToken) {
@@ -1223,7 +1434,7 @@ function createCoreRouter() {
1223
1434
  let extraData = {};
1224
1435
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1225
1436
  try {
1226
- const jwtToken = req.query.jwtToken;
1437
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1227
1438
  if (jwtToken) {
1228
1439
  const decodedToken = jwt.decodeJwt(jwtToken);
1229
1440
  if (!decodedToken) {
@@ -1274,7 +1485,7 @@ function createCoreRouter() {
1274
1485
  let extraData = {};
1275
1486
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1276
1487
  try {
1277
- const jwtToken = req.query.jwtToken;
1488
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1278
1489
  if (jwtToken) {
1279
1490
  const decodedToken = jwt.decodeJwt(jwtToken);
1280
1491
  if (!decodedToken) {
@@ -1338,7 +1549,7 @@ function createCoreRouter() {
1338
1549
  let extraData = {};
1339
1550
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1340
1551
  try {
1341
- const jwtToken = req.query.jwtToken;
1552
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1342
1553
  if (jwtToken) {
1343
1554
  const decodedToken = jwt.decodeJwt(jwtToken);
1344
1555
  if (!decodedToken) {
@@ -1401,7 +1612,7 @@ function createCoreRouter() {
1401
1612
  let extraData = {};
1402
1613
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1403
1614
  try {
1404
- const jwtToken = req.query.jwtToken;
1615
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1405
1616
  if (jwtToken) {
1406
1617
  const decodedToken = jwt.decodeJwt(jwtToken);
1407
1618
  if (!decodedToken) {
@@ -1458,9 +1669,15 @@ function createCoreRouter() {
1458
1669
  let extraData = {};
1459
1670
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1460
1671
  try {
1461
- const jwtToken = req.query.jwtToken;
1672
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1462
1673
  if (jwtToken) {
1463
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
1674
+ const decodedToken = jwt.decodeJwt(jwtToken);
1675
+ if (!decodedToken) {
1676
+ tracer?.trace('upsertCallDisposition:invalidJwtToken', {});
1677
+ res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
1678
+ return;
1679
+ }
1680
+ const { id: userId, platform } = decodedToken;
1464
1681
  platformName = platform;
1465
1682
  if (!userId) {
1466
1683
  tracer?.trace('upsertCallDisposition:invalidToken', {});
@@ -1527,7 +1744,7 @@ function createCoreRouter() {
1527
1744
  let extraData = {};
1528
1745
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1529
1746
  try {
1530
- const jwtToken = req.query.jwtToken;
1747
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1531
1748
  if (jwtToken) {
1532
1749
  const decodedToken = jwt.decodeJwt(jwtToken);
1533
1750
  if (!decodedToken) {
@@ -1591,7 +1808,7 @@ function createCoreRouter() {
1591
1808
  let statusCode = 200;
1592
1809
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1593
1810
  try {
1594
- const jwtToken = req.query.jwtToken;
1811
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1595
1812
  if (!jwtToken) {
1596
1813
  tracer?.trace('scheduleCallDown:noToken', {});
1597
1814
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1639,7 +1856,7 @@ function createCoreRouter() {
1639
1856
  let statusCode = 200;
1640
1857
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1641
1858
  try {
1642
- const jwtToken = req.query.jwtToken;
1859
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1643
1860
  if (!jwtToken) {
1644
1861
  tracer?.trace('getCallDownList:noToken', {});
1645
1862
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1680,7 +1897,7 @@ function createCoreRouter() {
1680
1897
  let statusCode = 200;
1681
1898
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1682
1899
  try {
1683
- const jwtToken = req.query.jwtToken;
1900
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1684
1901
  const id = req.query.id;
1685
1902
  if (!jwtToken) {
1686
1903
  tracer?.trace('deleteCallDownItem:noToken', {});
@@ -1728,7 +1945,7 @@ function createCoreRouter() {
1728
1945
  let statusCode = 200;
1729
1946
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1730
1947
  try {
1731
- const jwtToken = req.query.jwtToken;
1948
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1732
1949
  if (!jwtToken) {
1733
1950
  tracer?.trace('markCallDownCalled:noToken', {});
1734
1951
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1775,9 +1992,16 @@ function createCoreRouter() {
1775
1992
  let statusCode = 200;
1776
1993
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1777
1994
  try {
1778
- const jwtToken = req.query.jwtToken;
1995
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1779
1996
  if (jwtToken) {
1780
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
1997
+ const decodedToken = jwt.decodeJwt(jwtToken);
1998
+ if (!decodedToken) {
1999
+ tracer?.trace('findContactWithName:invalidJwtToken', {});
2000
+ res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
2001
+ success = false;
2002
+ return;
2003
+ }
2004
+ const { id: userId, platform } = decodedToken;
1781
2005
  platformName = platform;
1782
2006
  const { successful, returnMessage, contact, isRevokeUserSession } = await contactCore.findContactWithName({ platform, userId, name: req.query.name });
1783
2007
  if (isRevokeUserSession) {
@@ -1827,7 +2051,7 @@ function createCoreRouter() {
1827
2051
  let platformName = null;
1828
2052
  let success = false;
1829
2053
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1830
- const jwtToken = req.query.jwtToken;
2054
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1831
2055
  try {
1832
2056
  if (jwtToken) {
1833
2057
  const unAuthData = jwt.decodeJwt(jwtToken);
@@ -1873,7 +2097,7 @@ function createCoreRouter() {
1873
2097
  let platformName = null;
1874
2098
  let success = false;
1875
2099
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1876
- const jwtToken = req.query.jwtToken;
2100
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1877
2101
  try {
1878
2102
  if (jwtToken) {
1879
2103
  const unAuthData = jwt.decodeJwt(jwtToken);
@@ -1914,7 +2138,7 @@ function createCoreRouter() {
1914
2138
  router.get('/ringcentral/oauth/callback', async function (req, res) {
1915
2139
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1916
2140
  tracer?.trace('onRingcentralOAuthCallback:start', { query: req.query });
1917
- const jwtToken = req.query.jwtToken;
2141
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1918
2142
  if (jwtToken) {
1919
2143
  const unAuthData = jwt.decodeJwt(jwtToken);
1920
2144
  const { code } = req.query;
@@ -1938,7 +2162,7 @@ function createCoreRouter() {
1938
2162
  let platformName = null;
1939
2163
  let success = false;
1940
2164
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1941
- const jwtToken = req.query.jwtToken;
2165
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1942
2166
  if (jwtToken) {
1943
2167
  const unAuthData = jwt.decodeJwt(jwtToken);
1944
2168
  const uploadUrl = await s3ErrorLogReport.getUploadUrl({ userId: unAuthData?.id, platform: unAuthData?.platform });
@@ -2219,7 +2443,8 @@ function createCoreMiddleware() {
2219
2443
  }
2220
2444
  }),
2221
2445
  cors({
2222
- methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE']
2446
+ methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'],
2447
+ exposedHeaders: ['x-refreshed-jwt-token']
2223
2448
  })
2224
2449
  ];
2225
2450
  }
package/lib/jwt.js CHANGED
@@ -2,7 +2,7 @@ const { sign, verify } = require('jsonwebtoken');
2
2
  const logger = require('./logger');
3
3
 
4
4
  function generateJwt(data) {
5
- return sign(data, process.env.APP_SERVER_SECRET_KEY, { expiresIn: '120y' })
5
+ return sign(data, process.env.APP_SERVER_SECRET_KEY, { expiresIn: '2w' })
6
6
  }
7
7
 
8
8
  function decodeJwt(token) {
@@ -220,7 +220,11 @@ async function execute(args) {
220
220
  }
221
221
 
222
222
  // Decode JWT to get userId and platform
223
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
223
+ const decodedToken = jwt.decodeJwt(jwtToken);
224
+ if (!decodedToken) {
225
+ throw new Error('Invalid JWT token');
226
+ }
227
+ const { id: userId, platform } = decodedToken;
224
228
 
225
229
  if (!userId) {
226
230
  throw new Error('Invalid JWT token: userId not found');
@@ -57,7 +57,11 @@ async function execute(args) {
57
57
  }
58
58
 
59
59
  // Decode JWT to get userId and platform
60
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
60
+ const decodedToken = jwt.decodeJwt(jwtToken);
61
+ if (!decodedToken) {
62
+ throw new Error('Invalid JWT token');
63
+ }
64
+ const { id: userId, platform } = decodedToken;
61
65
 
62
66
  if (!userId) {
63
67
  throw new Error('Invalid JWT token: userId not found');
@@ -228,7 +228,11 @@ async function execute(args) {
228
228
  }
229
229
 
230
230
  // Decode JWT to get userId and platform
231
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
231
+ const decodedToken = jwt.decodeJwt(jwtToken);
232
+ if (!decodedToken) {
233
+ throw new Error('Invalid JWT token');
234
+ }
235
+ const { id: userId, platform } = decodedToken;
232
236
 
233
237
  if (!userId) {
234
238
  throw new Error('Invalid JWT token: userId not found');
@@ -42,7 +42,11 @@ async function execute(args) {
42
42
  throw new Error('Not authenticated. Please connect to your CRM first.');
43
43
  }
44
44
  // Decode JWT to get userId and platform
45
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
45
+ const decodedToken = jwt.decodeJwt(jwtToken);
46
+ if (!decodedToken) {
47
+ throw new Error('Invalid JWT token');
48
+ }
49
+ const { id: userId, platform } = decodedToken;
46
50
 
47
51
  if (!userId) {
48
52
  throw new Error('Invalid JWT token: userId not found');
@@ -51,7 +51,11 @@ async function execute(args) {
51
51
  const { jwtToken, phoneNumber, overridingFormat, isExtension } = args;
52
52
 
53
53
  // Decode JWT to get userId and platform
54
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
54
+ const decodedToken = jwt.decodeJwt(jwtToken);
55
+ if (!decodedToken) {
56
+ throw new Error('Invalid JWT token');
57
+ }
58
+ const { id: userId, platform } = decodedToken;
55
59
 
56
60
  if (!userId) {
57
61
  throw new Error('Invalid JWT token: userId not found');
@@ -94,4 +98,4 @@ async function execute(args) {
94
98
  }
95
99
 
96
100
  exports.definition = toolDefinition;
97
- exports.execute = execute;
101
+ exports.execute = execute;
@@ -45,7 +45,11 @@ async function execute(args) {
45
45
  const { jwtToken, sessionIds, requireDetails = false } = args;
46
46
 
47
47
  // Decode JWT to get userId and platform
48
- const { id: userId, platform } = jwt.decodeJwt(jwtToken);
48
+ const decodedToken = jwt.decodeJwt(jwtToken);
49
+ if (!decodedToken) {
50
+ throw new Error('Invalid JWT token');
51
+ }
52
+ const { id: userId, platform } = decodedToken;
49
53
 
50
54
  if (!userId) {
51
55
  throw new Error('Invalid JWT token: userId not found');
@@ -32,7 +32,11 @@ async function execute(args) {
32
32
  if (!rcAccessToken) {
33
33
  throw new Error('RingCentral access token not found');
34
34
  }
35
- const { id: userId } = jwt.decodeJwt(jwtToken);
35
+ const decodedToken = jwt.decodeJwt(jwtToken);
36
+ if (!decodedToken) {
37
+ throw new Error('Invalid JWT token');
38
+ }
39
+ const { id: userId } = decodedToken;
36
40
  if (!userId) {
37
41
  throw new Error('Invalid JWT token: userId not found');
38
42
  }
@@ -58,4 +62,4 @@ async function execute(args) {
58
62
  }
59
63
 
60
64
  exports.definition = toolDefinition;
61
- exports.execute = execute;
65
+ exports.execute = execute;