Initial commit
This commit is contained in:
+258
@@ -0,0 +1,258 @@
|
||||
var crypto = require('crypto');
|
||||
var crc32 = require('crc-32');
|
||||
var UINT32 = require('cuint').UINT32;
|
||||
var version = "006";
|
||||
var randomInt = Math.floor(Math.random() * 0xFFFFFFFF);
|
||||
const VERSION_LENGTH = 3;
|
||||
const APP_ID_LENGTH = 32;
|
||||
|
||||
var AccessToken = function (appID, appCertificate, channelName, uid) {
|
||||
let token = this;
|
||||
this.appID = appID;
|
||||
this.appCertificate = appCertificate;
|
||||
this.channelName = channelName;
|
||||
this.messages = {};
|
||||
this.salt = randomInt;
|
||||
this.ts = Math.floor(new Date() / 1000) + (24 * 3600);
|
||||
if (uid === 0) {
|
||||
this.uid = "";
|
||||
} else {
|
||||
this.uid = `${uid}`;
|
||||
}
|
||||
|
||||
this.build = function () {
|
||||
var m = Message({
|
||||
salt: token.salt
|
||||
, ts: token.ts
|
||||
, messages: token.messages
|
||||
}).pack();
|
||||
|
||||
var toSign = Buffer.concat(
|
||||
[Buffer.from(token.appID, 'utf8'),
|
||||
Buffer.from(token.channelName, 'utf8'),
|
||||
Buffer.from(token.uid, 'utf8'),
|
||||
m]);
|
||||
|
||||
var signature = encodeHMac(token.appCertificate, toSign);
|
||||
var crc_channel = UINT32(crc32.str(token.channelName)).and(UINT32(0xffffffff)).toNumber();
|
||||
var crc_uid = UINT32(crc32.str(token.uid)).and(UINT32(0xffffffff)).toNumber();
|
||||
var content = AccessTokenContent({
|
||||
signature: signature,
|
||||
crc_channel: crc_channel,
|
||||
crc_uid: crc_uid,
|
||||
m: m
|
||||
}).pack();
|
||||
return (version + token.appID + content.toString('base64'));
|
||||
}
|
||||
|
||||
this.addPriviledge = function (priviledge, expireTimestamp) {
|
||||
token.messages[priviledge] = expireTimestamp;
|
||||
};
|
||||
|
||||
this.fromString = function (originToken) {
|
||||
try {
|
||||
originVersion = originToken.substr(0, VERSION_LENGTH);
|
||||
if(originVersion != version) {
|
||||
return false;
|
||||
}
|
||||
var originAppID = originToken.substr(VERSION_LENGTH, (VERSION_LENGTH + APP_ID_LENGTH));
|
||||
var originContent = originToken.substr((VERSION_LENGTH + APP_ID_LENGTH));
|
||||
var originContentDecodedBuf = Buffer.from(originContent, 'base64');
|
||||
|
||||
var content = unPackContent(originContentDecodedBuf);
|
||||
this.signature = content.signature;
|
||||
this.crc_channel_name = content.crc_channel_name;
|
||||
this.crc_uid = content.crc_uid;
|
||||
this.m = content.m;
|
||||
|
||||
var msgs = unPackMessages(this.m);
|
||||
this.salt = msgs.salt;
|
||||
this.ts = msgs.ts;
|
||||
this.messages = msgs.messages;
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.version = version;
|
||||
module.exports.AccessToken = AccessToken;
|
||||
module.exports.priviledges = {
|
||||
kJoinChannel: 1,
|
||||
kPublishAudioStream: 2,
|
||||
kPublishVideoStream: 3,
|
||||
kPublishDataStream: 4,
|
||||
kPublishAudiocdn: 5,
|
||||
kPublishVideoCdn: 6,
|
||||
kRequestPublishAudioStream: 7,
|
||||
kRequestPublishVideoStream: 8,
|
||||
kRequestPublishDataStream: 9,
|
||||
kInvitePublishAudioStream: 10,
|
||||
kInvitePublishVideoStream: 11,
|
||||
kInvitePublishDataStream: 12,
|
||||
kAdministrateChannel: 101,
|
||||
kRtmLogin: 1000
|
||||
};
|
||||
|
||||
var encodeHMac = function (key, message) {
|
||||
return crypto.createHmac('sha256', key).update(message).digest();
|
||||
};
|
||||
|
||||
var ByteBuf = function () {
|
||||
var that = {
|
||||
buffer: Buffer.alloc(1024)
|
||||
, position: 0
|
||||
};
|
||||
|
||||
that.buffer.fill(0);
|
||||
|
||||
that.pack = function () {
|
||||
var out = Buffer.alloc(that.position);
|
||||
that.buffer.copy(out, 0, 0, out.length);
|
||||
return out;
|
||||
};
|
||||
|
||||
that.putUint16 = function (v) {
|
||||
that.buffer.writeUInt16LE(v, that.position);
|
||||
that.position += 2;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putUint32 = function (v) {
|
||||
that.buffer.writeUInt32LE(v, that.position);
|
||||
that.position += 4;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putBytes = function (bytes) {
|
||||
that.putUint16(bytes.length);
|
||||
bytes.copy(that.buffer, that.position);
|
||||
that.position += bytes.length;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putString = function (str) {
|
||||
return that.putBytes(Buffer.from(str));
|
||||
};
|
||||
|
||||
that.putTreeMap = function (map) {
|
||||
if (!map) {
|
||||
that.putUint16(0);
|
||||
return that;
|
||||
}
|
||||
|
||||
that.putUint16(Object.keys(map).length);
|
||||
for (var key in map) {
|
||||
that.putUint16(key);
|
||||
that.putString(map[key]);
|
||||
}
|
||||
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putTreeMapUInt32 = function (map) {
|
||||
if (!map) {
|
||||
that.putUint16(0);
|
||||
return that;
|
||||
}
|
||||
|
||||
that.putUint16(Object.keys(map).length);
|
||||
for (var key in map) {
|
||||
that.putUint16(key);
|
||||
that.putUint32(map[key]);
|
||||
}
|
||||
|
||||
return that;
|
||||
};
|
||||
|
||||
return that;
|
||||
}
|
||||
|
||||
|
||||
var ReadByteBuf = function(bytes) {
|
||||
var that = {
|
||||
buffer: bytes
|
||||
, position: 0
|
||||
};
|
||||
|
||||
that.getUint16 = function () {
|
||||
var ret = that.buffer.readUInt16LE(that.position);
|
||||
that.position += 2;
|
||||
return ret;
|
||||
};
|
||||
|
||||
that.getUint32 = function () {
|
||||
var ret = that.buffer.readUInt32LE(that.position);
|
||||
that.position += 4;
|
||||
return ret;
|
||||
};
|
||||
|
||||
that.getString = function () {
|
||||
var len = that.getUint16();
|
||||
|
||||
var out = Buffer.alloc(len);
|
||||
that.buffer.copy(out, 0, that.position, (that.position + len));
|
||||
that.position += len;
|
||||
return out;
|
||||
};
|
||||
|
||||
that.getTreeMapUInt32 = function () {
|
||||
var map = {};
|
||||
var len = that.getUint16();
|
||||
for( var i = 0; i < len; i++) {
|
||||
var key = that.getUint16();
|
||||
var value = that.getUint32();
|
||||
map[key] = value;
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
||||
return that;
|
||||
}
|
||||
var AccessTokenContent = function (options) {
|
||||
options.pack = function () {
|
||||
var out = new ByteBuf();
|
||||
return out.putString(options.signature)
|
||||
.putUint32(options.crc_channel)
|
||||
.putUint32(options.crc_uid)
|
||||
.putString(options.m).pack();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
var Message = function (options) {
|
||||
options.pack = function () {
|
||||
var out = new ByteBuf();
|
||||
var val = out
|
||||
.putUint32(options.salt)
|
||||
.putUint32(options.ts)
|
||||
.putTreeMapUInt32(options.messages).pack();
|
||||
return val;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
var unPackContent = function(bytes) {
|
||||
var readbuf = new ReadByteBuf(bytes);
|
||||
return AccessTokenContent({
|
||||
signature: readbuf.getString(),
|
||||
crc_channel_name: readbuf.getUint32(),
|
||||
crc_uid: readbuf.getUint32(),
|
||||
m: readbuf.getString()
|
||||
});
|
||||
}
|
||||
|
||||
var unPackMessages = function(bytes) {
|
||||
var readbuf = new ReadByteBuf(bytes);
|
||||
return Message({
|
||||
salt: readbuf.getUint32(),
|
||||
ts: readbuf.getUint32(),
|
||||
messages: readbuf.getTreeMapUInt32()
|
||||
});
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
var crypto = require('crypto');
|
||||
|
||||
var version = "005";
|
||||
var noUpload = "0";
|
||||
var audioVideoUpload = "3";
|
||||
|
||||
var generatePublicSharingKey = function (appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs) {
|
||||
channelName=channelName.toString();
|
||||
return generateDynamicKey(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, null, PUBLIC_SHARING_SERVICE);
|
||||
};
|
||||
|
||||
var generateRecordingKey = function (appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs) {
|
||||
channelName=channelName.toString();
|
||||
return generateDynamicKey(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, null, RECORDING_SERVICE);
|
||||
};
|
||||
|
||||
var generateMediaChannelKey = function (appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs) {
|
||||
channelName=channelName.toString();
|
||||
return generateDynamicKey(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, null, MEDIA_CHANNEL_SERVICE);
|
||||
};
|
||||
|
||||
var generateInChannelPermissionKey = function (appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, permission) {
|
||||
var extra = {};
|
||||
extra[ALLOW_UPLOAD_IN_CHANNEL] = permission;
|
||||
return generateDynamicKey(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, extra, IN_CHANNEL_PERMISSION);
|
||||
};
|
||||
|
||||
var generateDynamicKey = function (appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs, extra, serviceType) {
|
||||
var signature = generateSignature5(appCertificate, serviceType, appID, unixTs, randomInt, channelName, uid, expiredTs, extra);
|
||||
var content = DynamicKey5Content({
|
||||
serviceType: serviceType
|
||||
, signature: signature
|
||||
, appID: hexDecode(appID)
|
||||
, unixTs: unixTs
|
||||
, salt: randomInt
|
||||
, expiredTs: expiredTs
|
||||
, extra: extra}).pack();
|
||||
return version + content.toString('base64');
|
||||
};
|
||||
|
||||
module.exports.version = version;
|
||||
module.exports.noUpload = noUpload;
|
||||
module.exports.audioVideoUpload = audioVideoUpload;
|
||||
module.exports.generatePublicSharingKey = generatePublicSharingKey;
|
||||
module.exports.generateRecordingKey = generateRecordingKey;
|
||||
module.exports.generateMediaChannelKey = generateMediaChannelKey;
|
||||
module.exports.generateInChannelPermissionKey = generateInChannelPermissionKey;
|
||||
module.exports.generateDynamicKey = generateDynamicKey;
|
||||
|
||||
var generateSignature5 = function(appCertificate, serviceType, appID, unixTs, randomInt, channelName, uid, expiredTs, extra) {
|
||||
// decode hex to avoid case problem
|
||||
var rawAppID = hexDecode(appID);
|
||||
var rawAppCertificate = hexDecode(appCertificate);
|
||||
|
||||
var m = Message({
|
||||
serviceType: serviceType
|
||||
, appID: rawAppID
|
||||
, unixTs: unixTs
|
||||
, salt: randomInt
|
||||
, channelName: channelName
|
||||
, uid: uid
|
||||
, expiredTs: expiredTs
|
||||
, extra: extra
|
||||
});
|
||||
|
||||
var toSign = m.pack();
|
||||
return encodeHMac(rawAppCertificate, toSign);
|
||||
};
|
||||
|
||||
var encodeHMac = function(key, message) {
|
||||
return crypto.createHmac('sha1', key).update(message).digest('hex').toUpperCase();
|
||||
};
|
||||
|
||||
var hexDecode = function(str) {
|
||||
return Buffer.from(str, 'hex');
|
||||
};
|
||||
|
||||
var ByteBuf = function() {
|
||||
var that = {
|
||||
buffer: Buffer.alloc(1024)
|
||||
, position: 0
|
||||
};
|
||||
|
||||
that.buffer.fill(0);
|
||||
|
||||
that.pack = function() {
|
||||
var out = Buffer.alloc(that.position);
|
||||
that.buffer.copy(out, 0, 0, out.length);
|
||||
return out;
|
||||
};
|
||||
|
||||
that.putUint16 = function(v) {
|
||||
that.buffer.writeUInt16LE(v, that.position);
|
||||
that.position += 2;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putUint32 = function(v) {
|
||||
that.buffer.writeUInt32LE(v, that.position);
|
||||
that.position += 4;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putBytes = function(bytes) {
|
||||
that.putUint16(bytes.length);
|
||||
bytes.copy(that.buffer, that.position);
|
||||
that.position += bytes.length;
|
||||
return that;
|
||||
};
|
||||
|
||||
that.putString = function(str) {
|
||||
return that.putBytes(Buffer.from(str));
|
||||
};
|
||||
|
||||
that.putTreeMap = function(map) {
|
||||
if (!map) {
|
||||
that.putUint16(0);
|
||||
return that;
|
||||
}
|
||||
|
||||
that.putUint16(Object.keys(map).length);
|
||||
for (var key in map) {
|
||||
that.putUint16(key);
|
||||
that.putString(map[key]);
|
||||
}
|
||||
|
||||
return that;
|
||||
};
|
||||
|
||||
return that;
|
||||
}
|
||||
|
||||
var DynamicKey5Content = function(options) {
|
||||
options.pack = function() {
|
||||
var out = ByteBuf();
|
||||
return out.putUint16(options.serviceType)
|
||||
.putString(options.signature)
|
||||
.putBytes(options.appID)
|
||||
.putUint32(options.unixTs)
|
||||
.putUint32(options.salt)
|
||||
.putUint32(options.expiredTs)
|
||||
.putTreeMap(options.extra)
|
||||
.pack();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
var Message = function(options) {
|
||||
options.pack = function() {
|
||||
var out = ByteBuf();
|
||||
return out.putUint16(options.serviceType)
|
||||
.putBytes(options.appID)
|
||||
.putUint32(options.unixTs)
|
||||
.putUint32(options.salt)
|
||||
.putString(options.channelName)
|
||||
.putUint32(options.uid)
|
||||
.putUint32(options.expiredTs)
|
||||
.putTreeMap(options.extra)
|
||||
.pack();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// InChannelPermissionKey
|
||||
var ALLOW_UPLOAD_IN_CHANNEL = 1;
|
||||
|
||||
// Service Type
|
||||
var MEDIA_CHANNEL_SERVICE = 1;
|
||||
var RECORDING_SERVICE = 2;
|
||||
var PUBLIC_SHARING_SERVICE = 3;
|
||||
var IN_CHANNEL_PERMISSION = 4;
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
const AccessToken = require('../src/AccessToken').AccessToken
|
||||
const Priviledges = require('../src/AccessToken').priviledges
|
||||
|
||||
const Role = {
|
||||
// DEPRECATED. Role::ATTENDEE has the same privileges as Role.PUBLISHER.
|
||||
ATTENDEE: 0,
|
||||
|
||||
// RECOMMENDED. Use this role for a voice/video call or a live broadcast, if your scenario does not require authentication for [Hosting-in](https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#hosting-in).
|
||||
PUBLISHER: 1,
|
||||
|
||||
/* Only use this role if your scenario require authentication for [Hosting-in](https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#hosting-in).
|
||||
* @note In order for this role to take effect, please contact our support team to enable authentication for Hosting-in for you. Otherwise, Role.SUBSCRIBER still has the same privileges as Role.PUBLISHER.
|
||||
*/
|
||||
SUBSCRIBER: 2,
|
||||
|
||||
// DEPRECATED. Role.ADMIN has the same privileges as Role.PUBLISHER.
|
||||
ADMIN: 101
|
||||
}
|
||||
|
||||
class RtcTokenBuilder {
|
||||
|
||||
/**
|
||||
* Builds an RTC token using an Integer uid.
|
||||
* @param {*} appID The App ID issued to you by Agora.
|
||||
* @param {*} appCertificate Certificate of the application that you registered in the Agora Dashboard.
|
||||
* @param {*} channelName The unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are:
|
||||
* - The 26 lowercase English letters: a to z.
|
||||
* - The 26 uppercase English letters: A to Z.
|
||||
* - The 10 digits: 0 to 9.
|
||||
* - The space.
|
||||
* - "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",".
|
||||
* @param {*} uid User ID. A 32-bit unsigned integer with a value ranging from 1 to (2^32-1).
|
||||
* @param {*} role See #userRole.
|
||||
* - Role.PUBLISHER; RECOMMENDED. Use this role for a voice/video call or a live broadcast.
|
||||
* - Role.SUBSCRIBER: ONLY use this role if your live-broadcast scenario requires authentication for [Hosting-in](https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#hosting-in). In order for this role to take effect, please contact our support team to enable authentication for Hosting-in for you. Otherwise, Role_Subscriber still has the same privileges as Role_Publisher.
|
||||
* @param {*} privilegeExpiredTs represented by the number of seconds elapsed since 1/1/1970. If, for example, you want to access the Agora Service within 10 minutes after the token is generated, set expireTimestamp as the current timestamp + 600 (seconds).
|
||||
* @return The new Token.
|
||||
*/
|
||||
static buildTokenWithUid(appID, appCertificate, channelName, uid, role, privilegeExpiredTs) {
|
||||
return this.buildTokenWithAccount(appID, appCertificate, channelName, uid, role, privilegeExpiredTs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an RTC token using an Integer uid.
|
||||
* @param {*} appID The App ID issued to you by Agora.
|
||||
* @param {*} appCertificate Certificate of the application that you registered in the Agora Dashboard.
|
||||
* @param {*} channelName The unique channel name for the AgoraRTC session in the string format. The string length must be less than 64 bytes. Supported character scopes are:
|
||||
* - The 26 lowercase English letters: a to z.
|
||||
* - The 26 uppercase English letters: A to Z.
|
||||
* - The 10 digits: 0 to 9.
|
||||
* - The space.
|
||||
* - "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ",".
|
||||
* @param {*} account The user account.
|
||||
* @param {*} role See #userRole.
|
||||
* - Role.PUBLISHER; RECOMMENDED. Use this role for a voice/video call or a live broadcast.
|
||||
* - Role.SUBSCRIBER: ONLY use this role if your live-broadcast scenario requires authentication for [Hosting-in](https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#hosting-in). In order for this role to take effect, please contact our support team to enable authentication for Hosting-in for you. Otherwise, Role_Subscriber still has the same privileges as Role_Publisher.
|
||||
* @param {*} privilegeExpiredTs represented by the number of seconds elapsed since 1/1/1970. If, for example, you want to access the Agora Service within 10 minutes after the token is generated, set expireTimestamp as the current timestamp + 600 (seconds).
|
||||
* @return The new Token.
|
||||
*/
|
||||
static buildTokenWithAccount(appID, appCertificate, channelName, account, role, privilegeExpiredTs) {
|
||||
this.key = new AccessToken(appID, appCertificate, channelName, account)
|
||||
this.key.addPriviledge(Priviledges.kJoinChannel, privilegeExpiredTs)
|
||||
if (role == Role.ATTENDEE ||
|
||||
role == Role.PUBLISHER ||
|
||||
role == Role.ADMIN) {
|
||||
this.key.addPriviledge(Priviledges.kPublishAudioStream, privilegeExpiredTs)
|
||||
this.key.addPriviledge(Priviledges.kPublishVideoStream, privilegeExpiredTs)
|
||||
this.key.addPriviledge(Priviledges.kPublishDataStream, privilegeExpiredTs)
|
||||
}
|
||||
return this.key.build();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.RtcTokenBuilder = RtcTokenBuilder;
|
||||
module.exports.Role = Role;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
const AccessToken = require("../src/AccessToken").AccessToken
|
||||
const Priviledges = require('../src/AccessToken').priviledges
|
||||
|
||||
const Role = {
|
||||
Rtm_User: 1
|
||||
}
|
||||
class RtmTokenBuilder {
|
||||
|
||||
/**
|
||||
* @param {*} appID: The App ID issued to you by Agora. Apply for a new App ID from
|
||||
* Agora Dashboard if it is missing from your kit. See Get an App ID.
|
||||
* @param {*} appCertificate: Certificate of the application that you registered in
|
||||
* the Agora Dashboard. See Get an App Certificate.
|
||||
* @param {*} account: The user account.
|
||||
* @param {*} role : Role_Publisher = 1: A broadcaster (host) in a live-broadcast profile.
|
||||
* Role_Subscriber = 2: (Default) A audience in a live-broadcast profile.
|
||||
* @param {*} privilegeExpiredTs : represented by the number of seconds elapsed since
|
||||
* 1/1/1970. If, for example, you want to access the
|
||||
* Agora Service within 10 minutes after the token is
|
||||
* generated, set expireTimestamp as the current
|
||||
* @return token
|
||||
*/
|
||||
static buildToken (appID, appCertificate, account, role, privilegeExpiredTs) {
|
||||
const key = new AccessToken(appID, appCertificate, account, "")
|
||||
key.addPriviledge(Priviledges.kRtmLogin, privilegeExpiredTs)
|
||||
return key.build()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.RtmTokenBuilder = RtmTokenBuilder
|
||||
module.exports.Role = Role
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
const md5 = require("md5");
|
||||
|
||||
var SignalingToken = {}
|
||||
|
||||
SignalingToken.get = function(appid, appcertificate, account, validTimeInSeconds){
|
||||
var expiredTime = parseInt(new Date().getTime() / 1000)+ validTimeInSeconds;
|
||||
var token_items = [];
|
||||
|
||||
//append SDK VERSION
|
||||
token_items.push("1");
|
||||
|
||||
//append appid
|
||||
token_items.push(appid);
|
||||
|
||||
//expired time
|
||||
token_items.push(expiredTime);
|
||||
|
||||
//md5 account + appid + appcertificate + expiredtime
|
||||
token_items.push(md5(account + appid + appcertificate + expiredTime));
|
||||
|
||||
return token_items.join(":");
|
||||
}
|
||||
|
||||
//convenience function to get token valid within 1 day
|
||||
SignalingToken.get1DayToken = function(appid, appcertificate, account){
|
||||
return SignalingToken.get(appid, appcertificate, account, 3600 * 24);
|
||||
}
|
||||
|
||||
module.exports = SignalingToken;
|
||||
Reference in New Issue
Block a user