jitsi-jwt.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import jwt from 'jsonwebtoken';
  2. import { config } from './config';
  3. export interface JitsiJWTPayload {
  4. context: {
  5. user: {
  6. id: string;
  7. name: string;
  8. email?: string;
  9. avatar?: string;
  10. };
  11. features?: {
  12. livestreaming?: boolean | string;
  13. recording?: boolean | string;
  14. transcription?: boolean | string;
  15. 'outbound-call'?: boolean | string;
  16. 'sip-outbound-call'?: boolean | string;
  17. };
  18. };
  19. moderator?: boolean;
  20. aud: string;
  21. iss: string;
  22. sub: string;
  23. room: string;
  24. exp?: number;
  25. nbf?: number;
  26. }
  27. /**
  28. * Genera un JWT token para autenticación en Jitsi Meet
  29. *
  30. * @param userId - ID del usuario
  31. * @param userName - Nombre completo del usuario
  32. * @param email - Email del usuario (opcional)
  33. * @param roomName - Nombre de la sala de Jitsi
  34. * @param isModerator - Si el usuario tiene permisos de moderador
  35. * @param avatarUrl - URL del avatar del usuario (opcional)
  36. * @param expiresInSeconds - Tiempo de expiración en segundos (por defecto 2 horas)
  37. * @returns JWT token firmado
  38. */
  39. export function generateJitsiToken(
  40. userId: string,
  41. userName: string,
  42. email: string | undefined,
  43. roomName: string,
  44. isModerator: boolean = false,
  45. avatarUrl?: string,
  46. expiresInSeconds: number = 7200 // 2 horas por defecto
  47. ): string {
  48. if (!config.jitsi.appId || !config.jitsi.appSecret) {
  49. throw new Error('Jitsi JWT credentials not configured');
  50. }
  51. const now = Math.floor(Date.now() / 1000);
  52. const payload: JitsiJWTPayload = {
  53. context: {
  54. user: {
  55. id: userId,
  56. name: userName,
  57. email: email,
  58. avatar: avatarUrl,
  59. },
  60. features: {
  61. livestreaming: isModerator ? 'true' : false,
  62. recording: isModerator ? 'true' : false,
  63. transcription: isModerator ? 'true' : false,
  64. },
  65. },
  66. moderator: isModerator,
  67. aud: config.jitsi.appId, // Debe coincidir con JWT_APP_ID en Jitsi
  68. iss: config.jitsi.appId, // Debe coincidir con JWT_APP_ID en Jitsi
  69. sub: config.jitsi.domain, // Tu dominio de Jitsi
  70. room: roomName,
  71. exp: now + expiresInSeconds,
  72. nbf: now - 10, // Not before: 10 segundos antes para compensar desincronización de relojes
  73. };
  74. const token = jwt.sign(payload, config.jitsi.appSecret, {
  75. algorithm: 'HS256',
  76. header: {
  77. typ: 'JWT',
  78. alg: 'HS256',
  79. },
  80. });
  81. return token;
  82. }
  83. /**
  84. * Verifica si la configuración de Jitsi JWT está completa
  85. */
  86. export function isJitsiJWTConfigured(): boolean {
  87. return !!(
  88. config.jitsi.useJWT &&
  89. config.jitsi.appId &&
  90. config.jitsi.appSecret &&
  91. config.jitsi.domain
  92. );
  93. }