agora-token 2.0.4 → 2.0.6

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.
@@ -3,7 +3,26 @@
3
3
  * nodeunit AccessTokenTest.js
4
4
  * see https://github.com/caolan/nodeunit
5
5
  */
6
- const { AccessToken2, ServiceRtc, ServiceRtm, ServiceChat } = require('../src/AccessToken2')
6
+ const {
7
+ AccessToken2,
8
+ Rtm2Permissions,
9
+ Service,
10
+ ServiceRtc,
11
+ ServiceRtm,
12
+ ServiceStreaming,
13
+ ServiceFCdn,
14
+ ServiceRtm2,
15
+ ServiceChat,
16
+ kRtcServiceType,
17
+ kRtmServiceType,
18
+ kStreamingServiceType,
19
+ kFCdnServiceType,
20
+ kRtm2ServiceType,
21
+ kChatServiceType
22
+ } = require('../src/AccessToken2')
23
+ const fs = require('fs')
24
+ const path = require('path')
25
+ const Module = require('module')
7
26
 
8
27
  var appID = '970CA35de60c44645bbae8a215061b33'
9
28
  var appCertificate = '5CFd2fd1755d40ecb72977518be15d3b'
@@ -15,6 +34,15 @@ var expire = 600
15
34
  var salt = 1
16
35
  var user_id = 'test_user'
17
36
 
