@app-connect/core 1.7.21 → 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 (42) 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/log.js +4 -4
  14. package/handlers/managedAuth.js +446 -0
  15. package/index.js +264 -34
  16. package/lib/jwt.js +1 -1
  17. package/mcp/tools/createCallLog.js +5 -1
  18. package/mcp/tools/createContact.js +5 -1
  19. package/mcp/tools/createMessageLog.js +5 -1
  20. package/mcp/tools/findContactByName.js +5 -1
  21. package/mcp/tools/findContactByPhone.js +6 -2
  22. package/mcp/tools/getCallLog.js +5 -1
  23. package/mcp/tools/rcGetCallLogs.js +6 -2
  24. package/mcp/tools/updateCallLog.js +5 -1
  25. package/mcp/ui/App/lib/developerPortal.ts +1 -1
  26. package/package.json +72 -72
  27. package/releaseNotes.json +8 -0
  28. package/test/handlers/admin.test.js +34 -0
  29. package/test/handlers/auth.test.js +402 -6
  30. package/test/handlers/managedAuth.test.js +458 -0
  31. package/test/index.test.js +105 -0
  32. package/test/lib/jwt.test.js +15 -0
  33. package/test/mcp/tools/createCallLog.test.js +11 -0
  34. package/test/mcp/tools/createContact.test.js +58 -0
  35. package/test/mcp/tools/createMessageLog.test.js +15 -0
  36. package/test/mcp/tools/findContactByName.test.js +12 -0
  37. package/test/mcp/tools/findContactByPhone.test.js +12 -0
  38. package/test/mcp/tools/getCallLog.test.js +12 -0
  39. package/test/mcp/tools/rcGetCallLogs.test.js +56 -0
  40. package/test/mcp/tools/updateCallLog.test.js +14 -0
  41. package/test/routes/managedAuthRoutes.test.js +132 -0
  42. 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,12 +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
