Created
May 4, 2023 14:44
-
-
Save freele/923dd195b4a2dce203b8d924989c3261 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { TelecomServerInterface } from '../../../telecom-server-interface'; | |
import { twilioEnv } from '../environment'; | |
import { jwt } from 'twilio'; | |
const AccessToken = jwt.AccessToken; | |
const { VoiceGrant, VideoGrant, TaskRouterGrant } = AccessToken; | |
const MAX_ALLOWED_SESSION_DURATION = 14400; | |
const util = jwt.taskrouter.util; | |
const TaskRouterCapability = jwt.taskrouter.TaskRouterCapability; | |
const Policy = TaskRouterCapability.Policy; | |
// To set up environmental variables, see http://twil.io/secure | |
const accountSid = twilioEnv.TWILIO_ACCOUNT_SID; | |
const authToken = twilioEnv.TWILIO_AUTH_TOKEN; | |
const workspaceSid = twilioEnv.TWILIO_TR_WORKSPACE_SID; | |
const TASKROUTER_BASE_URL = 'https://taskrouter.twilio.com'; | |
const version = 'v1'; | |
const generateTaskRouterToken = function (input: { workerSid: string }) { | |
const capability = new TaskRouterCapability({ | |
accountSid: accountSid, | |
authToken: authToken, | |
workspaceSid: workspaceSid, | |
channelId: input.workerSid, | |
}); | |
// Helper function to create Policy | |
function buildWorkspacePolicy(options?: { | |
resources?: string[]; | |
method?: string; | |
}) { | |
const resources = options?.resources || []; | |
const urlComponents = [ | |
TASKROUTER_BASE_URL, | |
version, | |
'Workspaces', | |
workspaceSid, | |
]; | |
return new Policy({ | |
url: urlComponents.concat(resources).join('/'), | |
method: options?.method || 'GET', | |
allow: true, | |
}); | |
} | |
// Event Bridge Policies | |
const workerEventBridgePolicies = util.defaultEventBridgePolicies( | |
accountSid, | |
input.workerSid | |
); | |
const workspaceEventBridgePolicies = util.defaultEventBridgePolicies( | |
accountSid, | |
workspaceSid | |
); | |
const updateActivityPolicy = new Policy({ | |
url: util.workersUrl(workspaceSid, input.workerSid), | |
method: 'POST', | |
postFilter: { ActivitySid: { required: true } }, | |
allow: true, | |
}); | |
// Worker Policies | |
const workerPolicies = util.defaultWorkerPolicies( | |
version, | |
workspaceSid, | |
input.workerSid | |
); | |
const workspacePolicies = [ | |
// Workspace fetch Policy | |
buildWorkspacePolicy(), | |
// Workspace subresources fetch Policy | |
buildWorkspacePolicy({ resources: ['**'] }), | |
// Workspace Activities Update Policy | |
buildWorkspacePolicy({ resources: ['Activities'], method: 'POST' }), | |
// Workspace Activities Worker Reservations Policy | |
buildWorkspacePolicy({ | |
resources: ['Workers', input.workerSid, 'Reservations', '**'], | |
method: 'POST', | |
}), | |
// Workspace accept reservation | |
buildWorkspacePolicy({ | |
resources: ['Tasks', '**'], | |
method: 'POST', | |
}), | |
// Workspace Activities Worker Reservations Policy | |
// buildWorkspacePolicy({ | |
// resources: ['Workers', input.workerSid, 'Activities'], | |
// method: 'POST', | |
// }), | |
]; | |
workerEventBridgePolicies | |
.concat(workspaceEventBridgePolicies) | |
.concat(updateActivityPolicy) | |
.concat(workerPolicies) | |
.concat(workspacePolicies) | |
.forEach(function (policy) { | |
capability.addPolicy(policy); | |
}); | |
return capability.toJwt(); | |
}; | |
const generateTaskRouterWorkspaceToken = function () { | |
const capability = new TaskRouterCapability({ | |
accountSid: accountSid, | |
authToken: authToken, | |
workspaceSid: workspaceSid, | |
channelId: workspaceSid, | |
}); | |
// Helper function to create Policy | |
function buildWorkspacePolicy(options?: { | |
resources?: string[]; | |
method?: string; | |
}) { | |
options = options || {}; | |
const resources = options.resources || []; | |
const urlComponents = [ | |
TASKROUTER_BASE_URL, | |
version, | |
'Workspaces', | |
workspaceSid, | |
]; | |
return new Policy({ | |
url: urlComponents.concat(resources).join('/'), | |
method: options.method || 'GET', | |
allow: true, | |
}); | |
} | |
// Event Bridge Policies | |
const eventBridgePolicies = util.defaultEventBridgePolicies( | |
accountSid, | |
workspaceSid | |
); | |
const workspacePolicies = [ | |
// Workspace Policy | |
buildWorkspacePolicy(), | |
// Workspace subresources fetch Policy | |
buildWorkspacePolicy({ resources: ['**'] }), | |
// Workspace resources update Policy | |
buildWorkspacePolicy({ resources: ['**'], method: 'POST' }), | |
// Workspace resources delete Policy | |
// buildWorkspacePolicy({ resources: ['**'], method: 'DELETE' }), | |
]; | |
eventBridgePolicies.concat(workspacePolicies).forEach((policy) => { | |
capability.addPolicy(policy); | |
}); | |
return capability.toJwt(); | |
}; | |
const generateVideoToken = function (input: { | |
userId: string; | |
organisationId: string; | |
userType: string; | |
userProfileId?: string; | |
profileFirstName?: string; | |
profileLastName?: string; | |
profileTimeZone?: string; | |
}) { | |
const token = new AccessToken( | |
twilioEnv.TWILIO_ACCOUNT_SID, | |
twilioEnv.TWILIO_API_KEY_SID, | |
twilioEnv.TWILIO_API_KEY_SECRET, | |
{ | |
ttl: MAX_ALLOWED_SESSION_DURATION, | |
} | |
); | |
// @todo find another way to store identity | |
// as we have limit or 128 characters https://www.twilio.com/docs/video/programmable-video-limits | |
token.identity = [ | |
input.userType, | |
input.organisationId, | |
input.userId, | |
`${input.profileFirstName} ${input.profileLastName}` ?? 'no name', | |
input.profileTimeZone ?? 'empty', | |
input.userProfileId, | |
].join('__'); | |
// Should never happen, but just in case. As soon as we get here, we need to fix the identity | |
if (token.identity.length > 128) { | |
throw new Error('Identity is too long. Max length is 128 characters'); | |
} | |
console.log('token.identity:', token.identity); | |
// Add video grant to token | |
token.addGrant(new VideoGrant()); | |
token.addGrant(new VoiceGrant()); | |
token.addGrant( | |
new TaskRouterGrant({ | |
role: 'worker', | |
}) | |
); | |
// Return token | |
return token.toJwt(); | |
}; | |
export const getTelecomClientCredentials: TelecomServerInterface['getTelecomClientCredentials'] = | |
function (input) { | |
return { | |
videoToken: generateVideoToken(input), | |
taskRouterWorkspaceToken: | |
input.workerSid && generateTaskRouterWorkspaceToken(), | |
taskRouterToken: | |
input.workerSid && | |
generateTaskRouterToken({ workerSid: input.workerSid }), | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment