diff --git a/lib/generateJwt.js b/lib/generateJwt.js index 8e460fa..f458fba 100644 --- a/lib/generateJwt.js +++ b/lib/generateJwt.js @@ -1,13 +1,17 @@ var jwt = require('jsonwebtoken'); -module.exports = function (config) { +module.exports = function (config, additionalClaims) { var currentTime = Math.floor(new Date() / 1000); - var token = jwt.sign({ + const initialClaims = { iss: config.apiKey, ist: 'project', iat: currentTime, - exp: currentTime + config.auth.expire - }, config.apiSecret); + exp: additionalClaims?.expire_time || currentTime + config.auth.expire + }; + + const claims = {...initialClaims, ...additionalClaims}; + + var token = jwt.sign(claims, config.apiSecret); return token; }; diff --git a/lib/opentok.js b/lib/opentok.js index 266ad3d..92817dd 100644 --- a/lib/opentok.js +++ b/lib/opentok.js @@ -1,11 +1,12 @@ -/* +'use strict'; + +/** * OpenTok server-side SDK */ // Dependencies var net = require('net'); var _ = require('lodash'); -var encodeToken = require('opentok-token'); var Client = require('./client'); var Session = require('./session'); var Stream = require('./stream'); @@ -488,7 +489,6 @@ OpenTok = function (apiKey, apiSecret, env) { ); }; - /** * Starts live captions for an OpenTok Session *
@@ -549,7 +549,6 @@ OpenTok = function (apiKey, apiSecret, env) { this.startCaptions = captions.startCaptions.bind(null, apiConfig); - /** * Stops live captions for an OpenTok Session * @@ -581,7 +580,6 @@ OpenTok = function (apiKey, apiSecret, env) { this.stopCaptions = captions.stopCaptions.bind(null, apiConfig); - /** * Retrieves a List of {@link Render} objects, representing any renders in the starting, * started, stopped or failed state, for your API key. @@ -2118,7 +2116,7 @@ OpenTok.prototype.createSession = function (opts, callback) { * * * -* @return The token string. +* @return {String} The JWT Token that works for the client side */ OpenTok.prototype.generateToken = function (sessionId, opts) { @@ -2200,8 +2198,9 @@ OpenTok.prototype.generateToken = function (sessionId, opts) { + 'concatenated length of less than 1024'); } - return encodeToken(tokenData, this.apiKey, this.apiSecret); + tokenData.scope = 'session.connect'; + return generateJwt(this.client.c, tokenData); }; /* diff --git a/package-lock.json b/package-lock.json index fe834a3..8e28be1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "dependencies": { "jsonwebtoken": "9.0.2", "lodash": "4.17.21", - "node-fetch": "2.7.0", - "opentok-token": "1.1.1" + "node-fetch": "2.7.0" }, "devDependencies": { "chai": "4.3.10", @@ -3679,14 +3678,6 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, - "node_modules/nonce": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz", - "integrity": "sha512-FVPu+tMZPP91HDwiq1DNhn9WIhg4/uo6mXR0xXAn0IMOxDmjJOkgbH0tm7qtowvAFZofWZRX+9KWZpNURrgtSA==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4028,16 +4019,6 @@ "wrappy": "1" } }, - "node_modules/opentok-token": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/opentok-token/-/opentok-token-1.1.1.tgz", - "integrity": "sha512-/uMsmUMiGWT95zemuE9H3OWSb+1NcDmZSDzjum1oKk2KLLGkjqlPsEo8NWarH2q1rfd+cBWP8Pu+dwJS0uNHcg==", - "dependencies": { - "lodash": "^4.17.11", - "nonce": "^1.0.3", - "unix-timestamp": "^0.1.2" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -5126,11 +5107,6 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, - "node_modules/unix-timestamp": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unix-timestamp/-/unix-timestamp-0.1.2.tgz", - "integrity": "sha512-nSpkcoMTJWN8sup4/pAt04Rj8Psf9hV6ymtn6XWWBtGBCyKhxvkhi/MOfLn8GLfITIaRt4XFnrg9Mb3SSkT+sg==" - }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", diff --git a/package.json b/package.json index 5736712..4968501 100644 --- a/package.json +++ b/package.json @@ -82,8 +82,7 @@ "dependencies": { "jsonwebtoken": "9.0.2", "lodash": "4.17.21", - "node-fetch": "2.7.0", - "opentok-token": "1.1.1" + "node-fetch": "2.7.0" }, "devDependencies": { "chai": "4.3.10", diff --git a/test/helpers.js b/test/helpers.js index 53a6a17..90c2427 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -1,3 +1,5 @@ +'use strict'; + // Test Helpers var qs = require('querystring'); var crypto = require('crypto'); diff --git a/test/opentok-test.js b/test/opentok-test.js index af1ae4e..5db3ef2 100644 --- a/test/opentok-test.js +++ b/test/opentok-test.js @@ -907,11 +907,11 @@ describe('#generateToken', function () { var token = this.opentok.generateToken(this.sessionId); var decoded; expect(token).to.be.a('string'); - expect(helpers.verifyTokenSignature(token, apiSecret)).to.be.true; - decoded = helpers.decodeToken(token); - expect(decoded.partner_id).to.equal(apiKey); + decoded = jwt.verify(token, apiSecret); + expect(decoded.session_id).to.equal(this.sessionId); expect(decoded.create_time).to.exist; expect(decoded.nonce).to.exist; + expect(decoded.role).to.equal('publisher'); }); it('assigns a role in the token', function () { @@ -920,9 +920,7 @@ describe('#generateToken', function () { var decoded; var subscriberToken; expect(defaultRoleToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(defaultRoleToken, apiSecret)).to.be - .true; - decoded = helpers.decodeToken(defaultRoleToken); + decoded = jwt.verify(defaultRoleToken, apiSecret); expect(decoded.role).to.equal('publisher'); // expects one with a valid role defined to set it @@ -930,8 +928,7 @@ describe('#generateToken', function () { role: 'subscriber' }); expect(subscriberToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(subscriberToken, apiSecret)).to.be.true; - decoded = helpers.decodeToken(subscriberToken); + decoded = jwt.verify(subscriberToken, apiSecret); expect(decoded.role).to.equal('subscriber'); // expects one with an invalid role to complain @@ -953,24 +950,19 @@ describe('#generateToken', function () { var inOneHour; var oneHourAgo; - var fractionalExpireTime; var roundedToken; expect(defaultExpireToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(defaultExpireToken, apiSecret)).to.be - .true; - decoded = helpers.decodeToken(defaultExpireToken); + decoded = jwt.verify(defaultExpireToken, apiSecret); expireTime = parseInt(decoded.expire_time, 10); expect(expireTime).to.be.closeTo(inOneDay, delta); - // expects a token with an expiration time to have it inOneHour = now + (60 * 60); oneHourToken = this.opentok.generateToken(this.sessionId, { expireTime: inOneHour }); expect(oneHourToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(oneHourToken, apiSecret)).to.be.true; - decoded = helpers.decodeToken(oneHourToken); + decoded = jwt.verify(oneHourToken, apiSecret); expireTime = parseInt(decoded.expire_time, 10); expect(expireTime).to.be.closeTo(inOneHour, delta); @@ -985,13 +977,12 @@ describe('#generateToken', function () { }).to.throw(Error); // rounds down fractional expiration time - fractionalExpireTime = now + 60.5; + const fractionalExpireTime = now + 60.5; roundedToken = this.opentok.generateToken(this.sessionId, { expireTime: fractionalExpireTime }); - expect(helpers.verifyTokenSignature(roundedToken, apiSecret)).to.be.true; - decoded = helpers.decodeToken(roundedToken); - expect(decoded.expire_time).to.equal(Math.round(fractionalExpireTime).toString()); + decoded = jwt.verify(roundedToken, apiSecret); + expect(decoded.exp).to.equal(Math.round(fractionalExpireTime)); }); it('sets initial layout class list in the token', function () { @@ -1000,19 +991,15 @@ describe('#generateToken', function () { var layoutBearingToken = this.opentok.generateToken(this.sessionId, { initialLayoutClassList: layoutClassList }); - var decoded = helpers.decodeToken(layoutBearingToken); + var decoded = jwt.verify(layoutBearingToken, apiSecret); var singleLayoutBearingToken = this.opentok.generateToken(this.sessionId, { initialLayoutClassList: singleLayoutClass }); expect(layoutBearingToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(layoutBearingToken, apiSecret)).to.be - .true; expect(decoded.initial_layout_class_list).to.equal(layoutClassList.join(' ')); expect(singleLayoutBearingToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(singleLayoutBearingToken, apiSecret)).to - .be.true; - decoded = helpers.decodeToken(singleLayoutBearingToken); + decoded = jwt.verify(singleLayoutBearingToken, apiSecret); expect(decoded.initial_layout_class_list).to.equal(singleLayoutClass); // NOTE: ignores invalid options instead of throwing an error, except if its too long @@ -1032,9 +1019,7 @@ describe('#generateToken', function () { data: sampleData }); expect(dataBearingToken).to.be.a('string'); - expect(helpers.verifyTokenSignature(dataBearingToken, apiSecret)).to.be - .true; - decoded = helpers.decodeToken(dataBearingToken); + decoded = jwt.verify(dataBearingToken, apiSecret); expect(decoded.connection_data).to.equal(sampleData); // expects a token with invalid connection data to complain @@ -1066,8 +1051,9 @@ describe('#generateToken', function () { this.opentok.generateToken(this.sessionId) ]; var nonces = _.map(tokens, function (token) { - return helpers.decodeToken(token).nonce; + return jwt.verify(token, apiSecret).nonce; }); + expect(_.uniq(nonces)).to.have.length(nonces.length); });