37
+ // Represents an unsupported service type for forward compatibility tests.
38
+ class UnknownService extends Service {
39
+ // Creates a service whose type is not registered by AccessToken2.
40
+ constructor(serviceType = 999) {
41
+ super(serviceType)
42
+ }
43
+ }
44
+
45
+ // Verifies deterministic RTC token generation with a numeric user ID.
18
46
  exports.AccessToken_Test = function (test) {
19
47
  var expected =
20
48
  '007eJxTYBBbsMMnKq7p9Hf/HcIX5kce9b518kCiQgSr5Zrp4X1Tu6UUGCzNDZwdjU1TUs0Mkk1MzExMk5ISUy0SjQxNDcwMk4yN3b8IMEQwMTAwMoAwBIL4CgzmKeZGxmamqUmWFsYmFqbGluapxqnGaZYpJmYGSSkpiVwMRhYWRsYmhkbmxgDCaiTj'
@@ -30,7 +58,7 @@ exports.AccessToken_Test = function (test) {
30
58
  test.done()
31
59
  }
32
60
 
33
- // test uid = 0
61
+ // Verifies deterministic RTC token generation with an empty user ID.
34
62
  exports.AccessToken_Test2 = function (test) {
35
63
  var expected =
36
64
  '007eJxTYLhzZP08Lxa1Pg57+TcXb/3cZ3wi4V6kbpbOog0G2dOYk20UGCzNDZwdjU1TUs0Mkk1MzExMk5ISUy0SjQxNDcwMk4yN3b8IMEQwMTAwMoAwBIL4CgzmKeZGxmamqUmWFsYmFqbGluapxqnGaZYpJmYGSSkpiQwMADacImo='
@@ -46,7 +74,7 @@ exports.AccessToken_Test2 = function (test) {
46
74
  test.done()
47
75
  }
48
76
 
49
- // test service rtc account
77
+ // Verifies deterministic RTC token generation with a string user account.
50
78
  exports.AccessToken_Test3 = function (test) {
51
79
  var expected =
52
80
  '007eJxTYBBbsMMnKq7p9Hf/HcIX5kce9b518kCiQgSr5Zrp4X1Tu6UUGCzNDZwdjU1TUs0Mkk1MzExMk5ISUy0SjQxNDcwMk4yN3b8IMEQwMTAwMoAwBIL4CgzmKeZGxmamqUmWFsYmFqbGluapxqnGaZYpJmYGSSkpiVwMRhYWRsYmhkbmxgDCaiTj'
@@ -62,7 +90,7 @@ exports.AccessToken_Test3 = function (test) {
62
90
  test.done()
63
91
  }
64
92
 
65
- // test service multi service
93
+ // Verifies deterministic token generation with distinct service types.
66
94
  exports.AccessToken_Test4 = function (test) {
67
95
  var expected =
68
96
  '007eJxTYOAQsrQ5s3TfH+1tvy8zZZ46EpCc0V43JXdGd2jS8porKo4KDJbmBs6OxqYpqWYGySYmZiamSUmJqRaJRoamBmaGScbG7l8EGCKYGBgYGRgYmBgYGVgYGMF8JjDJDCZZwKQCg3mKuZGxmWlqkqWFsYmFqbGleapxqnGaZYqJmUFSSkoiF4ORhYWRsYmhkbkxyCyISZwMJanFJfGlxalFACKnKng='
@@ -85,6 +113,7 @@ exports.AccessToken_Test4 = function (test) {
85
113
  test.done()
86
114
  }
87
115
 
116
+ // Verifies deterministic Chat user token generation.
88
117
  exports.AccessToken_Test_buildChatUserToken = function (test) {
89
118
  var expected =
90
119
  '007eJxTYNAIsnbS3v/A5t2TC6feR15r+6cq8bqAvfaW+tk/Vzz+p6xTYLA0N3B2NDZNSTUzSDYxMTMxTUpKTLVINDI0NTAzTDI2dv8iwBDBxMDAyADCrAyMDIxgPheDkYWFkbGJoZG5MQAfpR64'
@@ -100,6 +129,7 @@ exports.AccessToken_Test_buildChatUserToken = function (test) {
100
129
  test.done()
101
130
  }
102
131
 
132
+ // Verifies deterministic Chat application token generation.
103
133
  exports.AccessToken_Test_buildChatAppToken = function (test) {
104
134
  var expected =
105
135
  '007eJxTYNDNaz3snC8huEfHWdz6s98qltq4zqy9fl99Uh0FDvy6F6DAYGlu4OxobJqSamaQbGJiZmKalJSYapFoZGhqYGaYZGzs/kWAIYKJgYGRAYRZGRgZmMB8BgYArfIYaw=='
@@ -114,3 +144,300 @@ exports.AccessToken_Test_buildChatAppToken = function (test) {
114
144
  test.equal(expected, actual)
115
145
  test.done()
116
146
  }
147
+
148
+ // Preserves repeated service types and their insertion order after parsing.
149
+ exports.AccessToken_Test_repeatedServiceTypes = function (test) {
150
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
151
+ token.salt = salt
152
+
153
+ const rtmService = new ServiceRtm(user_id)
154
+ rtmService.add_privilege(ServiceRtm.kPrivilegeLogin, expire + 50)
155
+ token.add_service(rtmService)
156
+
157
+ const rtcService = new ServiceRtc(channel, uid)
158
+ rtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
159
+ token.add_service(rtcService)
160
+
161
+ const streamRtcService = new ServiceRtc('stream-channel', 'stream-user')
162
+ streamRtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire + 100)
163
+ streamRtcService.add_privilege(ServiceRtc.kPrivilegePublishDataStream, expire + 100)
164
+ token.add_service(streamRtcService)
165
+
166
+ const encoded = token.build()
167
+ test.equal(3, token.services.length)
168
+ test.strictEqual(rtmService, token.services[0])
169
+ test.equal(2, token.getServices(kRtcServiceType).length)
170
+
171
+ const parsed = new AccessToken2('', '', 0, 0)
172
+ test.equal(true, parsed.from_string(encoded))
173
+ const rtcServices = parsed.getServices(kRtcServiceType)
174
+ test.equal(2, rtcServices.length)
175
+ test.equal(channel, rtcServices[0].__channel_name.toString())
176
+ test.equal('stream-channel', rtcServices[1].__channel_name.toString())
177
+ test.equal(expire + 100, rtcServices[1].__privileges[ServiceRtc.kPrivilegePublishDataStream])
178
+ test.equal(1, parsed.getServices(kRtmServiceType).length)
179
+ test.equal(0, parsed.getServices(kChatServiceType).length)
180
+ test.equal(true, parsed.verifySignature(appCertificate))
181
+ test.equal(false, parsed.verifySignature('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))
182
+ test.done()
183
+ }
184
+
185
+ // Parses and verifies C++ Streaming, FCDN, and RTM2 services.
186
+ exports.AccessToken_Test_extendedServicesFromCpp = function (test) {
187
+ const encoded = '007eJxTYPj86Lzdz79M25wNn/lMfvu+TkfmdpiviKvChm8ZV3SWndytwGBpbuDsaGyakmpmkGxiYmZimpSUmGqRaGRoamBmmGRs7P5FgCGCiYGBkYGBgRkImYAsEJ8JTCowmKeYGxmbmaYmWVoYm1iYGluapxqnGqdZppiYGSSlpCRyMRhZWBgZmxgamRuzUaSbA6gXopuToSS1uCS+tDi1iJkB4jQmoGBuanFxYnqqbiKCmcTIAIEcDMUlRamJubqJLGD1jAxsDCD9uokAO/VDvQ=='
188
+ const parsed = new AccessToken2('', '', 0, 0)
189
+
190
+ test.equal(true, parsed.from_string(encoded))
191
+ test.equal(true, parsed.verifySignature(appCertificate))
192
+
193
+ const streaming = parsed.getServices(kStreamingServiceType)[0]
194
+ test.equal(channel, streaming.__channel_name.toString())
195
+ test.equal(uidStr, streaming.__account.toString())
196
+ test.equal(expire, streaming.__privileges[ServiceStreaming.kPrivilegePublishMixStream])
197
+ test.equal(expire, streaming.__privileges[ServiceStreaming.kPrivilegePublishRawStream])
198
+
199
+ const fcdn = parsed.getServices(kFCdnServiceType)[0]
200
+ test.equal(channel, fcdn.__channel_name.toString())
201
+ test.equal(uidStr, fcdn.__account.toString())
202
+ test.equal(expire, fcdn.__privileges[ServiceFCdn.kPrivilegePublish])
203
+ test.equal(expire, fcdn.__privileges[ServiceFCdn.kPrivilegePlay])
204
+
205
+ const rtm2 = parsed.getServices(kRtm2ServiceType)[0]
206
+ test.equal(user_id, rtm2.__user_id.toString())
207
+ test.deepEqual({
208
+ 0: { 0: ['message-a', 'message-b'] },
209
+ 1: { 1: ['stream-a'] },
210
+ 4: { 0: ['user-a'] }
211
+ }, rtm2.__permissions.details)
212
+ test.equal(expire, rtm2.__privileges[ServiceRtm2.kPrivilegeLogin])
213
+ test.done()
214
+ }
215
+
216
+ // Verifies deterministic Streaming and FCDN generation and UID conversion against C++.
217
+ exports.AccessToken_Test_extendedServiceNumericUidConversion = function (test) {
218
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
219
+ token.salt = salt
220
+ const streamingUid = new ServiceStreaming(channel, uid)
221
+ streamingUid.add_privilege(ServiceStreaming.kPrivilegePublishMixStream, expire)
222
+ token.add_service(streamingUid)
223
+ const streamingWildcard = new ServiceStreaming(channel, 0)
224
+ streamingWildcard.add_privilege(ServiceStreaming.kPrivilegePublishRawStream, expire)
225
+ token.add_service(streamingWildcard)
226
+ const streamingAccount = new ServiceStreaming(channel, 'stream-account')
227
+ streamingAccount.add_privilege(ServiceStreaming.kPrivilegePublishMixStream, expire)
228
+ streamingAccount.add_privilege(ServiceStreaming.kPrivilegePublishRawStream, expire)
229
+ token.add_service(streamingAccount)
230
+ const fcdnUid = new ServiceFCdn(channel, uid)
231
+ fcdnUid.add_privilege(ServiceFCdn.kPrivilegePublish, expire)
232
+ token.add_service(fcdnUid)
233
+ const fcdnWildcard = new ServiceFCdn(channel, 0)
234
+ fcdnWildcard.add_privilege(ServiceFCdn.kPrivilegePlay, expire)
235
+ token.add_service(fcdnWildcard)
236
+ const fcdnAccount = new ServiceFCdn(channel, 'fcdn-account')
237
+ fcdnAccount.add_privilege(ServiceFCdn.kPrivilegePublish, expire)
238
+ fcdnAccount.add_privilege(ServiceFCdn.kPrivilegePlay, expire)
239
+ token.add_service(fcdnAccount)
240
+
241
+ const encoded = token.build()
242
+ test.equal(
243
+ encoded,
244
+ '007eJxTYLi93GuuUHrO9Fr71KVJKqfDby8RezlVfGLMO77DIl79U40UGCzNDZwdjU1TUs0Mkk1MzExMk5ISUy0SjQxNDcwMk4yN3b8IMEQwMTAwMjAwsDEwMzAyMIL5CgzmKeZGxmamqUmWFsYmFqbGluapxqnGaZYpJmYGSSkpiVwMRhYWRsYmhkbmxiB9TETqY2BgZmCC2kKsHj6G4pKi1MRc3cTk5PzSvBI2Mt3JRpI72Uh2Jw9DWnJKHsyVAElvX1c='
245
+ )
246
+ const parsed = new AccessToken2('', '', 0, 0)
247
+ test.equal(true, parsed.from_string(encoded))
248
+ test.deepEqual(
249
+ parsed.getServices(kStreamingServiceType).map(service => service.__account.toString()),
250
+ [uidStr, '', 'stream-account']
251
+ )
252
+ test.deepEqual(
253
+ parsed.getServices(kFCdnServiceType).map(service => service.__account.toString()),
254
+ [uidStr, '', 'fcdn-account']
255
+ )
256
+ test.done()
257
+ }
258
+
259
+ // Generates and parses an RTM2 token whose uncompressed payload exceeds the initial buffer capacity.
260
+ exports.AccessToken_Test_largeRtm2PermissionPayload = function (test) {
261
+ const resources = Array.from({ length: 160 }, (_, index) => `resource-${index.toString().padStart(4, '0')}`)
262
+ const permissions = new Rtm2Permissions()
263
+ permissions.add(Rtm2Permissions.kUsers, Rtm2Permissions.kRead, resources)
264
+
265
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
266
+ token.salt = salt
267
+ const rtm2Service = new ServiceRtm2(user_id, permissions)
268
+ rtm2Service.add_privilege(ServiceRtm2.kPrivilegeLogin, expire)
269
+ token.add_service(rtm2Service)
270
+
271
+ const parsed = new AccessToken2('', '', 0, 0)
272
+ test.equal(true, parsed.from_string(token.build()))
273
+ test.equal(true, parsed.verifySignature(appCertificate))
274
+ test.deepEqual(resources, parsed.getServices(kRtm2ServiceType)[0].__permissions.details[Rtm2Permissions.kUsers][Rtm2Permissions.kRead])
275
+ test.done()
276
+ }
277
+
278
+ // Keeps known services parsed before an unknown service type.
279
+ exports.AccessToken_Test_unknownServiceAfterKnownService = function (test) {
280
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
281
+ token.salt = salt
282
+
283
+ const rtcService = new ServiceRtc(channel, uid)
284
+ rtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
285
+ token.add_service(rtcService)
286
+
287
+ const unknownService = new UnknownService()
288
+ unknownService.add_privilege(1, expire)
289
+ token.add_service(unknownService)
290
+
291
+ const parsed = new AccessToken2('', '', 0, 0)
292
+ test.equal(true, parsed.from_string(token.build()))
293
+ test.equal(1, parsed.getServices(kRtcServiceType).length)
294
+ test.equal(0, parsed.getServices(999).length)
295
+ test.equal(true, parsed.verifySignature(appCertificate))
296
+ test.done()
297
+ }
298
+
299
+ // Stops before known services that follow an unknown service payload.
300
+ exports.AccessToken_Test_unknownServiceBeforeKnownService = function (test) {
301
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
302
+ token.salt = salt
303
+
304
+ const rtcService = new ServiceRtc(channel, uid)
305
+ rtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
306
+ token.add_service(rtcService)
307
+
308
+ const unknownService = new UnknownService(0)
309
+ unknownService.add_privilege(1, expire)
310
+ token.add_service(unknownService)
311
+
312
+ const parsed = new AccessToken2('', '', 0, 0)
313
+ test.equal(true, parsed.from_string(token.build()))
314
+ test.equal(0, parsed.getServices(kRtcServiceType).length)
315
+ test.equal(true, parsed.verifySignature(appCertificate))
316
+ test.done()
317
+ }
318
+
319
+ // Parses an old token and replaces services from an earlier parse.
320
+ exports.AccessToken_Test_parseOldTokenAndClearServices = function (test) {
321
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
322
+ token.salt = salt
323
+ const rtmService = new ServiceRtm(user_id)
324
+ rtmService.add_privilege(ServiceRtm.kPrivilegeLogin, expire)
325
+ token.add_service(rtmService)
326
+
327
+ const parsed = new AccessToken2('', '', 0, 0)
328
+ test.equal(true, parsed.from_string(token.build()))
329
+ test.equal(1, parsed.getServices(kRtmServiceType).length)
330
+
331
+ const oldToken =
332
+ '007eJxTYBBbsMMnKq7p9Hf/HcIX5kce9b518kCiQgSr5Zrp4X1Tu6UUGCzNDZwdjU1TUs0Mkk1MzExMk5ISUy0SjQxNDcwMk4yN3b8IMEQwMTAwMoAwBIL4CgzmKeZGxmamqUmWFsYmFqbGluapxqnGaZYpJmYGSSkpiVwMRhYWRsYmhkbmxgDCaiTj'
333
+ test.equal(true, parsed.from_string(oldToken))
334
+ test.equal(1, parsed.services.length)
335
+ test.equal(1, parsed.getServices(kRtcServiceType).length)
336
+ test.equal(0, parsed.getServices(kRtmServiceType).length)
337
+ test.equal(true, parsed.verifySignature(appCertificate))
338
+ test.done()
339
+ }
340
+
341
+ // Rejects signature verification before parsing or with invalid certificates.
342
+ exports.AccessToken_Test_verifySignaturePreconditions = function (test) {
343
+ const parsed = new AccessToken2('', '', 0, 0)
344
+ test.equal(false, parsed.verifySignature(appCertificate))
345
+
346
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
347
+ token.salt = salt
348
+ const rtcService = new ServiceRtc(channel, uid)
349
+ rtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
350
+ token.add_service(rtcService)
351
+
352
+ test.equal(true, parsed.from_string(token.build()))
353
+ test.equal(false, parsed.verifySignature(null))
354
+ test.equal(false, parsed.verifySignature('invalid'))
355
+ test.equal(false, parsed.verifySignature('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'))
356
+ test.equal(true, parsed.verifySignature(appCertificate))
357
+
358
+ test.equal(false, parsed.from_string('006invalid'))
359
+ test.equal(false, parsed.verifySignature(appCertificate))
360
+ test.equal(0, parsed.services.length)
361
+ test.done()
362
+ }
363
+
364
+ // Sorts distinct service types before packing without changing insertion order.
365
+ exports.AccessToken_Test_stableServiceTypeOrdering = function (test) {
366
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
367
+ token.salt = salt
368
+
369
+ const rtmService = new ServiceRtm(user_id)
370
+ rtmService.add_privilege(ServiceRtm.kPrivilegeLogin, expire)
371
+ token.add_service(rtmService)
372
+
373
+ const rtcService = new ServiceRtc(channel, uid)
374
+ rtcService.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
375
+ rtcService.add_privilege(ServiceRtc.kPrivilegePublishAudioStream, expire)
376
+ rtcService.add_privilege(ServiceRtc.kPrivilegePublishVideoStream, expire)
377
+ rtcService.add_privilege(ServiceRtc.kPrivilegePublishDataStream, expire)
378
+ token.add_service(rtcService)
379
+
380
+ const expected =
381
+ '007eJxTYOAQsrQ5s3TfH+1tvy8zZZ46EpCc0V43JXdGd2jS8porKo4KDJbmBs6OxqYpqWYGySYmZiamSUmJqRaJRoamBmaGScbG7l8EGCKYGBgYGRgYmBgYGVgYGMF8JjDJDCZZwKQCg3mKuZGxmWlqkqWFsYmFqbGleapxqnGaZYqJmUFSSkoiF4ORhYWRsYmhkbkxyCyISZwMJanFJfGlxalFACKnKng='
382
+ test.equal(expected, token.build())
383
+ test.strictEqual(rtmService, token.services[0])
384
+ test.done()
385
+ }
386
+
387
+ // Rejects invalid build fields, non-string tokens, and malformed Token007 payloads.
388
+ exports.AccessToken_Test_invalidBuildAndParseInputs = function (test) {
389
+ const empty = new AccessToken2(appID, appCertificate, ts, expire)
390
+ test.equal('', empty.build())
391
+
392
+ const invalid = new AccessToken2('invalid', appCertificate, ts, expire)
393
+ const service = new ServiceRtc(channel, uid)
394
+ service.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
395
+ invalid.add_service(service)
396
+ test.equal('', invalid.build())
397
+
398
+ const parsed = new AccessToken2('', '', 0, 0)
399
+ test.equal(false, parsed.from_string(null))
400
+ test.equal(false, parsed.from_string('00'))
401
+ test.equal(false, parsed.from_string('007invalid'))
402
+ test.done()
403
+ }
404
+
405
+ // Rejects verification when the parsed signature length is altered.
406
+ exports.AccessToken_Test_signatureLengthMismatch = function (test) {
407
+ const token = new AccessToken2(appID, appCertificate, ts, expire)
408
+ token.salt = salt
409
+ const service = new ServiceRtc(channel, uid)
410
+ service.add_privilege(ServiceRtc.kPrivilegeJoinChannel, expire)
411
+ token.add_service(service)
412
+
413
+ const parsed = new AccessToken2('', '', 0, 0)
414
+ test.equal(true, parsed.from_string(token.build()))
415
+ parsed.__signature = Buffer.alloc(1)
416
+ test.equal(false, parsed.verifySignature(appCertificate))
417
+ test.done()
418
+ }
419
+
420
+ // Exercises private buffer helpers that are retained for wire-format compatibility.
421
+ exports.AccessToken_Test_bufferHelpers = function (test) {
422
+ const filename = path.resolve(__dirname, '../src/AccessToken2.js')
423
+ const source = fs.readFileSync(filename, 'utf8') +
424
+ '\nmodule.exports.__ByteBuf = ByteBuf; module.exports.__ReadByteBuf = ReadByteBuf;'
425
+ const internalModule = new Module(filename, module)
426
+ internalModule.filename = filename
427
+ internalModule.paths = Module._nodeModulePaths(path.dirname(filename))
428
+ internalModule._compile(source, filename)
429
+ const ByteBuf = internalModule.exports.__ByteBuf
430
+ const ReadByteBuf = internalModule.exports.__ReadByteBuf
431
+
432
+ const signed = new ByteBuf().putInt32(-7).putInt16(-2).pack()
433
+ test.equal(-7, signed.readInt32LE(0))
434
+ test.equal(-2, signed.readInt16LE(4))
435
+ test.equal(2, new ByteBuf().putTreeMap(null).pack().length)
436
+ test.equal(2, new ByteBuf().putTreeMapUInt32(null).pack().length)
437
+ test.ok(new ByteBuf().putTreeMap({ 1: 'value' }).pack().length > 2)
438
+
439
+ const reader = new ReadByteBuf(Buffer.from([1, 0, 2, 0, 0, 0]))
440
+ test.equal(1, reader.getUint16())
441
+ test.equal(2, reader.getUint32())
442
+ test.done()
443
+ }
@@ -5,6 +5,11 @@
5
5
  */
6
6
  const AccessToken = require("../src/AccessToken").AccessToken;
7
7
  const Priviledges = require("../src/AccessToken").priviledges;
8
+ const RtcTokenBuilder = require('../src/RtcTokenBuilder').RtcTokenBuilder;
9
+ const SignalingToken = require('../src/SignalingToken');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const Module = require('module');
8
13
 
9
14
  const appID = "970CA35de60c44645bbae8a215061b33";
10
15
  const appCertificate = "5CFd2fd1755d40ecb72977518be15d3b";
@@ -14,6 +19,7 @@ const salt = 1;
14
19
  const ts = 1111111;
15
20
  const expireTimestamp = 1446455471;
16
21
 
22
+ // Verifies deterministic legacy AccessToken generation.
17
23
  exports.AccessToken_Test = function (test) {
18
24
  const expected = "006970CA35de60c44645bbae8a215061b33IACV0fZUBw+72cVoL9eyGGh3Q6Poi8bgjwVLnyKSJyOXR7dIfRBXoFHlEAABAAAAR/QQAAEAAQCvKDdW";
19
25
 
@@ -27,7 +33,7 @@ exports.AccessToken_Test = function (test) {
27
33
  test.done();
28
34
  };
29
35
 
30
- // test uid = 0
36
+ // Verifies deterministic legacy AccessToken generation with an empty user ID.
31
37
  exports.AccessToken_Test2 = function (test) {
32
38
  const expected = "006970CA35de60c44645bbae8a215061b33IACw1o7htY6ISdNRtku3p9tjTPi0jCKf9t49UHJhzCmL6bdIfRAAAAAAEAABAAAAR/QQAAEAAQCvKDdW";
33
39
 
@@ -44,6 +50,7 @@ exports.AccessToken_Test2 = function (test) {
44
50
 
45
51
  const RtcRole = require("../src/RtcTokenBuilder").Role;
46
52
 
53
+ // Verifies deterministic legacy RTC token generation.
47
54
  exports.RtcTokenBuilder_Test = function (test) {
48
55
  const appID = "970CA35de60c44645bbae8a215061b33";
49
56
  const certificate = "5CFd2fd1755d40ecb72977518be15d3b";
@@ -75,3 +82,57 @@ exports.RtcTokenBuilder_Test = function (test) {
75
82
  test.equal(expected, actual);
76
83
  test.done();
77
84
  };
85
+
86
+ // Verifies legacy token parsing and malformed input handling.
87
+ exports.AccessToken_Parse_Test = function (test) {
88
+ const key = new AccessToken(appID, appCertificate, channel, uid);
89
+ key.salt = salt;
90
+ key.ts = ts;
91
+ key.addPriviledge(Priviledges.kJoinChannel, expireTimestamp);
92
+
93
+ const parsed = new AccessToken('', '', '', '');
94
+ test.equal(true, parsed.fromString(key.build()));
95
+ test.equal(expireTimestamp, parsed.messages[Priviledges.kJoinChannel]);
96
+ test.equal(false, parsed.fromString('007invalid'));
97
+ test.equal(false, parsed.fromString('006' + appID + '!'));
98
+ test.done();
99
+ };
100
+
101
+ // Verifies both public legacy RTC builder entry points.
102
+ exports.RtcTokenBuilder_PublicMethods_Test = function (test) {
103
+ const uidToken = RtcTokenBuilder.buildTokenWithUid(
104
+ appID, appCertificate, channel, uid, RtcRole.PUBLISHER, expireTimestamp);
105
+ const accountToken = RtcTokenBuilder.buildTokenWithAccount(
106
+ appID, appCertificate, channel, String(uid), RtcRole.SUBSCRIBER, expireTimestamp);
107
+
108
+ test.equal(true, new AccessToken('', '', '', '').fromString(uidToken));
109
+ test.equal(true, new AccessToken('', '', '', '').fromString(accountToken));
110
+ test.done();
111
+ };
112
+
113
+ // Verifies signaling token generation for explicit and one-day lifetimes.
114
+ exports.SignalingToken_Test = function (test) {
115
+ const token = SignalingToken.get(appID, appCertificate, String(uid), 60);
116
+ const oneDayToken = SignalingToken.get1DayToken(appID, appCertificate, String(uid));
117
+
118
+ test.equal(4, token.split(':').length);
119
+ test.equal(appID, token.split(':')[1]);
120
+ test.equal(4, oneDayToken.split(':').length);
121
+ test.done();
122
+ };
123
+
124
+ // Exercises legacy private map writers retained by the Token006 wire format.
125
+ exports.AccessToken_BufferHelpers_Test = function (test) {
126
+ const filename = path.resolve(__dirname, '../src/AccessToken.js');
127
+ const source = fs.readFileSync(filename, 'utf8') + '\nmodule.exports.__ByteBuf = ByteBuf;';
128
+ const internalModule = new Module(filename, module);
129
+ internalModule.filename = filename;
130
+ internalModule.paths = Module._nodeModulePaths(path.dirname(filename));
131
+ internalModule._compile(source, filename);
132
+ const ByteBuf = internalModule.exports.__ByteBuf;
133
+
134
+ test.equal(2, new ByteBuf().putTreeMap(null).pack().length);
135
+ test.ok(new ByteBuf().putTreeMap({ 1: 'value' }).pack().length > 2);
136
+ test.equal(2, new ByteBuf().putTreeMapUInt32(null).pack().length);
137
+ test.done();
138
+ };
@@ -12,18 +12,21 @@ const roomUuid = '123'
12
12
  const userUuid = '2882341273'
13
13
  const role = 1
14
14
 
15
+ // Verifies APaaS room-user token generation and parsing.
15
16
  exports.BuildRoomUserToken_Test = function (test) {
16
17
  let accessToken = new AccessToken2('', '', 0, 0)
17
18
  let token = ApaasTokenBuilder.buildRoomUserToken(appId, appCertificate, roomUuid, userUuid, role, expire)
18
19
  accessToken.from_string(token)
20
+ const service = accessToken.getServices(kApaasServiceType)[0]
19
21
  test.equal(appId, accessToken.appId)
20
22
  test.equal(expire, accessToken.expire)
21
- test.equal(roomUuid, accessToken.services[kApaasServiceType].__room_uuid)
22
- test.equal(userUuid, accessToken.services[kApaasServiceType].__user_uuid)
23
- test.equal(role, accessToken.services[kApaasServiceType].__role)
23
+ test.equal(roomUuid, service.__room_uuid)
24
+ test.equal(userUuid, service.__user_uuid)
25
+ test.equal(role, service.__role)
24
26
  test.done()
25
27
  }
26
28
 
29
+ // Verifies APaaS user token generation and parsing.
27
30
  exports.BuildUserToken_Test = function (test) {
28
31
  let accessToken = new AccessToken2('', '', 0, 0)
29
32
  let token = ApaasTokenBuilder.buildUserToken(appId, appCertificate, userUuid, expire)
@@ -31,10 +34,11 @@ exports.BuildUserToken_Test = function (test) {
31
34
 
32
35
  test.equal(appId, accessToken.appId)
33
36
  test.equal(expire, accessToken.expire)
34
- test.equal(userUuid, accessToken.services[kApaasServiceType].__user_uuid)
37
+ test.equal(userUuid, accessToken.getServices(kApaasServiceType)[0].__user_uuid)
35
38
  test.done()
36
39
  }
37
40
 
41
+ // Verifies APaaS application token generation and parsing.
38
42
  exports.BuildAppToken_Test = function (test) {
39
43
  let accessToken = new AccessToken2('', '', 0, 0)
40
44
  let token = ApaasTokenBuilder.buildAppToken(appId, appCertificate, expire)
@@ -11,24 +11,26 @@ const appCertificate = "5CFd2fd1755d40ecb72977518be15d3b";
11
11
  const userUuid = "2882341273";
12
12
  const expire = 600;
13
13
 
14
+ // Verifies Chat user token generation and parsing.
14
15
  exports.buildUserToken_Test = function (test) {
15
16
  let token = ChatTokenBuilder.buildUserToken(appId, appCertificate, userUuid, expire);
16
17
  let accessToken = new AccessToken2("", "", 0, 0);
17
18
  accessToken.from_string(token);
19
+ const service = accessToken.getServices(kChatServiceType)[0];
18
20
  test.equal(appId, accessToken.appId);
19
21
  test.equal(expire, accessToken.expire);
20
- test.equal(userUuid, accessToken.services[kChatServiceType].__user_id);
21
- test.equal(expire, accessToken.services[kChatServiceType].__privileges[ServiceChat.kPrivilegeUser]);
22
+ test.equal(userUuid, service.__user_id);
23
+ test.equal(expire, service.__privileges[ServiceChat.kPrivilegeUser]);
22
24
  test.done();
23
25
  };
24
26
 
27
+ // Verifies Chat application token generation and parsing.
25
28
  exports.buildAppToken_Test = function (test) {
26
29
  let token = ChatTokenBuilder.buildAppToken(appId, appCertificate, expire);
27
30
  let accessToken = new AccessToken2("", "", 0, 0);
28
31
  accessToken.from_string(token);
29
32
  test.equal(appId, accessToken.appId);
30
33
  test.equal(expire, accessToken.expire);
31
- test.equal(expire, accessToken.services[kChatServiceType].__privileges[ServiceChat.kPrivilegeApp]);
34
+ test.equal(expire, accessToken.getServices(kChatServiceType)[0].__privileges[ServiceChat.kPrivilegeApp]);
32
35
  test.done();
33
36
  }
34
-
@@ -0,0 +1,58 @@
1
+ /**
2
+ * run this test with command:
3
+ * nodeunit test/ConvoAITokenBuilderTest.js
4
+ */
5
+ const { ConvoAITokenBuilder } = require('../src/ConvoAITokenBuilder')
6
+ const { AccessToken2, kConvoAIServiceType, kRtcServiceType, kRtmServiceType, ServiceRtc, ServiceRtm } = require('../src/AccessToken2')
7
+ const { Role } = require('../src/RtcTokenBuilder2')
8
+
9
+ const appId = '970CA35de60c44645bbae8a215061b33'
10
+ const appCertificate = '5CFd2fd1755d40ecb72977518be15d3b'
11
+ const channelName = '7d72365eb983485397e3e3f9d460bdda'
12
+ const rtcAccount = '2882341273'
13
+ const rtmUserId = '2882341273'
14
+ const rtcTokenExpire = 600
15
+ const joinChannelPrivilegeExpire = 600
16
+ const pubAudioPrivilegeExpire = 600
17
+ const pubVideoPrivilegeExpire = 600
18
+ const pubDataStreamPrivilegeExpire = 600
19
+ const rtmTokenExpire = 600
20
+
21
+ exports.buildToken_PUBLISHER_Test = function (test) {
22
+ const token = ConvoAITokenBuilder.buildToken(
23
+ appId, appCertificate, channelName, rtcAccount, Role.PUBLISHER, rtcTokenExpire,
24
+ joinChannelPrivilegeExpire, pubAudioPrivilegeExpire, pubVideoPrivilegeExpire,
25
+ pubDataStreamPrivilegeExpire, rtmUserId, rtmTokenExpire)
26
+ const parsed = new AccessToken2('', '', 0, 0)
27
+ parsed.from_string(token)
28
+
29
+ const rtc = parsed.getServices(kRtcServiceType)[0]
30
+ const rtm = parsed.getServices(kRtmServiceType)[0]
31
+ const convoai = parsed.getServices(kConvoAIServiceType)[0]
32
+
33
+ test.equal(appId, parsed.appId)
34
+ test.equal(rtcTokenExpire, parsed.expire)
35
+ test.equal(channelName, rtc.__channel_name)
36
+ test.equal(rtcAccount, rtc.__uid)
37
+ test.equal(joinChannelPrivilegeExpire, rtc.__privileges[ServiceRtc.kPrivilegeJoinChannel])
38
+ test.equal(pubAudioPrivilegeExpire, rtc.__privileges[ServiceRtc.kPrivilegePublishAudioStream])
39
+ test.equal(pubVideoPrivilegeExpire, rtc.__privileges[ServiceRtc.kPrivilegePublishVideoStream])
40
+ test.equal(pubDataStreamPrivilegeExpire, rtc.__privileges[ServiceRtc.kPrivilegePublishDataStream])
41
+ test.equal(rtmUserId, rtm.__user_id)
42
+ test.equal(rtmTokenExpire, rtm.__privileges[ServiceRtm.kPrivilegeLogin])
43
+ test.deepEqual({}, convoai.__privileges)
44
+ test.done()
45
+ }
46
+
47
+ exports.buildToken_SUBSCRIBER_Test = function (test) {
48
+ const token = ConvoAITokenBuilder.buildToken(
49
+ appId, appCertificate, channelName, rtcAccount, Role.SUBSCRIBER, rtcTokenExpire,
50
+ joinChannelPrivilegeExpire, pubAudioPrivilegeExpire, pubVideoPrivilegeExpire,
51
+ pubDataStreamPrivilegeExpire, rtmUserId, rtmTokenExpire)
52
+ const parsed = new AccessToken2('', '', 0, 0)
53
+ parsed.from_string(token)
54
+
55
+ const rtc = parsed.getServices(kRtcServiceType)[0]
56
+ test.deepEqual({ [ServiceRtc.kPrivilegeJoinChannel]: joinChannelPrivilegeExpire }, rtc.__privileges)
57
+ test.done()
58
+ }
@@ -14,6 +14,7 @@ var r = 58964981;
14
14
  var uid=2882341273;
15
15
  var expiredTs=1446455471;
16
16
 
17
+ // Verifies deterministic public sharing key generation.
17
18
  exports.PublicSharingKey5_Test = function(test) {
18
19
  var expected = "005AwAoADc0QTk5RTVEQjI4MDk0NUI0NzUwNTk0MUFDMjM4MDU2NzIwREY3QjAQAJcMo13mDERkW7roohUGGzOwKDdW9buDA68oN1YAAA==";
19
20
  var actual = DynamicKey5.generatePublicSharingKey(appID, appCertificate, channel, ts, r, uid, expiredTs);
@@ -21,6 +22,7 @@ exports.PublicSharingKey5_Test = function(test) {
21
22
  test.done();
22
23
  };
23
24
 
25
+ // Verifies deterministic recording key generation.
24
26
  exports.RecordingKey5_Test = function(test) {
25
27
  var expected = "005AgAoADkyOUM5RTQ2MTg3QTAyMkJBQUIyNkI3QkYwMTg0MzhDNjc1Q0ZFMUEQAJcMo13mDERkW7roohUGGzOwKDdW9buDA68oN1YAAA==";
26
28
  var result = DynamicKey5.generateRecordingKey(appID, appCertificate, channel, ts, r, uid, expiredTs);
@@ -28,6 +30,7 @@ exports.RecordingKey5_Test = function(test) {
28
30
  test.done();
29
31
  };
30
32
 
33
+ // Verifies deterministic media channel key generation.
31
34
  exports.MediaChannelKey5_Test = function(test) {
32
35
  var expected = "005AQAoAEJERTJDRDdFNkZDNkU0ODYxNkYxQTYwOUVFNTM1M0U5ODNCQjFDNDQQAJcMo13mDERkW7roohUGGzOwKDdW9buDA68oN1YAAA==";
33
36
  var result = DynamicKey5.generateMediaChannelKey(appID, appCertificate, channel, ts, r, uid, expiredTs);
@@ -35,6 +38,7 @@ exports.MediaChannelKey5_Test = function(test) {
35
38
  test.done();
36
39
  };
37
40
 
41
+ // Verifies deterministic in-channel permission key generation.
38
42
  exports.InChannelPermission5_Test = function(test) {
39
43
  var noUpload = "005BAAoADgyNEQxNDE4M0FGRDkyOEQ4REFFMUU1OTg5NTg2MzA3MTEyNjRGNzQQAJcMo13mDERkW7roohUGGzOwKDdW9buDA68oN1YBAAEAAQAw";
40
44
  var generatedNoUpload = DynamicKey5.generateInChannelPermissionKey(appID, appCertificate, channel, ts, r, uid, expiredTs, DynamicKey5.noUpload);
@@ -12,18 +12,21 @@ const roomUuid = '123'
12
12
  const userUuid = '2882341273'
13
13
  const role = 1
14
14
 
15
+ // Verifies Education room-user token generation and parsing.
15
16
  exports.BuildRoomUserToken_Test = function (test) {
16
17
  let accessToken = new AccessToken2('', '', 0, 0)
17
18
  let token = EducationTokenBuilder.buildRoomUserToken(appId, appCertificate, roomUuid, userUuid, role, expire)
18
19
  accessToken.from_string(token)
20
+ const service = accessToken.getServices(kApaasServiceType)[0]
19
21
  test.equal(appId, accessToken.appId)
20
22
  test.equal(expire, accessToken.expire)
21
- test.equal(roomUuid, accessToken.services[kApaasServiceType].__room_uuid)
22
- test.equal(userUuid, accessToken.services[kApaasServiceType].__user_uuid)
23
- test.equal(role, accessToken.services[kApaasServiceType].__role)
23
+ test.equal(roomUuid, service.__room_uuid)
24
+ test.equal(userUuid, service.__user_uuid)
25
+ test.equal(role, service.__role)
24
26
  test.done()
25
27
  }
26
28
 
29
+ // Verifies Education user token generation and parsing.
27
30
  exports.BuildUserToken_Test = function (test) {
28
31
  let accessToken = new AccessToken2('', '', 0, 0)
29
32
  let token = EducationTokenBuilder.buildUserToken(appId, appCertificate, userUuid, expire)
@@ -31,10 +34,11 @@ exports.BuildUserToken_Test = function (test) {
31
34
 
32
35
  test.equal(appId, accessToken.appId)
33
36
  test.equal(expire, accessToken.expire)
34
- test.equal(userUuid, accessToken.services[kApaasServiceType].__user_uuid)
37
+ test.equal(userUuid, accessToken.getServices(kApaasServiceType)[0].__user_uuid)
35
38
  test.done()
36
39
  }
37
40
 
41
+ // Verifies Education application token generation and parsing.
38
42
  exports.BuildAppToken_Test = function (test) {
39
43
  let accessToken = new AccessToken2('', '', 0, 0)
40
44
  let token = EducationTokenBuilder.buildAppToken(appId, appCertificate, expire)