- const { userInfo, returnMessage } = await authCore.onApiKeyLogin({ platform, hostname, apiKey, proxyId, rcAccountId: req.body.rcAccountId, hashedRcExtensionId: hashedExtensionId, additionalInfo });
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;
1174
+ }
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
+ });
971
1187
  if (userInfo) {
972
1188
  const jwtToken = jwt.generateJwt({
973
1189
  id: userInfo.id.toString(),
@@ -1010,7 +1226,7 @@ function createCoreRouter() {
1010
1226
  let success = false;
1011
1227
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1012
1228
  try {
1013
- const jwtToken = req.query.jwtToken;
1229
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1014
1230
  if (jwtToken) {
1015
1231
  const unAuthData = jwt.decodeJwt(jwtToken);
1016
1232
  platformName = unAuthData?.platform ?? 'Unknown';
@@ -1077,7 +1293,7 @@ function createCoreRouter() {
1077
1293
  let extraData = {};
1078
1294
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1079
1295
  try {
1080
- const jwtToken = req.query.jwtToken;
1296
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1081
1297
  if (jwtToken) {
1082
1298
  const decodedToken = jwt.decodeJwt(jwtToken);
1083
1299
  tracer?.trace('findContact:jwtDecoded', { decodedToken });
@@ -1155,7 +1371,7 @@ function createCoreRouter() {
1155
1371
  let extraData = {};
1156
1372
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1157
1373
  try {
1158
- const jwtToken = req.query.jwtToken;
1374
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1159
1375
  if (jwtToken) {
1160
1376
  const decodedToken = jwt.decodeJwt(jwtToken);
1161
1377
  if (!decodedToken) {
@@ -1218,7 +1434,7 @@ function createCoreRouter() {
1218
1434
  let extraData = {};
1219
1435
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1220
1436
  try {
1221
- const jwtToken = req.query.jwtToken;
1437
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1222
1438
  if (jwtToken) {
1223
1439
  const decodedToken = jwt.decodeJwt(jwtToken);
1224
1440
  if (!decodedToken) {
@@ -1269,7 +1485,7 @@ function createCoreRouter() {
1269
1485
  let extraData = {};
1270
1486
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1271
1487
  try {
1272
- const jwtToken = req.query.jwtToken;
1488
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1273
1489
  if (jwtToken) {
1274
1490
  const decodedToken = jwt.decodeJwt(jwtToken);
1275
1491
  if (!decodedToken) {
@@ -1333,7 +1549,7 @@ function createCoreRouter() {
1333
1549
  let extraData = {};
1334
1550
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1335
1551
  try {
1336
- const jwtToken = req.query.jwtToken;
1552
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1337
1553
  if (jwtToken) {
1338
1554
  const decodedToken = jwt.decodeJwt(jwtToken);
1339
1555
  if (!decodedToken) {
@@ -1396,7 +1612,7 @@ function createCoreRouter() {
1396
1612
  let extraData = {};
1397
1613
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1398
1614
  try {
1399
- const jwtToken = req.query.jwtToken;
1615
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1400
1616
  if (jwtToken) {
1401
1617
  const decodedToken = jwt.decodeJwt(jwtToken);
1402
1618
  if (!decodedToken) {
@@ -1453,9 +1669,15 @@ function createCoreRouter() {
1453
1669
  let extraData = {};
1454
1670
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1455
1671
  try {
1456
- const jwtToken = req.query.jwtToken;
1672
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1457
1673
  if (jwtToken) {
1458
- 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;
1459
1681
  platformName = platform;
1460
1682
  if (!userId) {
1461
1683
  tracer?.trace('upsertCallDisposition:invalidToken', {});
@@ -1522,7 +1744,7 @@ function createCoreRouter() {
1522
1744
  let extraData = {};
1523
1745
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1524
1746
  try {
1525
- const jwtToken = req.query.jwtToken;
1747
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1526
1748
  if (jwtToken) {
1527
1749
  const decodedToken = jwt.decodeJwt(jwtToken);
1528
1750
  if (!decodedToken) {
@@ -1586,7 +1808,7 @@ function createCoreRouter() {
1586
1808
  let statusCode = 200;
1587
1809
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1588
1810
  try {
1589
- const jwtToken = req.query.jwtToken;
1811
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1590
1812
  if (!jwtToken) {
1591
1813
  tracer?.trace('scheduleCallDown:noToken', {});
1592
1814
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1634,7 +1856,7 @@ function createCoreRouter() {
1634
1856
  let statusCode = 200;
1635
1857
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1636
1858
  try {
1637
- const jwtToken = req.query.jwtToken;
1859
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1638
1860
  if (!jwtToken) {
1639
1861
  tracer?.trace('getCallDownList:noToken', {});
1640
1862
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1675,7 +1897,7 @@ function createCoreRouter() {
1675
1897
  let statusCode = 200;
1676
1898
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1677
1899
  try {
1678
- const jwtToken = req.query.jwtToken;
1900
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1679
1901
  const id = req.query.id;
1680
1902
  if (!jwtToken) {
1681
1903
  tracer?.trace('deleteCallDownItem:noToken', {});
@@ -1723,7 +1945,7 @@ function createCoreRouter() {
1723
1945
  let statusCode = 200;
1724
1946
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1725
1947
  try {
1726
- const jwtToken = req.query.jwtToken;
1948
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1727
1949
  if (!jwtToken) {
1728
1950
  tracer?.trace('markCallDownCalled:noToken', {});
1729
1951
  res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
@@ -1770,9 +1992,16 @@ function createCoreRouter() {
1770
1992
  let statusCode = 200;
1771
1993
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1772
1994
  try {
1773
- const jwtToken = req.query.jwtToken;
1995
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1774
1996
  if (jwtToken) {
1775
- 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;
1776
2005
  platformName = platform;
1777
2006
  const { successful, returnMessage, contact, isRevokeUserSession } = await contactCore.findContactWithName({ platform, userId, name: req.query.name });
1778
2007
  if (isRevokeUserSession) {
@@ -1822,7 +2051,7 @@ function createCoreRouter() {
1822
2051
  let platformName = null;
1823
2052
  let success = false;
1824
2053
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1825
- const jwtToken = req.query.jwtToken;
2054
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1826
2055
  try {
1827
2056
  if (jwtToken) {
1828
2057
  const unAuthData = jwt.decodeJwt(jwtToken);
@@ -1868,7 +2097,7 @@ function createCoreRouter() {
1868
2097
  let platformName = null;
1869
2098
  let success = false;
1870
2099
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1871
- const jwtToken = req.query.jwtToken;
2100
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1872
2101
  try {
1873
2102
  if (jwtToken) {
1874
2103
  const unAuthData = jwt.decodeJwt(jwtToken);
@@ -1909,7 +2138,7 @@ function createCoreRouter() {
1909
2138
  router.get('/ringcentral/oauth/callback', async function (req, res) {
1910
2139
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1911
2140
  tracer?.trace('onRingcentralOAuthCallback:start', { query: req.query });
1912
- const jwtToken = req.query.jwtToken;
2141
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1913
2142
  if (jwtToken) {
1914
2143
  const unAuthData = jwt.decodeJwt(jwtToken);
1915
2144
  const { code } = req.query;
@@ -1933,7 +2162,7 @@ function createCoreRouter() {
1933
2162
  let platformName = null;
1934
2163
  let success = false;
1935
2164
  const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1936
- const jwtToken = req.query.jwtToken;
2165
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1937
2166
  if (jwtToken) {
1938
2167
  const unAuthData = jwt.decodeJwt(jwtToken);
1939
2168
  const uploadUrl = await s3ErrorLogReport.getUploadUrl({ userId: unAuthData?.id, platform: unAuthData?.platform });
@@ -2214,7 +2443,8 @@ function createCoreMiddleware() {
2214
2443
  }
2215
2444
  }),
2216
2445
  cors({
2217
- methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE']
2446
+ methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'],
2447
+ exposedHeaders: ['x-refreshed-jwt-token']
2218
2448
  })
2219
2449
  ];
2220
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;