livekit-client 2.6.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- {"version":3,"file":"livekit-client.e2ee.worker.js","sources":["../node_modules/.pnpm/loglevel@1.9.1/node_modules/loglevel/lib/loglevel.js","../src/logger.ts","../src/utils/AsyncQueue.ts","../node_modules/.pnpm/@livekit+mutex@1.0.0/node_modules/@livekit/mutex/dist/index.mjs","../src/e2ee/constants.ts","../src/room/errors.ts","../src/e2ee/errors.ts","../src/e2ee/events.ts","../node_modules/.pnpm/events@3.3.0/node_modules/events/events.js","../src/e2ee/utils.ts","../src/e2ee/worker/SifGuard.ts","../src/e2ee/worker/FrameCryptor.ts","../src/e2ee/worker/ParticipantKeyHandler.ts","../src/e2ee/worker/e2ee.worker.ts"],"sourcesContent":["/*\n* loglevel - https://github.com/pimterry/loglevel\n*\n* Copyright (c) 2013 Tim Perry\n* Licensed under the MIT license.\n*/\n(function (root, definition) {\n \"use strict\";\n if (typeof define === 'function' && define.amd) {\n define(definition);\n } else if (typeof module === 'object' && module.exports) {\n module.exports = definition();\n } else {\n root.log = definition();\n }\n}(this, function () {\n \"use strict\";\n\n // Slightly dubious tricks to cut down minimized file size\n var noop = function() {};\n var undefinedType = \"undefined\";\n var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (\n /Trident\\/|MSIE /.test(window.navigator.userAgent)\n );\n\n var logMethods = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\"\n ];\n\n var _loggersByName = {};\n var defaultLogger = null;\n\n // Cross-browser bind equivalent that works at least back to IE6\n function bindMethod(obj, methodName) {\n var method = obj[methodName];\n if (typeof method.bind === 'function') {\n return method.bind(obj);\n } else {\n try {\n return Function.prototype.bind.call(method, obj);\n } catch (e) {\n // Missing bind shim or IE8 + Modernizr, fallback to wrapping\n return function() {\n return Function.prototype.apply.apply(method, [obj, arguments]);\n };\n }\n }\n }\n\n // Trace() doesn't print the message in IE, so for that case we need to wrap it\n function traceForIE() {\n if (console.log) {\n if (console.log.apply) {\n console.log.apply(console, arguments);\n } else {\n // In old IE, native console methods themselves don't have apply().\n Function.prototype.apply.apply(console.log, [console, arguments]);\n }\n }\n if (console.trace) console.trace();\n }\n\n // Build the best logging method possible for this env\n // Wherever possible we want to bind, not wrap, to preserve stack traces\n function realMethod(methodName) {\n if (methodName === 'debug') {\n methodName = 'log';\n }\n\n if (typeof console === undefinedType) {\n return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives\n } else if (methodName === 'trace' && isIE) {\n return traceForIE;\n } else if (console[methodName] !== undefined) {\n return bindMethod(console, methodName);\n } else if (console.log !== undefined) {\n return bindMethod(console, 'log');\n } else {\n return noop;\n }\n }\n\n // These private functions always need `this` to be set properly\n\n function replaceLoggingMethods() {\n /*jshint validthis:true */\n var level = this.getLevel();\n\n // Replace the actual methods.\n for (var i = 0; i < logMethods.length; i++) {\n var methodName = logMethods[i];\n this[methodName] = (i < level) ?\n noop :\n this.methodFactory(methodName, level, this.name);\n }\n\n // Define log.log as an alias for log.debug\n this.log = this.debug;\n\n // Return any important warnings.\n if (typeof console === undefinedType && level < this.levels.SILENT) {\n return \"No console available for logging\";\n }\n }\n\n // In old IE versions, the console isn't present until you first open it.\n // We build realMethod() replacements here that regenerate logging methods\n function enableLoggingWhenConsoleArrives(methodName) {\n return function () {\n if (typeof console !== undefinedType) {\n replaceLoggingMethods.call(this);\n this[methodName].apply(this, arguments);\n }\n };\n }\n\n // By default, we use closely bound real methods wherever possible, and\n // otherwise we wait for a console to appear, and then try again.\n function defaultMethodFactory(methodName, _level, _loggerName) {\n /*jshint validthis:true */\n return realMethod(methodName) ||\n enableLoggingWhenConsoleArrives.apply(this, arguments);\n }\n\n function Logger(name, factory) {\n // Private instance variables.\n var self = this;\n /**\n * The level inherited from a parent logger (or a global default). We\n * cache this here rather than delegating to the parent so that it stays\n * in sync with the actual logging methods that we have installed (the\n * parent could change levels but we might not have rebuilt the loggers\n * in this child yet).\n * @type {number}\n */\n var inheritedLevel;\n /**\n * The default level for this logger, if any. If set, this overrides\n * `inheritedLevel`.\n * @type {number|null}\n */\n var defaultLevel;\n /**\n * A user-specific level for this logger. If set, this overrides\n * `defaultLevel`.\n * @type {number|null}\n */\n var userLevel;\n\n var storageKey = \"loglevel\";\n if (typeof name === \"string\") {\n storageKey += \":\" + name;\n } else if (typeof name === \"symbol\") {\n storageKey = undefined;\n }\n\n function persistLevelIfPossible(levelNum) {\n var levelName = (logMethods[levelNum] || 'silent').toUpperCase();\n\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage[storageKey] = levelName;\n return;\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=\" + levelName + \";\";\n } catch (ignore) {}\n }\n\n function getPersistedLevel() {\n var storedLevel;\n\n if (typeof window === undefinedType || !storageKey) return;\n\n try {\n storedLevel = window.localStorage[storageKey];\n } catch (ignore) {}\n\n // Fallback to cookies if local storage gives us nothing\n if (typeof storedLevel === undefinedType) {\n try {\n var cookie = window.document.cookie;\n var cookieName = encodeURIComponent(storageKey);\n var location = cookie.indexOf(cookieName + \"=\");\n if (location !== -1) {\n storedLevel = /^([^;]+)/.exec(\n cookie.slice(location + cookieName.length + 1)\n )[1];\n }\n } catch (ignore) {}\n }\n\n // If the stored level is not valid, treat it as if nothing was stored.\n if (self.levels[storedLevel] === undefined) {\n storedLevel = undefined;\n }\n\n return storedLevel;\n }\n\n function clearPersistedLevel() {\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage.removeItem(storageKey);\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=; expires=Thu, 01 Jan 1970 00:00:00 UTC\";\n } catch (ignore) {}\n }\n\n function normalizeLevel(input) {\n var level = input;\n if (typeof level === \"string\" && self.levels[level.toUpperCase()] !== undefined) {\n level = self.levels[level.toUpperCase()];\n }\n if (typeof level === \"number\" && level >= 0 && level <= self.levels.SILENT) {\n return level;\n } else {\n throw new TypeError(\"log.setLevel() called with invalid level: \" + input);\n }\n }\n\n /*\n *\n * Public logger API - see https://github.com/pimterry/loglevel for details\n *\n */\n\n self.name = name;\n\n self.levels = { \"TRACE\": 0, \"DEBUG\": 1, \"INFO\": 2, \"WARN\": 3,\n \"ERROR\": 4, \"SILENT\": 5};\n\n self.methodFactory = factory || defaultMethodFactory;\n\n self.getLevel = function () {\n if (userLevel != null) {\n return userLevel;\n } else if (defaultLevel != null) {\n return defaultLevel;\n } else {\n return inheritedLevel;\n }\n };\n\n self.setLevel = function (level, persist) {\n userLevel = normalizeLevel(level);\n if (persist !== false) { // defaults to true\n persistLevelIfPossible(userLevel);\n }\n\n // NOTE: in v2, this should call rebuild(), which updates children.\n return replaceLoggingMethods.call(self);\n };\n\n self.setDefaultLevel = function (level) {\n defaultLevel = normalizeLevel(level);\n if (!getPersistedLevel()) {\n self.setLevel(level, false);\n }\n };\n\n self.resetLevel = function () {\n userLevel = null;\n clearPersistedLevel();\n replaceLoggingMethods.call(self);\n };\n\n self.enableAll = function(persist) {\n self.setLevel(self.levels.TRACE, persist);\n };\n\n self.disableAll = function(persist) {\n self.setLevel(self.levels.SILENT, persist);\n };\n\n self.rebuild = function () {\n if (defaultLogger !== self) {\n inheritedLevel = normalizeLevel(defaultLogger.getLevel());\n }\n replaceLoggingMethods.call(self);\n\n if (defaultLogger === self) {\n for (var childName in _loggersByName) {\n _loggersByName[childName].rebuild();\n }\n }\n };\n\n // Initialize all the internal levels.\n inheritedLevel = normalizeLevel(\n defaultLogger ? defaultLogger.getLevel() : \"WARN\"\n );\n var initialLevel = getPersistedLevel();\n if (initialLevel != null) {\n userLevel = normalizeLevel(initialLevel);\n }\n replaceLoggingMethods.call(self);\n }\n\n /*\n *\n * Top-level API\n *\n */\n\n defaultLogger = new Logger();\n\n defaultLogger.getLogger = function getLogger(name) {\n if ((typeof name !== \"symbol\" && typeof name !== \"string\") || name === \"\") {\n throw new TypeError(\"You must supply a name when creating a logger.\");\n }\n\n var logger = _loggersByName[name];\n if (!logger) {\n logger = _loggersByName[name] = new Logger(\n name,\n defaultLogger.methodFactory\n );\n }\n return logger;\n };\n\n // Grab the current global log variable in case of overwrite\n var _log = (typeof window !== undefinedType) ? window.log : undefined;\n defaultLogger.noConflict = function() {\n if (typeof window !== undefinedType &&\n window.log === defaultLogger) {\n window.log = _log;\n }\n\n return defaultLogger;\n };\n\n defaultLogger.getLoggers = function getLoggers() {\n return _loggersByName;\n };\n\n // ES6 default export, for compatibility\n defaultLogger['default'] = defaultLogger;\n\n return defaultLogger;\n}));\n","import * as log from 'loglevel';\n\nexport enum LogLevel {\n trace = 0,\n debug = 1,\n info = 2,\n warn = 3,\n error = 4,\n silent = 5,\n}\n\nexport enum LoggerNames {\n Default = 'livekit',\n Room = 'livekit-room',\n Participant = 'livekit-participant',\n Track = 'livekit-track',\n Publication = 'livekit-track-publication',\n Engine = 'livekit-engine',\n Signal = 'livekit-signal',\n PCManager = 'livekit-pc-manager',\n PCTransport = 'livekit-pc-transport',\n E2EE = 'lk-e2ee',\n}\n\ntype LogLevelString = keyof typeof LogLevel;\n\nexport type StructuredLogger = log.Logger & {\n trace: (msg: string, context?: object) => void;\n debug: (msg: string, context?: object) => void;\n info: (msg: string, context?: object) => void;\n warn: (msg: string, context?: object) => void;\n error: (msg: string, context?: object) => void;\n setDefaultLevel: (level: log.LogLevelDesc) => void;\n setLevel: (level: log.LogLevelDesc) => void;\n getLevel: () => number;\n};\n\nlet livekitLogger = log.getLogger('livekit');\nconst livekitLoggers = Object.values(LoggerNames).map((name) => log.getLogger(name));\n\nlivekitLogger.setDefaultLevel(LogLevel.info);\n\nexport default livekitLogger as StructuredLogger;\n\n/**\n * @internal\n */\nexport function getLogger(name: string) {\n const logger = log.getLogger(name);\n logger.setDefaultLevel(livekitLogger.getLevel());\n return logger as StructuredLogger;\n}\n\nexport function setLogLevel(level: LogLevel | LogLevelString, loggerName?: LoggerNames) {\n if (loggerName) {\n log.getLogger(loggerName).setLevel(level);\n } else {\n for (const logger of livekitLoggers) {\n logger.setLevel(level);\n }\n }\n}\n\nexport type LogExtension = (level: LogLevel, msg: string, context?: object) => void;\n\n/**\n * use this to hook into the logging function to allow sending internal livekit logs to third party services\n * if set, the browser logs will lose their stacktrace information (see https://github.com/pimterry/loglevel#writing-plugins)\n */\nexport function setLogExtension(extension: LogExtension, logger?: StructuredLogger) {\n const loggers = logger ? [logger] : livekitLoggers;\n\n loggers.forEach((logR) => {\n const originalFactory = logR.methodFactory;\n\n logR.methodFactory = (methodName, configLevel, loggerName) => {\n const rawMethod = originalFactory(methodName, configLevel, loggerName);\n\n const logLevel = LogLevel[methodName as LogLevelString];\n const needLog = logLevel >= configLevel && logLevel < LogLevel.silent;\n\n return (msg, context?: [msg: string, context: object]) => {\n if (context) rawMethod(msg, context);\n else rawMethod(msg);\n if (needLog) {\n extension(logLevel, msg, context);\n }\n };\n };\n logR.setLevel(logR.getLevel());\n });\n}\n\nexport const workerLogger = log.getLogger('lk-e2ee') as StructuredLogger;\n","import { Mutex } from '@livekit/mutex';\n\ntype QueueTask<T> = () => PromiseLike<T>;\n\nenum QueueTaskStatus {\n 'WAITING',\n 'RUNNING',\n 'COMPLETED',\n}\n\ntype QueueTaskInfo = {\n id: number;\n enqueuedAt: number;\n executedAt?: number;\n status: QueueTaskStatus;\n};\n\nexport class AsyncQueue {\n private pendingTasks: Map<number, QueueTaskInfo>;\n\n private taskMutex: Mutex;\n\n private nextTaskIndex: number;\n\n constructor() {\n this.pendingTasks = new Map();\n this.taskMutex = new Mutex();\n this.nextTaskIndex = 0;\n }\n\n async run<T>(task: QueueTask<T>) {\n const taskInfo: QueueTaskInfo = {\n id: this.nextTaskIndex++,\n enqueuedAt: Date.now(),\n status: QueueTaskStatus.WAITING,\n };\n this.pendingTasks.set(taskInfo.id, taskInfo);\n const unlock = await this.taskMutex.lock();\n try {\n taskInfo.executedAt = Date.now();\n taskInfo.status = QueueTaskStatus.RUNNING;\n return await task();\n } finally {\n taskInfo.status = QueueTaskStatus.COMPLETED;\n this.pendingTasks.delete(taskInfo.id);\n unlock();\n }\n }\n\n async flush() {\n return this.run(async () => {});\n }\n\n snapshot() {\n return Array.from(this.pendingTasks.values());\n }\n}\n","var k = Object.defineProperty;\nvar n = (s, o, c) => o in s ? k(s, o, { enumerable: !0, configurable: !0, writable: !0, value: c }) : s[o] = c;\nvar l = (s, o, c) => n(s, typeof o != \"symbol\" ? o + \"\" : o, c);\nclass h {\n constructor() {\n l(this, \"_locking\");\n l(this, \"_locks\");\n this._locking = Promise.resolve(), this._locks = 0;\n }\n isLocked() {\n return this._locks > 0;\n }\n lock() {\n this._locks += 1;\n let o;\n const c = new Promise(\n (i) => o = () => {\n this._locks -= 1, i();\n }\n ), t = this._locking.then(() => o);\n return this._locking = this._locking.then(() => c), t;\n }\n}\nexport {\n h as Mutex\n};\n//# sourceMappingURL=index.mjs.map\n","import type { KeyProviderOptions } from './types';\n\nexport const ENCRYPTION_ALGORITHM = 'AES-GCM';\n\n// How many consecutive frames can fail decrypting before a particular key gets marked as invalid\nexport const DECRYPTION_FAILURE_TOLERANCE = 10;\n\n// We copy the first bytes of the VP8 payload unencrypted.\n// For keyframes this is 10 bytes, for non-keyframes (delta) 3. See\n// https://tools.ietf.org/html/rfc6386#section-9.1\n// This allows the bridge to continue detecting keyframes (only one byte needed in the JVB)\n// and is also a bit easier for the VP8 decoder (i.e. it generates funny garbage pictures\n// instead of being unable to decode).\n// This is a bit for show and we might want to reduce to 1 unconditionally in the final version.\n//\n// For audio (where frame.type is not set) we do not encrypt the opus TOC byte:\n// https://tools.ietf.org/html/rfc6716#section-3.1\nexport const UNENCRYPTED_BYTES = {\n key: 10,\n delta: 3,\n audio: 1, // frame.type is not set on audio, so this is set manually\n empty: 0,\n} as const;\n\n/* We use a 12 byte bit IV. This is signalled in plain together with the\n packet. See https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#parameters */\nexport const IV_LENGTH = 12;\n\n// flag set to indicate that e2ee has been setup for sender/receiver;\nexport const E2EE_FLAG = 'lk_e2ee';\n\nexport const SALT = 'LKFrameEncryptionKey';\n\nexport const KEY_PROVIDER_DEFAULTS: KeyProviderOptions = {\n sharedKey: false,\n ratchetSalt: SALT,\n ratchetWindowSize: 8,\n failureTolerance: DECRYPTION_FAILURE_TOLERANCE,\n keyringSize: 16,\n} as const;\n\nexport const MAX_SIF_COUNT = 100;\nexport const MAX_SIF_DURATION = 2000;\n","import { RequestResponse_Reason } from '@livekit/protocol';\n\nexport class LivekitError extends Error {\n code: number;\n\n constructor(code: number, message?: string) {\n super(message || 'an error has occured');\n this.code = code;\n }\n}\n\nexport const enum ConnectionErrorReason {\n NotAllowed,\n ServerUnreachable,\n InternalError,\n Cancelled,\n LeaveRequest,\n}\n\nexport class ConnectionError extends LivekitError {\n status?: number;\n\n reason?: ConnectionErrorReason;\n\n constructor(message?: string, reason?: ConnectionErrorReason, status?: number) {\n super(1, message);\n this.status = status;\n this.reason = reason;\n }\n}\n\nexport class DeviceUnsupportedError extends LivekitError {\n constructor(message?: string) {\n super(21, message ?? 'device is unsupported');\n }\n}\n\nexport class TrackInvalidError extends LivekitError {\n constructor(message?: string) {\n super(20, message ?? 'track is invalid');\n }\n}\n\nexport class UnsupportedServer extends LivekitError {\n constructor(message?: string) {\n super(10, message ?? 'unsupported server');\n }\n}\n\nexport class UnexpectedConnectionState extends LivekitError {\n constructor(message?: string) {\n super(12, message ?? 'unexpected connection state');\n }\n}\n\nexport class NegotiationError extends LivekitError {\n constructor(message?: string) {\n super(13, message ?? 'unable to negotiate');\n }\n}\n\nexport class PublishDataError extends LivekitError {\n constructor(message?: string) {\n super(13, message ?? 'unable to publish data');\n }\n}\n\nexport type RequestErrorReason =\n | Exclude<RequestResponse_Reason, RequestResponse_Reason.OK>\n | 'TimeoutError';\n\nexport class SignalRequestError extends LivekitError {\n reason: RequestErrorReason;\n\n constructor(message: string, reason: RequestErrorReason) {\n super(15, message);\n this.reason = reason;\n }\n}\n\nexport enum MediaDeviceFailure {\n // user rejected permissions\n PermissionDenied = 'PermissionDenied',\n // device is not available\n NotFound = 'NotFound',\n // device is in use. On Windows, only a single tab may get access to a device at a time.\n DeviceInUse = 'DeviceInUse',\n Other = 'Other',\n}\n\nexport namespace MediaDeviceFailure {\n export function getFailure(error: any): MediaDeviceFailure | undefined {\n if (error && 'name' in error) {\n if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {\n return MediaDeviceFailure.NotFound;\n }\n if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {\n return MediaDeviceFailure.PermissionDenied;\n }\n if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {\n return MediaDeviceFailure.DeviceInUse;\n }\n return MediaDeviceFailure.Other;\n }\n }\n}\n","import { LivekitError } from '../room/errors';\n\nexport enum CryptorErrorReason {\n InvalidKey = 0,\n MissingKey = 1,\n InternalError = 2,\n}\n\nexport class CryptorError extends LivekitError {\n reason: CryptorErrorReason;\n\n participantIdentity?: string;\n\n constructor(\n message?: string,\n reason: CryptorErrorReason = CryptorErrorReason.InternalError,\n participantIdentity?: string,\n ) {\n super(40, message);\n this.reason = reason;\n this.participantIdentity = participantIdentity;\n }\n}\n","import type Participant from '../room/participant/Participant';\nimport type { CryptorError } from './errors';\nimport type { KeyInfo } from './types';\n\nexport enum KeyProviderEvent {\n SetKey = 'setKey',\n RatchetRequest = 'ratchetRequest',\n KeyRatcheted = 'keyRatcheted',\n}\n\nexport type KeyProviderCallbacks = {\n [KeyProviderEvent.SetKey]: (keyInfo: KeyInfo) => void;\n [KeyProviderEvent.RatchetRequest]: (participantIdentity?: string, keyIndex?: number) => void;\n [KeyProviderEvent.KeyRatcheted]: (material: CryptoKey, keyIndex?: number) => void;\n};\n\nexport enum KeyHandlerEvent {\n KeyRatcheted = 'keyRatcheted',\n}\n\nexport type ParticipantKeyHandlerCallbacks = {\n [KeyHandlerEvent.KeyRatcheted]: (\n material: CryptoKey,\n participantIdentity: string,\n keyIndex?: number,\n ) => void;\n};\n\nexport enum EncryptionEvent {\n ParticipantEncryptionStatusChanged = 'participantEncryptionStatusChanged',\n EncryptionError = 'encryptionError',\n}\n\nexport type E2EEManagerCallbacks = {\n [EncryptionEvent.ParticipantEncryptionStatusChanged]: (\n enabled: boolean,\n participant: Participant,\n ) => void;\n [EncryptionEvent.EncryptionError]: (error: Error) => void;\n};\n\nexport type CryptorCallbacks = {\n [CryptorEvent.Error]: (error: CryptorError) => void;\n};\n\nexport enum CryptorEvent {\n Error = 'cryptorError',\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n","import { ENCRYPTION_ALGORITHM } from './constants';\n\nexport function isE2EESupported() {\n return isInsertableStreamSupported() || isScriptTransformSupported();\n}\n\nexport function isScriptTransformSupported() {\n // @ts-ignore\n return typeof window.RTCRtpScriptTransform !== 'undefined';\n}\n\nexport function isInsertableStreamSupported() {\n return (\n typeof window.RTCRtpSender !== 'undefined' &&\n // @ts-ignore\n typeof window.RTCRtpSender.prototype.createEncodedStreams !== 'undefined'\n );\n}\n\nexport function isVideoFrame(\n frame: RTCEncodedAudioFrame | RTCEncodedVideoFrame,\n): frame is RTCEncodedVideoFrame {\n return 'type' in frame;\n}\n\nexport async function importKey(\n keyBytes: Uint8Array | ArrayBuffer,\n algorithm: string | { name: string } = { name: ENCRYPTION_ALGORITHM },\n usage: 'derive' | 'encrypt' = 'encrypt',\n) {\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey\n return crypto.subtle.importKey(\n 'raw',\n keyBytes,\n algorithm,\n false,\n usage === 'derive' ? ['deriveBits', 'deriveKey'] : ['encrypt', 'decrypt'],\n );\n}\n\nexport async function createKeyMaterialFromString(password: string) {\n let enc = new TextEncoder();\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n enc.encode(password),\n {\n name: 'PBKDF2',\n },\n false,\n ['deriveBits', 'deriveKey'],\n );\n\n return keyMaterial;\n}\n\nexport async function createKeyMaterialFromBuffer(cryptoBuffer: ArrayBuffer) {\n const keyMaterial = await crypto.subtle.importKey('raw', cryptoBuffer, 'HKDF', false, [\n 'deriveBits',\n 'deriveKey',\n ]);\n\n return keyMaterial;\n}\n\nfunction getAlgoOptions(algorithmName: string, salt: string) {\n const textEncoder = new TextEncoder();\n const encodedSalt = textEncoder.encode(salt);\n switch (algorithmName) {\n case 'HKDF':\n return {\n name: 'HKDF',\n salt: encodedSalt,\n hash: 'SHA-256',\n info: new ArrayBuffer(128),\n };\n case 'PBKDF2': {\n return {\n name: 'PBKDF2',\n salt: encodedSalt,\n hash: 'SHA-256',\n iterations: 100000,\n };\n }\n default:\n throw new Error(`algorithm ${algorithmName} is currently unsupported`);\n }\n}\n\n/**\n * Derives a set of keys from the master key.\n * See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1\n */\nexport async function deriveKeys(material: CryptoKey, salt: string) {\n const algorithmOptions = getAlgoOptions(material.algorithm.name, salt);\n\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF\n // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams\n const encryptionKey = await crypto.subtle.deriveKey(\n algorithmOptions,\n material,\n {\n name: ENCRYPTION_ALGORITHM,\n length: 128,\n },\n false,\n ['encrypt', 'decrypt'],\n );\n\n return { material, encryptionKey };\n}\n\nexport function createE2EEKey(): Uint8Array {\n return window.crypto.getRandomValues(new Uint8Array(32));\n}\n\n/**\n * Ratchets a key. See\n * https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1\n */\nexport async function ratchet(material: CryptoKey, salt: string): Promise<ArrayBuffer> {\n const algorithmOptions = getAlgoOptions(material.algorithm.name, salt);\n\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits\n return crypto.subtle.deriveBits(algorithmOptions, material, 256);\n}\n\nexport function needsRbspUnescaping(frameData: Uint8Array) {\n for (var i = 0; i < frameData.length - 3; i++) {\n if (frameData[i] == 0 && frameData[i + 1] == 0 && frameData[i + 2] == 3) return true;\n }\n return false;\n}\n\nexport function parseRbsp(stream: Uint8Array): Uint8Array {\n const dataOut: number[] = [];\n var length = stream.length;\n for (var i = 0; i < stream.length; ) {\n // Be careful about over/underflow here. byte_length_ - 3 can underflow, and\n // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_\n // above, and that expression will produce the number of bytes left in\n // the stream including the byte at i.\n if (length - i >= 3 && !stream[i] && !stream[i + 1] && stream[i + 2] == 3) {\n // Two rbsp bytes.\n dataOut.push(stream[i++]);\n dataOut.push(stream[i++]);\n // Skip the emulation byte.\n i++;\n } else {\n // Single rbsp byte.\n dataOut.push(stream[i++]);\n }\n }\n return new Uint8Array(dataOut);\n}\n\nconst kZerosInStartSequence = 2;\nconst kEmulationByte = 3;\n\nexport function writeRbsp(data_in: Uint8Array): Uint8Array {\n const dataOut: number[] = [];\n var numConsecutiveZeros = 0;\n for (var i = 0; i < data_in.length; ++i) {\n var byte = data_in[i];\n if (byte <= kEmulationByte && numConsecutiveZeros >= kZerosInStartSequence) {\n // Need to escape.\n dataOut.push(kEmulationByte);\n numConsecutiveZeros = 0;\n }\n dataOut.push(byte);\n if (byte == 0) {\n ++numConsecutiveZeros;\n } else {\n numConsecutiveZeros = 0;\n }\n }\n return new Uint8Array(dataOut);\n}\n","import { MAX_SIF_COUNT, MAX_SIF_DURATION } from '../constants';\n\nexport class SifGuard {\n private consecutiveSifCount = 0;\n\n private sifSequenceStartedAt: number | undefined;\n\n private lastSifReceivedAt: number = 0;\n\n private userFramesSinceSif: number = 0;\n\n recordSif() {\n this.consecutiveSifCount += 1;\n this.sifSequenceStartedAt ??= Date.now();\n this.lastSifReceivedAt = Date.now();\n }\n\n recordUserFrame() {\n if (this.sifSequenceStartedAt === undefined) {\n return;\n } else {\n this.userFramesSinceSif += 1;\n }\n if (\n // reset if we received more user frames than SIFs\n this.userFramesSinceSif > this.consecutiveSifCount ||\n // also reset if we got a new user frame and the latest SIF frame hasn't been updated in a while\n Date.now() - this.lastSifReceivedAt > MAX_SIF_DURATION\n ) {\n this.reset();\n }\n }\n\n isSifAllowed() {\n return (\n this.consecutiveSifCount < MAX_SIF_COUNT &&\n (this.sifSequenceStartedAt === undefined ||\n Date.now() - this.sifSequenceStartedAt < MAX_SIF_DURATION)\n );\n }\n\n reset() {\n this.userFramesSinceSif = 0;\n this.consecutiveSifCount = 0;\n this.sifSequenceStartedAt = undefined;\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n// TODO code inspired by https://github.com/webrtc/samples/blob/gh-pages/src/content/insertable-streams/endtoend-encryption/js/worker.js\nimport { EventEmitter } from 'events';\nimport type TypedEventEmitter from 'typed-emitter';\nimport { workerLogger } from '../../logger';\nimport type { VideoCodec } from '../../room/track/options';\nimport { ENCRYPTION_ALGORITHM, IV_LENGTH, UNENCRYPTED_BYTES } from '../constants';\nimport { CryptorError, CryptorErrorReason } from '../errors';\nimport { type CryptorCallbacks, CryptorEvent } from '../events';\nimport type { DecodeRatchetOptions, KeyProviderOptions, KeySet } from '../types';\nimport { deriveKeys, isVideoFrame, needsRbspUnescaping, parseRbsp, writeRbsp } from '../utils';\nimport type { ParticipantKeyHandler } from './ParticipantKeyHandler';\nimport { SifGuard } from './SifGuard';\n\nexport const encryptionEnabledMap: Map<string, boolean> = new Map();\n\nexport interface FrameCryptorConstructor {\n new (opts?: unknown): BaseFrameCryptor;\n}\n\nexport interface TransformerInfo {\n readable: ReadableStream;\n writable: WritableStream;\n transformer: TransformStream;\n abortController: AbortController;\n}\n\nexport class BaseFrameCryptor extends (EventEmitter as new () => TypedEventEmitter<CryptorCallbacks>) {\n protected encodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ): Promise<any> {\n throw Error('not implemented for subclass');\n }\n\n protected decodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ): Promise<any> {\n throw Error('not implemented for subclass');\n }\n}\n\n/**\n * Cryptor is responsible for en-/decrypting media frames.\n * Each Cryptor instance is responsible for en-/decrypting a single mediaStreamTrack.\n */\nexport class FrameCryptor extends BaseFrameCryptor {\n private sendCounts: Map<number, number>;\n\n private participantIdentity: string | undefined;\n\n private trackId: string | undefined;\n\n private keys: ParticipantKeyHandler;\n\n private videoCodec?: VideoCodec;\n\n private rtpMap: Map<number, VideoCodec>;\n\n private keyProviderOptions: KeyProviderOptions;\n\n /**\n * used for detecting server injected unencrypted frames\n */\n private sifTrailer: Uint8Array;\n\n private sifGuard: SifGuard;\n\n private detectedCodec?: VideoCodec;\n\n constructor(opts: {\n keys: ParticipantKeyHandler;\n participantIdentity: string;\n keyProviderOptions: KeyProviderOptions;\n sifTrailer?: Uint8Array;\n }) {\n super();\n this.sendCounts = new Map();\n this.keys = opts.keys;\n this.participantIdentity = opts.participantIdentity;\n this.rtpMap = new Map();\n this.keyProviderOptions = opts.keyProviderOptions;\n this.sifTrailer = opts.sifTrailer ?? Uint8Array.from([]);\n this.sifGuard = new SifGuard();\n }\n\n private get logContext() {\n return {\n participant: this.participantIdentity,\n mediaTrackId: this.trackId,\n fallbackCodec: this.videoCodec,\n };\n }\n\n /**\n * Assign a different participant to the cryptor.\n * useful for transceiver re-use\n * @param id\n * @param keys\n */\n setParticipant(id: string, keys: ParticipantKeyHandler) {\n workerLogger.debug('setting new participant on cryptor', {\n ...this.logContext,\n participant: id,\n });\n if (this.participantIdentity) {\n workerLogger.error(\n 'cryptor has already a participant set, participant should have been unset before',\n {\n ...this.logContext,\n },\n );\n }\n this.participantIdentity = id;\n this.keys = keys;\n this.sifGuard.reset();\n }\n\n unsetParticipant() {\n workerLogger.debug('unsetting participant', this.logContext);\n this.participantIdentity = undefined;\n }\n\n isEnabled() {\n if (this.participantIdentity) {\n return encryptionEnabledMap.get(this.participantIdentity);\n } else {\n return undefined;\n }\n }\n\n getParticipantIdentity() {\n return this.participantIdentity;\n }\n\n getTrackId() {\n return this.trackId;\n }\n\n /**\n * Update the video codec used by the mediaStreamTrack\n * @param codec\n */\n setVideoCodec(codec: VideoCodec) {\n this.videoCodec = codec;\n }\n\n /**\n * rtp payload type map used for figuring out codec of payload type when encoding\n * @param map\n */\n setRtpMap(map: Map<number, VideoCodec>) {\n this.rtpMap = map;\n }\n\n setupTransform(\n operation: 'encode' | 'decode',\n readable: ReadableStream<RTCEncodedVideoFrame | RTCEncodedAudioFrame>,\n writable: WritableStream<RTCEncodedVideoFrame | RTCEncodedAudioFrame>,\n trackId: string,\n codec?: VideoCodec,\n ) {\n if (codec) {\n workerLogger.info('setting codec on cryptor to', { codec });\n this.videoCodec = codec;\n }\n\n workerLogger.debug('Setting up frame cryptor transform', {\n operation,\n passedTrackId: trackId,\n codec,\n ...this.logContext,\n });\n\n const transformFn = operation === 'encode' ? this.encodeFunction : this.decodeFunction;\n const transformStream = new TransformStream({\n transform: transformFn.bind(this),\n });\n\n readable\n .pipeThrough(transformStream)\n .pipeTo(writable)\n .catch((e) => {\n workerLogger.warn(e);\n this.emit(\n CryptorEvent.Error,\n e instanceof CryptorError\n ? e\n : new CryptorError(e.message, undefined, this.participantIdentity),\n );\n });\n this.trackId = trackId;\n }\n\n setSifTrailer(trailer: Uint8Array) {\n workerLogger.debug('setting SIF trailer', { ...this.logContext, trailer });\n this.sifTrailer = trailer;\n }\n\n /**\n * Function that will be injected in a stream and will encrypt the given encoded frames.\n *\n * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame.\n * @param {TransformStreamDefaultController} controller - TransportStreamController.\n *\n * The VP8 payload descriptor described in\n * https://tools.ietf.org/html/rfc7741#section-4.2\n * is part of the RTP packet and not part of the frame and is not controllable by us.\n * This is fine as the SFU keeps having access to it for routing.\n *\n * The encrypted frame is formed as follows:\n * 1) Find unencrypted byte length, depending on the codec, frame type and kind.\n * 2) Form the GCM IV for the frame as described above.\n * 3) Encrypt the rest of the frame using AES-GCM.\n * 4) Allocate space for the encrypted frame.\n * 5) Copy the unencrypted bytes to the start of the encrypted frame.\n * 6) Append the ciphertext to the encrypted frame.\n * 7) Append the IV.\n * 8) Append a single byte for the key identifier.\n * 9) Enqueue the encrypted frame for sending.\n */\n protected async encodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ) {\n if (\n !this.isEnabled() ||\n // skip for encryption for empty dtx frames\n encodedFrame.data.byteLength === 0\n ) {\n return controller.enqueue(encodedFrame);\n }\n const keySet = this.keys.getKeySet();\n if (!keySet) {\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `key set not found for ${\n this.participantIdentity\n } at index ${this.keys.getCurrentKeyIndex()}`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n return;\n }\n const { encryptionKey } = keySet;\n const keyIndex = this.keys.getCurrentKeyIndex();\n\n if (encryptionKey) {\n const iv = this.makeIV(\n encodedFrame.getMetadata().synchronizationSource ?? -1,\n encodedFrame.timestamp,\n );\n let frameInfo = this.getUnencryptedBytes(encodedFrame);\n\n // Thіs is not encrypted and contains the VP8 payload descriptor or the Opus TOC byte.\n const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);\n\n // Frame trailer contains the R|IV_LENGTH and key index\n const frameTrailer = new Uint8Array(2);\n\n frameTrailer[0] = IV_LENGTH;\n frameTrailer[1] = keyIndex;\n\n // Construct frame trailer. Similar to the frame header described in\n // https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2\n // but we put it at the end.\n //\n // ---------+-------------------------+-+---------+----\n // payload |IV...(length = IV_LENGTH)|R|IV_LENGTH|KID |\n // ---------+-------------------------+-+---------+----\n try {\n const cipherText = await crypto.subtle.encrypt(\n {\n name: ENCRYPTION_ALGORITHM,\n iv,\n additionalData: new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength),\n },\n encryptionKey,\n new Uint8Array(encodedFrame.data, frameInfo.unencryptedBytes),\n );\n\n let newDataWithoutHeader = new Uint8Array(\n cipherText.byteLength + iv.byteLength + frameTrailer.byteLength,\n );\n newDataWithoutHeader.set(new Uint8Array(cipherText)); // add ciphertext.\n newDataWithoutHeader.set(new Uint8Array(iv), cipherText.byteLength); // append IV.\n newDataWithoutHeader.set(frameTrailer, cipherText.byteLength + iv.byteLength); // append frame trailer.\n\n if (frameInfo.isH264) {\n newDataWithoutHeader = writeRbsp(newDataWithoutHeader);\n }\n\n var newData = new Uint8Array(frameHeader.byteLength + newDataWithoutHeader.byteLength);\n newData.set(frameHeader);\n newData.set(newDataWithoutHeader, frameHeader.byteLength);\n\n encodedFrame.data = newData.buffer;\n\n return controller.enqueue(encodedFrame);\n } catch (e: any) {\n // TODO: surface this to the app.\n workerLogger.error(e);\n }\n } else {\n workerLogger.debug('failed to encrypt, emitting error', this.logContext);\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `encryption key missing for encoding`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n }\n }\n\n /**\n * Function that will be injected in a stream and will decrypt the given encoded frames.\n *\n * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame.\n * @param {TransformStreamDefaultController} controller - TransportStreamController.\n */\n protected async decodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ) {\n if (\n !this.isEnabled() ||\n // skip for decryption for empty dtx frames\n encodedFrame.data.byteLength === 0\n ) {\n workerLogger.debug('skipping empty frame', this.logContext);\n this.sifGuard.recordUserFrame();\n return controller.enqueue(encodedFrame);\n }\n\n if (isFrameServerInjected(encodedFrame.data, this.sifTrailer)) {\n workerLogger.debug('enqueue SIF', this.logContext);\n this.sifGuard.recordSif();\n\n if (this.sifGuard.isSifAllowed()) {\n encodedFrame.data = encodedFrame.data.slice(\n 0,\n encodedFrame.data.byteLength - this.sifTrailer.byteLength,\n );\n return controller.enqueue(encodedFrame);\n } else {\n workerLogger.warn('SIF limit reached, dropping frame');\n return;\n }\n } else {\n this.sifGuard.recordUserFrame();\n }\n const data = new Uint8Array(encodedFrame.data);\n const keyIndex = data[encodedFrame.data.byteLength - 1];\n\n if (this.keys.hasInvalidKeyAtIndex(keyIndex)) {\n // drop frame\n return;\n }\n\n if (this.keys.getKeySet(keyIndex)) {\n try {\n const decodedFrame = await this.decryptFrame(encodedFrame, keyIndex);\n this.keys.decryptionSuccess(keyIndex);\n if (decodedFrame) {\n return controller.enqueue(decodedFrame);\n }\n } catch (error) {\n if (error instanceof CryptorError && error.reason === CryptorErrorReason.InvalidKey) {\n // emit an error if the key handler thinks we have a valid key\n if (this.keys.hasValidKey) {\n this.emit(CryptorEvent.Error, error);\n this.keys.decryptionFailure(keyIndex);\n }\n } else {\n workerLogger.warn('decoding frame failed', { error });\n }\n }\n } else {\n // emit an error if the key index is out of bounds but the key handler thinks we still have a valid key\n workerLogger.warn(`skipping decryption due to missing key at index ${keyIndex}`);\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `missing key at index ${keyIndex} for participant ${this.participantIdentity}`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n this.keys.decryptionFailure(keyIndex);\n }\n }\n\n /**\n * Function that will decrypt the given encoded frame. If the decryption fails, it will\n * ratchet the key for up to RATCHET_WINDOW_SIZE times.\n */\n private async decryptFrame(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n keyIndex: number,\n initialMaterial: KeySet | undefined = undefined,\n ratchetOpts: DecodeRatchetOptions = { ratchetCount: 0 },\n ): Promise<RTCEncodedVideoFrame | RTCEncodedAudioFrame | undefined> {\n const keySet = this.keys.getKeySet(keyIndex);\n if (!ratchetOpts.encryptionKey && !keySet) {\n throw new TypeError(`no encryption key found for decryption of ${this.participantIdentity}`);\n }\n let frameInfo = this.getUnencryptedBytes(encodedFrame);\n\n // Construct frame trailer. Similar to the frame header described in\n // https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2\n // but we put it at the end.\n //\n // ---------+-------------------------+-+---------+----\n // payload |IV...(length = IV_LENGTH)|R|IV_LENGTH|KID |\n // ---------+-------------------------+-+---------+----\n\n try {\n const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);\n var encryptedData = new Uint8Array(\n encodedFrame.data,\n frameHeader.length,\n encodedFrame.data.byteLength - frameHeader.length,\n );\n if (frameInfo.isH264 && needsRbspUnescaping(encryptedData)) {\n encryptedData = parseRbsp(encryptedData);\n const newUint8 = new Uint8Array(frameHeader.byteLength + encryptedData.byteLength);\n newUint8.set(frameHeader);\n newUint8.set(encryptedData, frameHeader.byteLength);\n encodedFrame.data = newUint8.buffer;\n }\n\n const frameTrailer = new Uint8Array(encodedFrame.data, encodedFrame.data.byteLength - 2, 2);\n\n const ivLength = frameTrailer[0];\n const iv = new Uint8Array(\n encodedFrame.data,\n encodedFrame.data.byteLength - ivLength - frameTrailer.byteLength,\n ivLength,\n );\n\n const cipherTextStart = frameHeader.byteLength;\n const cipherTextLength =\n encodedFrame.data.byteLength -\n (frameHeader.byteLength + ivLength + frameTrailer.byteLength);\n\n const plainText = await crypto.subtle.decrypt(\n {\n name: ENCRYPTION_ALGORITHM,\n iv,\n additionalData: new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength),\n },\n ratchetOpts.encryptionKey ?? keySet!.encryptionKey,\n new Uint8Array(encodedFrame.data, cipherTextStart, cipherTextLength),\n );\n\n const newData = new ArrayBuffer(frameHeader.byteLength + plainText.byteLength);\n const newUint8 = new Uint8Array(newData);\n\n newUint8.set(new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength));\n newUint8.set(new Uint8Array(plainText), frameHeader.byteLength);\n\n encodedFrame.data = newData;\n\n return encodedFrame;\n } catch (error: any) {\n if (this.keyProviderOptions.ratchetWindowSize > 0) {\n if (ratchetOpts.ratchetCount < this.keyProviderOptions.ratchetWindowSize) {\n workerLogger.debug(\n `ratcheting key attempt ${ratchetOpts.ratchetCount} of ${\n this.keyProviderOptions.ratchetWindowSize\n }, for kind ${encodedFrame instanceof RTCEncodedAudioFrame ? 'audio' : 'video'}`,\n );\n\n let ratchetedKeySet: KeySet | undefined;\n if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {\n // only ratchet if the currently set key is still the same as the one used to decrypt this frame\n // if not, it might be that a different frame has already ratcheted and we try with that one first\n const newMaterial = await this.keys.ratchetKey(keyIndex, false);\n\n ratchetedKeySet = await deriveKeys(newMaterial, this.keyProviderOptions.ratchetSalt);\n }\n\n const frame = await this.decryptFrame(encodedFrame, keyIndex, initialMaterial || keySet, {\n ratchetCount: ratchetOpts.ratchetCount + 1,\n encryptionKey: ratchetedKeySet?.encryptionKey,\n });\n if (frame && ratchetedKeySet) {\n // before updating the keys, make sure that the keySet used for this frame is still the same as the currently set key\n // if it's not, a new key might have been set already, which we don't want to override\n if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {\n this.keys.setKeySet(ratchetedKeySet, keyIndex, true);\n // decryption was successful, set the new key index to reflect the ratcheted key set\n this.keys.setCurrentKeyIndex(keyIndex);\n }\n }\n return frame;\n } else {\n /**\n * Because we only set a new key once decryption has been successful,\n * we can be sure that we don't need to reset the key to the initial material at this point\n * as the key has not been updated on the keyHandler instance\n */\n\n workerLogger.warn('maximum ratchet attempts exceeded');\n throw new CryptorError(\n `valid key missing for participant ${this.participantIdentity}`,\n CryptorErrorReason.InvalidKey,\n this.participantIdentity,\n );\n }\n } else {\n throw new CryptorError(\n `Decryption failed: ${error.message}`,\n CryptorErrorReason.InvalidKey,\n this.participantIdentity,\n );\n }\n }\n }\n\n /**\n * Construct the IV used for AES-GCM and sent (in plain) with the packet similar to\n * https://tools.ietf.org/html/rfc7714#section-8.1\n * It concatenates\n * - the 32 bit synchronization source (SSRC) given on the encoded frame,\n * - the 32 bit rtp timestamp given on the encoded frame,\n * - a send counter that is specific to the SSRC. Starts at a random number.\n * The send counter is essentially the pictureId but we currently have to implement this ourselves.\n * There is no XOR with a salt. Note that this IV leaks the SSRC to the receiver but since this is\n * randomly generated and SFUs may not rewrite this is considered acceptable.\n * The SSRC is used to allow demultiplexing multiple streams with the same key, as described in\n * https://tools.ietf.org/html/rfc3711#section-4.1.1\n * The RTP timestamp is 32 bits and advances by the codec clock rate (90khz for video, 48khz for\n * opus audio) every second. For video it rolls over roughly every 13 hours.\n * The send counter will advance at the frame rate (30fps for video, 50fps for 20ms opus audio)\n * every second. It will take a long time to roll over.\n *\n * See also https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams\n */\n private makeIV(synchronizationSource: number, timestamp: number) {\n const iv = new ArrayBuffer(IV_LENGTH);\n const ivView = new DataView(iv);\n\n // having to keep our own send count (similar to a picture id) is not ideal.\n if (!this.sendCounts.has(synchronizationSource)) {\n // Initialize with a random offset, similar to the RTP sequence number.\n this.sendCounts.set(synchronizationSource, Math.floor(Math.random() * 0xffff));\n }\n\n const sendCount = this.sendCounts.get(synchronizationSource) ?? 0;\n\n ivView.setUint32(0, synchronizationSource);\n ivView.setUint32(4, timestamp);\n ivView.setUint32(8, timestamp - (sendCount % 0xffff));\n\n this.sendCounts.set(synchronizationSource, sendCount + 1);\n\n return iv;\n }\n\n private getUnencryptedBytes(frame: RTCEncodedVideoFrame | RTCEncodedAudioFrame): {\n unencryptedBytes: number;\n isH264: boolean;\n } {\n var frameInfo = { unencryptedBytes: 0, isH264: false };\n if (isVideoFrame(frame)) {\n let detectedCodec = this.getVideoCodec(frame) ?? this.videoCodec;\n if (detectedCodec !== this.detectedCodec) {\n workerLogger.debug('detected different codec', {\n detectedCodec,\n oldCodec: this.detectedCodec,\n ...this.logContext,\n });\n this.detectedCodec = detectedCodec;\n }\n\n if (detectedCodec === 'av1') {\n throw new Error(`${detectedCodec} is not yet supported for end to end encryption`);\n }\n\n if (detectedCodec === 'vp8') {\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];\n } else if (detectedCodec === 'vp9') {\n frameInfo.unencryptedBytes = 0;\n return frameInfo;\n }\n\n const data = new Uint8Array(frame.data);\n try {\n const naluIndices = findNALUIndices(data);\n\n // if the detected codec is undefined we test whether it _looks_ like a h264 frame as a best guess\n frameInfo.isH264 =\n detectedCodec === 'h264' ||\n naluIndices.some((naluIndex) =>\n [NALUType.SLICE_IDR, NALUType.SLICE_NON_IDR].includes(parseNALUType(data[naluIndex])),\n );\n\n if (frameInfo.isH264) {\n for (const index of naluIndices) {\n let type = parseNALUType(data[index]);\n switch (type) {\n case NALUType.SLICE_IDR:\n case NALUType.SLICE_NON_IDR:\n frameInfo.unencryptedBytes = index + 2;\n return frameInfo;\n default:\n break;\n }\n }\n throw new TypeError('Could not find NALU');\n }\n } catch (e) {\n // no op, we just continue and fallback to vp8\n }\n\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];\n return frameInfo;\n } else {\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES.audio;\n return frameInfo;\n }\n }\n\n /**\n * inspects frame payloadtype if available and maps it to the codec specified in rtpMap\n */\n private getVideoCodec(frame: RTCEncodedVideoFrame): VideoCodec | undefined {\n if (this.rtpMap.size === 0) {\n return undefined;\n }\n const payloadType = frame.getMetadata().payloadType;\n const codec = payloadType ? this.rtpMap.get(payloadType) : undefined;\n return codec;\n }\n}\n\n/**\n * Slice the NALUs present in the supplied buffer, assuming it is already byte-aligned\n * code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only\n */\nexport function findNALUIndices(stream: Uint8Array): number[] {\n const result: number[] = [];\n let start = 0,\n pos = 0,\n searchLength = stream.length - 2;\n while (pos < searchLength) {\n // skip until end of current NALU\n while (\n pos < searchLength &&\n !(stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 1)\n )\n pos++;\n if (pos >= searchLength) pos = stream.length;\n // remove trailing zeros from current NALU\n let end = pos;\n while (end > start && stream[end - 1] === 0) end--;\n // save current NALU\n if (start === 0) {\n if (end !== start) throw TypeError('byte stream contains leading data');\n } else {\n result.push(start);\n }\n // begin new NALU\n start = pos = pos + 3;\n }\n return result;\n}\n\nexport function parseNALUType(startByte: number): NALUType {\n return startByte & kNaluTypeMask;\n}\n\nconst kNaluTypeMask = 0x1f;\n\nexport enum NALUType {\n /** Coded slice of a non-IDR picture */\n SLICE_NON_IDR = 1,\n /** Coded slice data partition A */\n SLICE_PARTITION_A = 2,\n /** Coded slice data partition B */\n SLICE_PARTITION_B = 3,\n /** Coded slice data partition C */\n SLICE_PARTITION_C = 4,\n /** Coded slice of an IDR picture */\n SLICE_IDR = 5,\n /** Supplemental enhancement information */\n SEI = 6,\n /** Sequence parameter set */\n SPS = 7,\n /** Picture parameter set */\n PPS = 8,\n /** Access unit delimiter */\n AUD = 9,\n /** End of sequence */\n END_SEQ = 10,\n /** End of stream */\n END_STREAM = 11,\n /** Filler data */\n FILLER_DATA = 12,\n /** Sequence parameter set extension */\n SPS_EXT = 13,\n /** Prefix NAL unit */\n PREFIX_NALU = 14,\n /** Subset sequence parameter set */\n SUBSET_SPS = 15,\n /** Depth parameter set */\n DPS = 16,\n\n // 17, 18 reserved\n\n /** Coded slice of an auxiliary coded picture without partitioning */\n SLICE_AUX = 19,\n /** Coded slice extension */\n SLICE_EXT = 20,\n /** Coded slice extension for a depth view component or a 3D-AVC texture view component */\n SLICE_LAYER_EXT = 21,\n\n // 22, 23 reserved\n}\n\n/**\n * we use a magic frame trailer to detect whether a frame is injected\n * by the livekit server and thus to be treated as unencrypted\n * @internal\n */\nexport function isFrameServerInjected(frameData: ArrayBuffer, trailerBytes: Uint8Array): boolean {\n if (trailerBytes.byteLength === 0) {\n return false;\n }\n const frameTrailer = new Uint8Array(\n frameData.slice(frameData.byteLength - trailerBytes.byteLength),\n );\n return trailerBytes.every((value, index) => value === frameTrailer[index]);\n}\n","import { EventEmitter } from 'events';\nimport type TypedEventEmitter from 'typed-emitter';\nimport { workerLogger } from '../../logger';\nimport { KeyHandlerEvent, type ParticipantKeyHandlerCallbacks } from '../events';\nimport type { KeyProviderOptions, KeySet } from '../types';\nimport { deriveKeys, importKey, ratchet } from '../utils';\n\n// TODO ParticipantKeyHandlers currently don't get destroyed on participant disconnect\n// we could do this by having a separate worker message on participant disconnected.\n\n/**\n * ParticipantKeyHandler is responsible for providing a cryptor instance with the\n * en-/decryption key of a participant. It assumes that all tracks of a specific participant\n * are encrypted with the same key.\n * Additionally it exposes a method to ratchet a key which can be used by the cryptor either automatically\n * if decryption fails or can be triggered manually on both sender and receiver side.\n *\n */\nexport class ParticipantKeyHandler extends (EventEmitter as new () => TypedEventEmitter<ParticipantKeyHandlerCallbacks>) {\n private currentKeyIndex: number;\n\n private cryptoKeyRing: Array<KeySet | undefined>;\n\n private decryptionFailureCounts: Array<number>;\n\n private keyProviderOptions: KeyProviderOptions;\n\n private ratchetPromiseMap: Map<number, Promise<CryptoKey>>;\n\n private participantIdentity: string;\n\n /**\n * true if the current key has not been marked as invalid\n */\n get hasValidKey(): boolean {\n return !this.hasInvalidKeyAtIndex(this.currentKeyIndex);\n }\n\n constructor(participantIdentity: string, keyProviderOptions: KeyProviderOptions) {\n super();\n this.currentKeyIndex = 0;\n if (keyProviderOptions.keyringSize < 1 || keyProviderOptions.keyringSize > 256) {\n throw new TypeError('Keyring size needs to be between 1 and 256');\n }\n this.cryptoKeyRing = new Array(keyProviderOptions.keyringSize).fill(undefined);\n this.decryptionFailureCounts = new Array(keyProviderOptions.keyringSize).fill(0);\n this.keyProviderOptions = keyProviderOptions;\n this.ratchetPromiseMap = new Map();\n this.participantIdentity = participantIdentity;\n }\n\n /**\n * Returns true if the key at the given index is marked as invalid.\n *\n * @param keyIndex the index of the key\n */\n hasInvalidKeyAtIndex(keyIndex: number): boolean {\n return (\n this.keyProviderOptions.failureTolerance >= 0 &&\n this.decryptionFailureCounts[keyIndex] > this.keyProviderOptions.failureTolerance\n );\n }\n\n /**\n * Informs the key handler that a decryption failure occurred for an encryption key.\n * @internal\n * @param keyIndex the key index for which the failure occurred. Defaults to the current key index.\n */\n decryptionFailure(keyIndex: number = this.currentKeyIndex): void {\n if (this.keyProviderOptions.failureTolerance < 0) {\n return;\n }\n\n this.decryptionFailureCounts[keyIndex] += 1;\n\n if (this.decryptionFailureCounts[keyIndex] > this.keyProviderOptions.failureTolerance) {\n workerLogger.warn(\n `key for ${this.participantIdentity} at index ${keyIndex} is being marked as invalid`,\n );\n }\n }\n\n /**\n * Informs the key handler that a frame was successfully decrypted using an encryption key.\n * @internal\n * @param keyIndex the key index for which the success occurred. Defaults to the current key index.\n */\n decryptionSuccess(keyIndex: number = this.currentKeyIndex): void {\n this.resetKeyStatus(keyIndex);\n }\n\n /**\n * Call this after user initiated ratchet or a new key has been set in order to make sure to mark potentially\n * invalid keys as valid again\n *\n * @param keyIndex the index of the key. Defaults to the current key index.\n */\n resetKeyStatus(keyIndex?: number): void {\n if (keyIndex === undefined) {\n this.decryptionFailureCounts.fill(0);\n } else {\n this.decryptionFailureCounts[keyIndex] = 0;\n }\n }\n\n /**\n * Ratchets the current key (or the one at keyIndex if provided) and\n * returns the ratcheted material\n * if `setKey` is true (default), it will also set the ratcheted key directly on the crypto key ring\n * @param keyIndex\n * @param setKey\n */\n ratchetKey(keyIndex?: number, setKey = true): Promise<CryptoKey> {\n const currentKeyIndex = keyIndex ?? this.getCurrentKeyIndex();\n\n const existingPromise = this.ratchetPromiseMap.get(currentKeyIndex);\n if (typeof existingPromise !== 'undefined') {\n return existingPromise;\n }\n const ratchetPromise = new Promise<CryptoKey>(async (resolve, reject) => {\n try {\n const keySet = this.getKeySet(currentKeyIndex);\n if (!keySet) {\n throw new TypeError(\n `Cannot ratchet key without a valid keyset of participant ${this.participantIdentity}`,\n );\n }\n const currentMaterial = keySet.material;\n const newMaterial = await importKey(\n await ratchet(currentMaterial, this.keyProviderOptions.ratchetSalt),\n currentMaterial.algorithm.name,\n 'derive',\n );\n\n if (setKey) {\n await this.setKeyFromMaterial(newMaterial, currentKeyIndex, true);\n this.emit(\n KeyHandlerEvent.KeyRatcheted,\n newMaterial,\n this.participantIdentity,\n currentKeyIndex,\n );\n }\n resolve(newMaterial);\n } catch (e) {\n reject(e);\n } finally {\n this.ratchetPromiseMap.delete(currentKeyIndex);\n }\n });\n this.ratchetPromiseMap.set(currentKeyIndex, ratchetPromise);\n return ratchetPromise;\n }\n\n /**\n * takes in a key material with `deriveBits` and `deriveKey` set as key usages\n * and derives encryption keys from the material and sets it on the key ring buffer\n * together with the material\n * also resets the valid key property and updates the currentKeyIndex\n */\n async setKey(material: CryptoKey, keyIndex = 0) {\n await this.setKeyFromMaterial(material, keyIndex);\n this.resetKeyStatus(keyIndex);\n }\n\n /**\n * takes in a key material with `deriveBits` and `deriveKey` set as key usages\n * and derives encryption keys from the material and sets it on the key ring buffers\n * together with the material\n * also updates the currentKeyIndex\n */\n async setKeyFromMaterial(material: CryptoKey, keyIndex: number, emitRatchetEvent = false) {\n const keySet = await deriveKeys(material, this.keyProviderOptions.ratchetSalt);\n const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : this.currentKeyIndex;\n workerLogger.debug(`setting new key with index ${keyIndex}`, {\n usage: material.usages,\n algorithm: material.algorithm,\n ratchetSalt: this.keyProviderOptions.ratchetSalt,\n });\n this.setKeySet(keySet, newIndex, emitRatchetEvent);\n if (newIndex >= 0) this.currentKeyIndex = newIndex;\n }\n\n setKeySet(keySet: KeySet, keyIndex: number, emitRatchetEvent = false) {\n this.cryptoKeyRing[keyIndex % this.cryptoKeyRing.length] = keySet;\n\n if (emitRatchetEvent) {\n this.emit(KeyHandlerEvent.KeyRatcheted, keySet.material, this.participantIdentity, keyIndex);\n }\n }\n\n async setCurrentKeyIndex(index: number) {\n this.currentKeyIndex = index % this.cryptoKeyRing.length;\n this.resetKeyStatus(index);\n }\n\n getCurrentKeyIndex() {\n return this.currentKeyIndex;\n }\n\n /**\n * returns currently used KeySet or the one at `keyIndex` if provided\n * @param keyIndex\n * @returns\n */\n getKeySet(keyIndex?: number) {\n return this.cryptoKeyRing[keyIndex ?? this.currentKeyIndex];\n }\n}\n","import { workerLogger } from '../../logger';\nimport type { VideoCodec } from '../../room/track/options';\nimport { AsyncQueue } from '../../utils/AsyncQueue';\nimport { KEY_PROVIDER_DEFAULTS } from '../constants';\nimport { CryptorErrorReason } from '../errors';\nimport { CryptorEvent, KeyHandlerEvent } from '../events';\nimport type {\n E2EEWorkerMessage,\n ErrorMessage,\n InitAck,\n KeyProviderOptions,\n RatchetMessage,\n RatchetRequestMessage,\n} from '../types';\nimport { FrameCryptor, encryptionEnabledMap } from './FrameCryptor';\nimport { ParticipantKeyHandler } from './ParticipantKeyHandler';\n\nconst participantCryptors: FrameCryptor[] = [];\nconst participantKeys: Map<string, ParticipantKeyHandler> = new Map();\nlet sharedKeyHandler: ParticipantKeyHandler | undefined;\nlet messageQueue = new AsyncQueue();\n\nlet isEncryptionEnabled: boolean = false;\n\nlet useSharedKey: boolean = false;\n\nlet sifTrailer: Uint8Array | undefined;\n\nlet keyProviderOptions: KeyProviderOptions = KEY_PROVIDER_DEFAULTS;\n\nlet rtpMap: Map<number, VideoCodec> = new Map();\n\nworkerLogger.setDefaultLevel('info');\n\nonmessage = (ev) => {\n messageQueue.run(async () => {\n const { kind, data }: E2EEWorkerMessage = ev.data;\n\n switch (kind) {\n case 'init':\n workerLogger.setLevel(data.loglevel);\n workerLogger.info('worker initialized');\n keyProviderOptions = data.keyProviderOptions;\n useSharedKey = !!data.keyProviderOptions.sharedKey;\n // acknowledge init successful\n const ackMsg: InitAck = {\n kind: 'initAck',\n data: { enabled: isEncryptionEnabled },\n };\n postMessage(ackMsg);\n break;\n case 'enable':\n setEncryptionEnabled(data.enabled, data.participantIdentity);\n workerLogger.info(\n `updated e2ee enabled status for ${data.participantIdentity} to ${data.enabled}`,\n );\n // acknowledge enable call successful\n postMessage(ev.data);\n break;\n case 'decode':\n let cryptor = getTrackCryptor(data.participantIdentity, data.trackId);\n cryptor.setupTransform(\n kind,\n data.readableStream,\n data.writableStream,\n data.trackId,\n data.codec,\n );\n break;\n case 'encode':\n let pubCryptor = getTrackCryptor(data.participantIdentity, data.trackId);\n pubCryptor.setupTransform(\n kind,\n data.readableStream,\n data.writableStream,\n data.trackId,\n data.codec,\n );\n break;\n case 'setKey':\n if (useSharedKey) {\n await setSharedKey(data.key, data.keyIndex);\n } else if (data.participantIdentity) {\n workerLogger.info(\n `set participant sender key ${data.participantIdentity} index ${data.keyIndex}`,\n );\n await getParticipantKeyHandler(data.participantIdentity).setKey(data.key, data.keyIndex);\n } else {\n workerLogger.error('no participant Id was provided and shared key usage is disabled');\n }\n break;\n case 'removeTransform':\n unsetCryptorParticipant(data.trackId, data.participantIdentity);\n break;\n case 'updateCodec':\n getTrackCryptor(data.participantIdentity, data.trackId).setVideoCodec(data.codec);\n break;\n case 'setRTPMap':\n // this is only used for the local participant\n rtpMap = data.map;\n participantCryptors.forEach((cr) => {\n if (cr.getParticipantIdentity() === data.participantIdentity) {\n cr.setRtpMap(data.map);\n }\n });\n break;\n case 'ratchetRequest':\n handleRatchetRequest(data);\n break;\n case 'setSifTrailer':\n handleSifTrailer(data.trailer);\n break;\n default:\n break;\n }\n });\n};\n\nasync function handleRatchetRequest(data: RatchetRequestMessage['data']) {\n if (useSharedKey) {\n const keyHandler = getSharedKeyHandler();\n await keyHandler.ratchetKey(data.keyIndex);\n keyHandler.resetKeyStatus();\n } else if (data.participantIdentity) {\n const keyHandler = getParticipantKeyHandler(data.participantIdentity);\n await keyHandler.ratchetKey(data.keyIndex);\n keyHandler.resetKeyStatus();\n } else {\n workerLogger.error(\n 'no participant Id was provided for ratchet request and shared key usage is disabled',\n );\n }\n}\n\nfunction getTrackCryptor(participantIdentity: string, trackId: string) {\n let cryptors = participantCryptors.filter((c) => c.getTrackId() === trackId);\n if (cryptors.length > 1) {\n const debugInfo = cryptors\n .map((c) => {\n return { participant: c.getParticipantIdentity() };\n })\n .join(',');\n workerLogger.error(\n `Found multiple cryptors for the same trackID ${trackId}. target participant: ${participantIdentity} `,\n { participants: debugInfo },\n );\n }\n let cryptor = cryptors[0];\n if (!cryptor) {\n workerLogger.info('creating new cryptor for', { participantIdentity });\n if (!keyProviderOptions) {\n throw Error('Missing keyProvider options');\n }\n cryptor = new FrameCryptor({\n participantIdentity,\n keys: getParticipantKeyHandler(participantIdentity),\n keyProviderOptions,\n sifTrailer,\n });\n cryptor.setRtpMap(rtpMap);\n setupCryptorErrorEvents(cryptor);\n participantCryptors.push(cryptor);\n } else if (participantIdentity !== cryptor.getParticipantIdentity()) {\n // assign new participant id to track cryptor and pass in correct key handler\n cryptor.setParticipant(participantIdentity, getParticipantKeyHandler(participantIdentity));\n }\n\n return cryptor;\n}\n\nfunction getParticipantKeyHandler(participantIdentity: string) {\n if (useSharedKey) {\n return getSharedKeyHandler();\n }\n let keys = participantKeys.get(participantIdentity);\n if (!keys) {\n keys = new ParticipantKeyHandler(participantIdentity, keyProviderOptions);\n keys.on(KeyHandlerEvent.KeyRatcheted, emitRatchetedKeys);\n participantKeys.set(participantIdentity, keys);\n }\n return keys;\n}\n\nfunction getSharedKeyHandler() {\n if (!sharedKeyHandler) {\n workerLogger.debug('creating new shared key handler');\n sharedKeyHandler = new ParticipantKeyHandler('shared-key', keyProviderOptions);\n }\n return sharedKeyHandler;\n}\n\nfunction unsetCryptorParticipant(trackId: string, participantIdentity: string) {\n const cryptors = participantCryptors.filter(\n (c) => c.getParticipantIdentity() === participantIdentity && c.getTrackId() === trackId,\n );\n if (cryptors.length > 1) {\n workerLogger.error('Found multiple cryptors for the same participant and trackID combination', {\n trackId,\n participantIdentity,\n });\n }\n const cryptor = cryptors[0];\n if (!cryptor) {\n workerLogger.warn('Could not unset participant on cryptor', { trackId, participantIdentity });\n } else {\n cryptor.unsetParticipant();\n }\n}\n\nfunction setEncryptionEnabled(enable: boolean, participantIdentity: string) {\n workerLogger.debug(`setting encryption enabled for all tracks of ${participantIdentity}`, {\n enable,\n });\n encryptionEnabledMap.set(participantIdentity, enable);\n}\n\nasync function setSharedKey(key: CryptoKey, index?: number) {\n workerLogger.info('set shared key', { index });\n await getSharedKeyHandler().setKey(key, index);\n}\n\nfunction setupCryptorErrorEvents(cryptor: FrameCryptor) {\n cryptor.on(CryptorEvent.Error, (error) => {\n const msg: ErrorMessage = {\n kind: 'error',\n data: { error: new Error(`${CryptorErrorReason[error.reason]}: ${error.message}`) },\n };\n postMessage(msg);\n });\n}\n\nfunction emitRatchetedKeys(material: CryptoKey, participantIdentity: string, keyIndex?: number) {\n const msg: RatchetMessage = {\n kind: `ratchetKey`,\n data: {\n participantIdentity,\n keyIndex,\n material,\n },\n };\n postMessage(msg);\n}\n\nfunction handleSifTrailer(trailer: Uint8Array) {\n sifTrailer = trailer;\n participantCryptors.forEach((c) => {\n c.setSifTrailer(trailer);\n });\n}\n\n// Operations using RTCRtpScriptTransform.\n// @ts-ignore\nif (self.RTCTransformEvent) {\n workerLogger.debug('setup transform event');\n // @ts-ignore\n self.onrtctransform = (event: RTCTransformEvent) => {\n // @ts-ignore .transformer property is part of RTCTransformEvent\n const transformer = event.transformer;\n workerLogger.debug('transformer', transformer);\n // @ts-ignore monkey patching non standard flag\n transformer.handled = true;\n const { kind, participantIdentity, trackId, codec } = transformer.options;\n const cryptor = getTrackCryptor(participantIdentity, trackId);\n workerLogger.debug('transform', { codec });\n cryptor.setupTransform(kind, transformer.readable, transformer.writable, trackId, codec);\n };\n}\n"],"names":["root","definition","LogLevel","LoggerNames","noop","undefinedType","isIE","window","navigator","test","userAgent","logMethods","_loggersByName","defaultLogger","bindMethod","obj","methodName","method","bind","Function","prototype","call","e","apply","arguments","traceForIE","console","log","trace","replaceLoggingMethods","level","this","getLevel","i","length","methodFactory","name","debug","levels","SILENT","enableLoggingWhenConsoleArrives","defaultMethodFactory","_level","_loggerName","undefined","realMethod","Logger","factory","inheritedLevel","defaultLevel","userLevel","self","storageKey","getPersistedLevel","storedLevel","localStorage","ignore","cookie","document","cookieName","encodeURIComponent","location","indexOf","exec","slice","normalizeLevel","input","toUpperCase","TypeError","TRACE","DEBUG","INFO","WARN","ERROR","setLevel","persist","levelNum","levelName","persistLevelIfPossible","setDefaultLevel","resetLevel","removeItem","clearPersistedLevel","enableAll","disableAll","rebuild","childName","initialLevel","getLogger","logger","_log","noConflict","getLoggers","exports","module","livekitLogger","Object","values","map","info","workerLogger","QueueTaskStatus","h","constructor","l","_locking","Promise","resolve","_locks","isLocked","lock","o","c","unlockNext","t","then","ENCRYPTION_ALGORITHM","UNENCRYPTED_BYTES","key","delta","audio","empty","KEY_PROVIDER_DEFAULTS","sharedKey","ratchetSalt","ratchetWindowSize","failureTolerance","keyringSize","LivekitError","Error","code","message","super","ConnectionErrorReason","MediaDeviceFailure","CryptorErrorReason","KeyProviderEvent","KeyHandlerEvent","EncryptionEvent","CryptorEvent","getFailure","error","NotFound","PermissionDenied","DeviceInUse","Other","CryptorError","reason","InternalError","participantIdentity","ReflectOwnKeys","R","Reflect","ReflectApply","target","receiver","args","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","concat","NumberIsNaN","Number","isNaN","value","EventEmitter","init","eventsModule","once","emitter","reject","errorListener","err","removeListener","resolver","eventTargetAgnosticAddListener","handler","flags","on","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","_getMaxListeners","that","_addListener","type","prepend","m","events","existing","warning","create","newListener","emit","unshift","push","warned","w","String","count","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","_listeners","unwrap","evlistener","arr","ret","Array","unwrapListeners","arrayClone","listenerCount","n","copy","addEventListener","wrapListener","arg","removeEventListener","defineProperty","enumerable","get","set","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","context","len","listeners","addListener","prependListener","prependOnceListener","list","position","originalListener","shift","index","pop","spliceOne","off","removeAllListeners","keys","rawListeners","eventNames","getAlgoOptions","algorithmName","salt","encodedSalt","TextEncoder","encode","hash","ArrayBuffer","iterations","deriveKeys","material","algorithmOptions","algorithm","encryptionKey","crypto","subtle","deriveKey","SifGuard","consecutiveSifCount","lastSifReceivedAt","userFramesSinceSif","recordSif","_a","sifSequenceStartedAt","Date","now","recordUserFrame","reset","isSifAllowed","encryptionEnabledMap","Map","BaseFrameCryptor","encodeFunction","encodedFrame","controller","decodeFunction","FrameCryptor","opts","sendCounts","rtpMap","keyProviderOptions","sifTrailer","Uint8Array","from","sifGuard","logContext","participant","mediaTrackId","trackId","fallbackCodec","videoCodec","setParticipant","id","assign","unsetParticipant","isEnabled","getParticipantIdentity","getTrackId","setVideoCodec","codec","setRtpMap","setupTransform","operation","readable","writable","passedTrackId","transformFn","transformStream","TransformStream","transform","pipeThrough","pipeTo","catch","setSifTrailer","trailer","data","byteLength","enqueue","keySet","getKeySet","getCurrentKeyIndex","MissingKey","keyIndex","iv","makeIV","getMetadata","synchronizationSource","timestamp","frameInfo","getUnencryptedBytes","frameHeader","unencryptedBytes","frameTrailer","cipherText","encrypt","additionalData","newDataWithoutHeader","isH264","data_in","dataOut","numConsecutiveZeros","byte","writeRbsp","newData","buffer","frameData","trailerBytes","every","isFrameServerInjected","hasInvalidKeyAtIndex","decodedFrame","decryptFrame","decryptionSuccess","InvalidKey","hasValidKey","decryptionFailure","encodedFrame_1","keyIndex_1","_this","initialMaterial","ratchetOpts","ratchetCount","encryptedData","needsRbspUnescaping","stream","parseRbsp","newUint8","ivLength","cipherTextStart","cipherTextLength","plainText","decrypt","ratchetedKeySet","RTCEncodedAudioFrame","newMaterial","ratchetKey","frame","setKeySet","setCurrentKeyIndex","ivView","DataView","has","Math","floor","random","sendCount","setUint32","isVideoFrame","detectedCodec","getVideoCodec","oldCodec","naluIndices","result","start","pos","searchLength","end","findNALUIndices","some","naluIndex","NALUType","SLICE_IDR","SLICE_NON_IDR","includes","parseNALUType","size","payloadType","startByte","kNaluTypeMask","ParticipantKeyHandler","currentKeyIndex","cryptoKeyRing","fill","decryptionFailureCounts","ratchetPromiseMap","resetKeyStatus","setKey","existingPromise","ratchetPromise","__awaiter","currentMaterial","keyBytes_1","keyBytes","usage","importKey","deriveBits","ratchet","setKeyFromMaterial","KeyRatcheted","delete","material_1","_this2","emitRatchetEvent","newIndex","usages","participantCryptors","participantKeys","sharedKeyHandler","messageQueue","pendingTasks","taskMutex","Mutex","nextTaskIndex","run","task","taskInfo","enqueuedAt","status","WAITING","unlock","executedAt","RUNNING","COMPLETED","flush","snapshot","useSharedKey","getTrackCryptor","cryptors","filter","debugInfo","join","participants","cryptor","getParticipantKeyHandler","msg","kind","postMessage","setupCryptorErrorEvents","getSharedKeyHandler","emitRatchetedKeys","onmessage","ev","loglevel","enabled","enable","readableStream","writableStream","setSharedKey","unsetCryptorParticipant","forEach","cr","keyHandler","handleRatchetRequest","RTCTransformEvent","onrtctransform","event","transformer","handled","options"],"mappings":"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","x_google_ignoreList":[0,3,8]}
1
+ {"version":3,"file":"livekit-client.e2ee.worker.js","sources":["../node_modules/.pnpm/loglevel@1.9.1/node_modules/loglevel/lib/loglevel.js","../src/logger.ts","../src/utils/AsyncQueue.ts","../node_modules/.pnpm/@livekit+mutex@1.0.0/node_modules/@livekit/mutex/dist/index.mjs","../src/e2ee/constants.ts","../src/room/errors.ts","../src/e2ee/errors.ts","../src/e2ee/events.ts","../node_modules/.pnpm/events@3.3.0/node_modules/events/events.js","../src/e2ee/utils.ts","../src/e2ee/worker/SifGuard.ts","../src/e2ee/worker/FrameCryptor.ts","../src/e2ee/worker/ParticipantKeyHandler.ts","../src/e2ee/worker/e2ee.worker.ts"],"sourcesContent":["/*\n* loglevel - https://github.com/pimterry/loglevel\n*\n* Copyright (c) 2013 Tim Perry\n* Licensed under the MIT license.\n*/\n(function (root, definition) {\n \"use strict\";\n if (typeof define === 'function' && define.amd) {\n define(definition);\n } else if (typeof module === 'object' && module.exports) {\n module.exports = definition();\n } else {\n root.log = definition();\n }\n}(this, function () {\n \"use strict\";\n\n // Slightly dubious tricks to cut down minimized file size\n var noop = function() {};\n var undefinedType = \"undefined\";\n var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (\n /Trident\\/|MSIE /.test(window.navigator.userAgent)\n );\n\n var logMethods = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\"\n ];\n\n var _loggersByName = {};\n var defaultLogger = null;\n\n // Cross-browser bind equivalent that works at least back to IE6\n function bindMethod(obj, methodName) {\n var method = obj[methodName];\n if (typeof method.bind === 'function') {\n return method.bind(obj);\n } else {\n try {\n return Function.prototype.bind.call(method, obj);\n } catch (e) {\n // Missing bind shim or IE8 + Modernizr, fallback to wrapping\n return function() {\n return Function.prototype.apply.apply(method, [obj, arguments]);\n };\n }\n }\n }\n\n // Trace() doesn't print the message in IE, so for that case we need to wrap it\n function traceForIE() {\n if (console.log) {\n if (console.log.apply) {\n console.log.apply(console, arguments);\n } else {\n // In old IE, native console methods themselves don't have apply().\n Function.prototype.apply.apply(console.log, [console, arguments]);\n }\n }\n if (console.trace) console.trace();\n }\n\n // Build the best logging method possible for this env\n // Wherever possible we want to bind, not wrap, to preserve stack traces\n function realMethod(methodName) {\n if (methodName === 'debug') {\n methodName = 'log';\n }\n\n if (typeof console === undefinedType) {\n return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives\n } else if (methodName === 'trace' && isIE) {\n return traceForIE;\n } else if (console[methodName] !== undefined) {\n return bindMethod(console, methodName);\n } else if (console.log !== undefined) {\n return bindMethod(console, 'log');\n } else {\n return noop;\n }\n }\n\n // These private functions always need `this` to be set properly\n\n function replaceLoggingMethods() {\n /*jshint validthis:true */\n var level = this.getLevel();\n\n // Replace the actual methods.\n for (var i = 0; i < logMethods.length; i++) {\n var methodName = logMethods[i];\n this[methodName] = (i < level) ?\n noop :\n this.methodFactory(methodName, level, this.name);\n }\n\n // Define log.log as an alias for log.debug\n this.log = this.debug;\n\n // Return any important warnings.\n if (typeof console === undefinedType && level < this.levels.SILENT) {\n return \"No console available for logging\";\n }\n }\n\n // In old IE versions, the console isn't present until you first open it.\n // We build realMethod() replacements here that regenerate logging methods\n function enableLoggingWhenConsoleArrives(methodName) {\n return function () {\n if (typeof console !== undefinedType) {\n replaceLoggingMethods.call(this);\n this[methodName].apply(this, arguments);\n }\n };\n }\n\n // By default, we use closely bound real methods wherever possible, and\n // otherwise we wait for a console to appear, and then try again.\n function defaultMethodFactory(methodName, _level, _loggerName) {\n /*jshint validthis:true */\n return realMethod(methodName) ||\n enableLoggingWhenConsoleArrives.apply(this, arguments);\n }\n\n function Logger(name, factory) {\n // Private instance variables.\n var self = this;\n /**\n * The level inherited from a parent logger (or a global default). We\n * cache this here rather than delegating to the parent so that it stays\n * in sync with the actual logging methods that we have installed (the\n * parent could change levels but we might not have rebuilt the loggers\n * in this child yet).\n * @type {number}\n */\n var inheritedLevel;\n /**\n * The default level for this logger, if any. If set, this overrides\n * `inheritedLevel`.\n * @type {number|null}\n */\n var defaultLevel;\n /**\n * A user-specific level for this logger. If set, this overrides\n * `defaultLevel`.\n * @type {number|null}\n */\n var userLevel;\n\n var storageKey = \"loglevel\";\n if (typeof name === \"string\") {\n storageKey += \":\" + name;\n } else if (typeof name === \"symbol\") {\n storageKey = undefined;\n }\n\n function persistLevelIfPossible(levelNum) {\n var levelName = (logMethods[levelNum] || 'silent').toUpperCase();\n\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage[storageKey] = levelName;\n return;\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=\" + levelName + \";\";\n } catch (ignore) {}\n }\n\n function getPersistedLevel() {\n var storedLevel;\n\n if (typeof window === undefinedType || !storageKey) return;\n\n try {\n storedLevel = window.localStorage[storageKey];\n } catch (ignore) {}\n\n // Fallback to cookies if local storage gives us nothing\n if (typeof storedLevel === undefinedType) {\n try {\n var cookie = window.document.cookie;\n var cookieName = encodeURIComponent(storageKey);\n var location = cookie.indexOf(cookieName + \"=\");\n if (location !== -1) {\n storedLevel = /^([^;]+)/.exec(\n cookie.slice(location + cookieName.length + 1)\n )[1];\n }\n } catch (ignore) {}\n }\n\n // If the stored level is not valid, treat it as if nothing was stored.\n if (self.levels[storedLevel] === undefined) {\n storedLevel = undefined;\n }\n\n return storedLevel;\n }\n\n function clearPersistedLevel() {\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage.removeItem(storageKey);\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=; expires=Thu, 01 Jan 1970 00:00:00 UTC\";\n } catch (ignore) {}\n }\n\n function normalizeLevel(input) {\n var level = input;\n if (typeof level === \"string\" && self.levels[level.toUpperCase()] !== undefined) {\n level = self.levels[level.toUpperCase()];\n }\n if (typeof level === \"number\" && level >= 0 && level <= self.levels.SILENT) {\n return level;\n } else {\n throw new TypeError(\"log.setLevel() called with invalid level: \" + input);\n }\n }\n\n /*\n *\n * Public logger API - see https://github.com/pimterry/loglevel for details\n *\n */\n\n self.name = name;\n\n self.levels = { \"TRACE\": 0, \"DEBUG\": 1, \"INFO\": 2, \"WARN\": 3,\n \"ERROR\": 4, \"SILENT\": 5};\n\n self.methodFactory = factory || defaultMethodFactory;\n\n self.getLevel = function () {\n if (userLevel != null) {\n return userLevel;\n } else if (defaultLevel != null) {\n return defaultLevel;\n } else {\n return inheritedLevel;\n }\n };\n\n self.setLevel = function (level, persist) {\n userLevel = normalizeLevel(level);\n if (persist !== false) { // defaults to true\n persistLevelIfPossible(userLevel);\n }\n\n // NOTE: in v2, this should call rebuild(), which updates children.\n return replaceLoggingMethods.call(self);\n };\n\n self.setDefaultLevel = function (level) {\n defaultLevel = normalizeLevel(level);\n if (!getPersistedLevel()) {\n self.setLevel(level, false);\n }\n };\n\n self.resetLevel = function () {\n userLevel = null;\n clearPersistedLevel();\n replaceLoggingMethods.call(self);\n };\n\n self.enableAll = function(persist) {\n self.setLevel(self.levels.TRACE, persist);\n };\n\n self.disableAll = function(persist) {\n self.setLevel(self.levels.SILENT, persist);\n };\n\n self.rebuild = function () {\n if (defaultLogger !== self) {\n inheritedLevel = normalizeLevel(defaultLogger.getLevel());\n }\n replaceLoggingMethods.call(self);\n\n if (defaultLogger === self) {\n for (var childName in _loggersByName) {\n _loggersByName[childName].rebuild();\n }\n }\n };\n\n // Initialize all the internal levels.\n inheritedLevel = normalizeLevel(\n defaultLogger ? defaultLogger.getLevel() : \"WARN\"\n );\n var initialLevel = getPersistedLevel();\n if (initialLevel != null) {\n userLevel = normalizeLevel(initialLevel);\n }\n replaceLoggingMethods.call(self);\n }\n\n /*\n *\n * Top-level API\n *\n */\n\n defaultLogger = new Logger();\n\n defaultLogger.getLogger = function getLogger(name) {\n if ((typeof name !== \"symbol\" && typeof name !== \"string\") || name === \"\") {\n throw new TypeError(\"You must supply a name when creating a logger.\");\n }\n\n var logger = _loggersByName[name];\n if (!logger) {\n logger = _loggersByName[name] = new Logger(\n name,\n defaultLogger.methodFactory\n );\n }\n return logger;\n };\n\n // Grab the current global log variable in case of overwrite\n var _log = (typeof window !== undefinedType) ? window.log : undefined;\n defaultLogger.noConflict = function() {\n if (typeof window !== undefinedType &&\n window.log === defaultLogger) {\n window.log = _log;\n }\n\n return defaultLogger;\n };\n\n defaultLogger.getLoggers = function getLoggers() {\n return _loggersByName;\n };\n\n // ES6 default export, for compatibility\n defaultLogger['default'] = defaultLogger;\n\n return defaultLogger;\n}));\n","import * as log from 'loglevel';\n\nexport enum LogLevel {\n trace = 0,\n debug = 1,\n info = 2,\n warn = 3,\n error = 4,\n silent = 5,\n}\n\nexport enum LoggerNames {\n Default = 'livekit',\n Room = 'livekit-room',\n Participant = 'livekit-participant',\n Track = 'livekit-track',\n Publication = 'livekit-track-publication',\n Engine = 'livekit-engine',\n Signal = 'livekit-signal',\n PCManager = 'livekit-pc-manager',\n PCTransport = 'livekit-pc-transport',\n E2EE = 'lk-e2ee',\n}\n\ntype LogLevelString = keyof typeof LogLevel;\n\nexport type StructuredLogger = log.Logger & {\n trace: (msg: string, context?: object) => void;\n debug: (msg: string, context?: object) => void;\n info: (msg: string, context?: object) => void;\n warn: (msg: string, context?: object) => void;\n error: (msg: string, context?: object) => void;\n setDefaultLevel: (level: log.LogLevelDesc) => void;\n setLevel: (level: log.LogLevelDesc) => void;\n getLevel: () => number;\n};\n\nlet livekitLogger = log.getLogger('livekit');\nconst livekitLoggers = Object.values(LoggerNames).map((name) => log.getLogger(name));\n\nlivekitLogger.setDefaultLevel(LogLevel.info);\n\nexport default livekitLogger as StructuredLogger;\n\n/**\n * @internal\n */\nexport function getLogger(name: string) {\n const logger = log.getLogger(name);\n logger.setDefaultLevel(livekitLogger.getLevel());\n return logger as StructuredLogger;\n}\n\nexport function setLogLevel(level: LogLevel | LogLevelString, loggerName?: LoggerNames) {\n if (loggerName) {\n log.getLogger(loggerName).setLevel(level);\n } else {\n for (const logger of livekitLoggers) {\n logger.setLevel(level);\n }\n }\n}\n\nexport type LogExtension = (level: LogLevel, msg: string, context?: object) => void;\n\n/**\n * use this to hook into the logging function to allow sending internal livekit logs to third party services\n * if set, the browser logs will lose their stacktrace information (see https://github.com/pimterry/loglevel#writing-plugins)\n */\nexport function setLogExtension(extension: LogExtension, logger?: StructuredLogger) {\n const loggers = logger ? [logger] : livekitLoggers;\n\n loggers.forEach((logR) => {\n const originalFactory = logR.methodFactory;\n\n logR.methodFactory = (methodName, configLevel, loggerName) => {\n const rawMethod = originalFactory(methodName, configLevel, loggerName);\n\n const logLevel = LogLevel[methodName as LogLevelString];\n const needLog = logLevel >= configLevel && logLevel < LogLevel.silent;\n\n return (msg, context?: [msg: string, context: object]) => {\n if (context) rawMethod(msg, context);\n else rawMethod(msg);\n if (needLog) {\n extension(logLevel, msg, context);\n }\n };\n };\n logR.setLevel(logR.getLevel());\n });\n}\n\nexport const workerLogger = log.getLogger('lk-e2ee') as StructuredLogger;\n","import { Mutex } from '@livekit/mutex';\n\ntype QueueTask<T> = () => PromiseLike<T>;\n\nenum QueueTaskStatus {\n 'WAITING',\n 'RUNNING',\n 'COMPLETED',\n}\n\ntype QueueTaskInfo = {\n id: number;\n enqueuedAt: number;\n executedAt?: number;\n status: QueueTaskStatus;\n};\n\nexport class AsyncQueue {\n private pendingTasks: Map<number, QueueTaskInfo>;\n\n private taskMutex: Mutex;\n\n private nextTaskIndex: number;\n\n constructor() {\n this.pendingTasks = new Map();\n this.taskMutex = new Mutex();\n this.nextTaskIndex = 0;\n }\n\n async run<T>(task: QueueTask<T>) {\n const taskInfo: QueueTaskInfo = {\n id: this.nextTaskIndex++,\n enqueuedAt: Date.now(),\n status: QueueTaskStatus.WAITING,\n };\n this.pendingTasks.set(taskInfo.id, taskInfo);\n const unlock = await this.taskMutex.lock();\n try {\n taskInfo.executedAt = Date.now();\n taskInfo.status = QueueTaskStatus.RUNNING;\n return await task();\n } finally {\n taskInfo.status = QueueTaskStatus.COMPLETED;\n this.pendingTasks.delete(taskInfo.id);\n unlock();\n }\n }\n\n async flush() {\n return this.run(async () => {});\n }\n\n snapshot() {\n return Array.from(this.pendingTasks.values());\n }\n}\n","var k = Object.defineProperty;\nvar n = (s, o, c) => o in s ? k(s, o, { enumerable: !0, configurable: !0, writable: !0, value: c }) : s[o] = c;\nvar l = (s, o, c) => n(s, typeof o != \"symbol\" ? o + \"\" : o, c);\nclass h {\n constructor() {\n l(this, \"_locking\");\n l(this, \"_locks\");\n this._locking = Promise.resolve(), this._locks = 0;\n }\n isLocked() {\n return this._locks > 0;\n }\n lock() {\n this._locks += 1;\n let o;\n const c = new Promise(\n (i) => o = () => {\n this._locks -= 1, i();\n }\n ), t = this._locking.then(() => o);\n return this._locking = this._locking.then(() => c), t;\n }\n}\nexport {\n h as Mutex\n};\n//# sourceMappingURL=index.mjs.map\n","import type { KeyProviderOptions } from './types';\n\nexport const ENCRYPTION_ALGORITHM = 'AES-GCM';\n\n// How many consecutive frames can fail decrypting before a particular key gets marked as invalid\nexport const DECRYPTION_FAILURE_TOLERANCE = 10;\n\n// We copy the first bytes of the VP8 payload unencrypted.\n// For keyframes this is 10 bytes, for non-keyframes (delta) 3. See\n// https://tools.ietf.org/html/rfc6386#section-9.1\n// This allows the bridge to continue detecting keyframes (only one byte needed in the JVB)\n// and is also a bit easier for the VP8 decoder (i.e. it generates funny garbage pictures\n// instead of being unable to decode).\n// This is a bit for show and we might want to reduce to 1 unconditionally in the final version.\n//\n// For audio (where frame.type is not set) we do not encrypt the opus TOC byte:\n// https://tools.ietf.org/html/rfc6716#section-3.1\nexport const UNENCRYPTED_BYTES = {\n key: 10,\n delta: 3,\n audio: 1, // frame.type is not set on audio, so this is set manually\n empty: 0,\n} as const;\n\n/* We use a 12 byte bit IV. This is signalled in plain together with the\n packet. See https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#parameters */\nexport const IV_LENGTH = 12;\n\n// flag set to indicate that e2ee has been setup for sender/receiver;\nexport const E2EE_FLAG = 'lk_e2ee';\n\nexport const SALT = 'LKFrameEncryptionKey';\n\nexport const KEY_PROVIDER_DEFAULTS: KeyProviderOptions = {\n sharedKey: false,\n ratchetSalt: SALT,\n ratchetWindowSize: 8,\n failureTolerance: DECRYPTION_FAILURE_TOLERANCE,\n keyringSize: 16,\n} as const;\n\nexport const MAX_SIF_COUNT = 100;\nexport const MAX_SIF_DURATION = 2000;\n","import { RequestResponse_Reason } from '@livekit/protocol';\n\nexport class LivekitError extends Error {\n code: number;\n\n constructor(code: number, message?: string) {\n super(message || 'an error has occured');\n this.code = code;\n }\n}\n\nexport const enum ConnectionErrorReason {\n NotAllowed,\n ServerUnreachable,\n InternalError,\n Cancelled,\n LeaveRequest,\n}\n\nexport class ConnectionError extends LivekitError {\n status?: number;\n\n reason: ConnectionErrorReason;\n\n constructor(message: string, reason: ConnectionErrorReason, status?: number) {\n super(1, message);\n this.status = status;\n this.reason = reason;\n }\n}\n\nexport class DeviceUnsupportedError extends LivekitError {\n constructor(message?: string) {\n super(21, message ?? 'device is unsupported');\n }\n}\n\nexport class TrackInvalidError extends LivekitError {\n constructor(message?: string) {\n super(20, message ?? 'track is invalid');\n }\n}\n\nexport class UnsupportedServer extends LivekitError {\n constructor(message?: string) {\n super(10, message ?? 'unsupported server');\n }\n}\n\nexport class UnexpectedConnectionState extends LivekitError {\n constructor(message?: string) {\n super(12, message ?? 'unexpected connection state');\n }\n}\n\nexport class NegotiationError extends LivekitError {\n constructor(message?: string) {\n super(13, message ?? 'unable to negotiate');\n }\n}\n\nexport class PublishDataError extends LivekitError {\n constructor(message?: string) {\n super(13, message ?? 'unable to publish data');\n }\n}\n\nexport type RequestErrorReason =\n | Exclude<RequestResponse_Reason, RequestResponse_Reason.OK>\n | 'TimeoutError';\n\nexport class SignalRequestError extends LivekitError {\n reason: RequestErrorReason;\n\n constructor(message: string, reason: RequestErrorReason) {\n super(15, message);\n this.reason = reason;\n }\n}\n\nexport enum MediaDeviceFailure {\n // user rejected permissions\n PermissionDenied = 'PermissionDenied',\n // device is not available\n NotFound = 'NotFound',\n // device is in use. On Windows, only a single tab may get access to a device at a time.\n DeviceInUse = 'DeviceInUse',\n Other = 'Other',\n}\n\nexport namespace MediaDeviceFailure {\n export function getFailure(error: any): MediaDeviceFailure | undefined {\n if (error && 'name' in error) {\n if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {\n return MediaDeviceFailure.NotFound;\n }\n if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {\n return MediaDeviceFailure.PermissionDenied;\n }\n if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {\n return MediaDeviceFailure.DeviceInUse;\n }\n return MediaDeviceFailure.Other;\n }\n }\n}\n","import { LivekitError } from '../room/errors';\n\nexport enum CryptorErrorReason {\n InvalidKey = 0,\n MissingKey = 1,\n InternalError = 2,\n}\n\nexport class CryptorError extends LivekitError {\n reason: CryptorErrorReason;\n\n participantIdentity?: string;\n\n constructor(\n message?: string,\n reason: CryptorErrorReason = CryptorErrorReason.InternalError,\n participantIdentity?: string,\n ) {\n super(40, message);\n this.reason = reason;\n this.participantIdentity = participantIdentity;\n }\n}\n","import type Participant from '../room/participant/Participant';\nimport type { CryptorError } from './errors';\nimport type { KeyInfo } from './types';\n\nexport enum KeyProviderEvent {\n SetKey = 'setKey',\n RatchetRequest = 'ratchetRequest',\n KeyRatcheted = 'keyRatcheted',\n}\n\nexport type KeyProviderCallbacks = {\n [KeyProviderEvent.SetKey]: (keyInfo: KeyInfo) => void;\n [KeyProviderEvent.RatchetRequest]: (participantIdentity?: string, keyIndex?: number) => void;\n [KeyProviderEvent.KeyRatcheted]: (material: CryptoKey, keyIndex?: number) => void;\n};\n\nexport enum KeyHandlerEvent {\n KeyRatcheted = 'keyRatcheted',\n}\n\nexport type ParticipantKeyHandlerCallbacks = {\n [KeyHandlerEvent.KeyRatcheted]: (\n material: CryptoKey,\n participantIdentity: string,\n keyIndex?: number,\n ) => void;\n};\n\nexport enum EncryptionEvent {\n ParticipantEncryptionStatusChanged = 'participantEncryptionStatusChanged',\n EncryptionError = 'encryptionError',\n}\n\nexport type E2EEManagerCallbacks = {\n [EncryptionEvent.ParticipantEncryptionStatusChanged]: (\n enabled: boolean,\n participant: Participant,\n ) => void;\n [EncryptionEvent.EncryptionError]: (error: Error) => void;\n};\n\nexport type CryptorCallbacks = {\n [CryptorEvent.Error]: (error: CryptorError) => void;\n};\n\nexport enum CryptorEvent {\n Error = 'cryptorError',\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n","import { ENCRYPTION_ALGORITHM } from './constants';\n\nexport function isE2EESupported() {\n return isInsertableStreamSupported() || isScriptTransformSupported();\n}\n\nexport function isScriptTransformSupported() {\n // @ts-ignore\n return typeof window.RTCRtpScriptTransform !== 'undefined';\n}\n\nexport function isInsertableStreamSupported() {\n return (\n typeof window.RTCRtpSender !== 'undefined' &&\n // @ts-ignore\n typeof window.RTCRtpSender.prototype.createEncodedStreams !== 'undefined'\n );\n}\n\nexport function isVideoFrame(\n frame: RTCEncodedAudioFrame | RTCEncodedVideoFrame,\n): frame is RTCEncodedVideoFrame {\n return 'type' in frame;\n}\n\nexport async function importKey(\n keyBytes: Uint8Array | ArrayBuffer,\n algorithm: string | { name: string } = { name: ENCRYPTION_ALGORITHM },\n usage: 'derive' | 'encrypt' = 'encrypt',\n) {\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey\n return crypto.subtle.importKey(\n 'raw',\n keyBytes,\n algorithm,\n false,\n usage === 'derive' ? ['deriveBits', 'deriveKey'] : ['encrypt', 'decrypt'],\n );\n}\n\nexport async function createKeyMaterialFromString(password: string) {\n let enc = new TextEncoder();\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n enc.encode(password),\n {\n name: 'PBKDF2',\n },\n false,\n ['deriveBits', 'deriveKey'],\n );\n\n return keyMaterial;\n}\n\nexport async function createKeyMaterialFromBuffer(cryptoBuffer: ArrayBuffer) {\n const keyMaterial = await crypto.subtle.importKey('raw', cryptoBuffer, 'HKDF', false, [\n 'deriveBits',\n 'deriveKey',\n ]);\n\n return keyMaterial;\n}\n\nfunction getAlgoOptions(algorithmName: string, salt: string) {\n const textEncoder = new TextEncoder();\n const encodedSalt = textEncoder.encode(salt);\n switch (algorithmName) {\n case 'HKDF':\n return {\n name: 'HKDF',\n salt: encodedSalt,\n hash: 'SHA-256',\n info: new ArrayBuffer(128),\n };\n case 'PBKDF2': {\n return {\n name: 'PBKDF2',\n salt: encodedSalt,\n hash: 'SHA-256',\n iterations: 100000,\n };\n }\n default:\n throw new Error(`algorithm ${algorithmName} is currently unsupported`);\n }\n}\n\n/**\n * Derives a set of keys from the master key.\n * See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1\n */\nexport async function deriveKeys(material: CryptoKey, salt: string) {\n const algorithmOptions = getAlgoOptions(material.algorithm.name, salt);\n\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF\n // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams\n const encryptionKey = await crypto.subtle.deriveKey(\n algorithmOptions,\n material,\n {\n name: ENCRYPTION_ALGORITHM,\n length: 128,\n },\n false,\n ['encrypt', 'decrypt'],\n );\n\n return { material, encryptionKey };\n}\n\nexport function createE2EEKey(): Uint8Array {\n return window.crypto.getRandomValues(new Uint8Array(32));\n}\n\n/**\n * Ratchets a key. See\n * https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1\n */\nexport async function ratchet(material: CryptoKey, salt: string): Promise<ArrayBuffer> {\n const algorithmOptions = getAlgoOptions(material.algorithm.name, salt);\n\n // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits\n return crypto.subtle.deriveBits(algorithmOptions, material, 256);\n}\n\nexport function needsRbspUnescaping(frameData: Uint8Array) {\n for (var i = 0; i < frameData.length - 3; i++) {\n if (frameData[i] == 0 && frameData[i + 1] == 0 && frameData[i + 2] == 3) return true;\n }\n return false;\n}\n\nexport function parseRbsp(stream: Uint8Array): Uint8Array {\n const dataOut: number[] = [];\n var length = stream.length;\n for (var i = 0; i < stream.length; ) {\n // Be careful about over/underflow here. byte_length_ - 3 can underflow, and\n // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_\n // above, and that expression will produce the number of bytes left in\n // the stream including the byte at i.\n if (length - i >= 3 && !stream[i] && !stream[i + 1] && stream[i + 2] == 3) {\n // Two rbsp bytes.\n dataOut.push(stream[i++]);\n dataOut.push(stream[i++]);\n // Skip the emulation byte.\n i++;\n } else {\n // Single rbsp byte.\n dataOut.push(stream[i++]);\n }\n }\n return new Uint8Array(dataOut);\n}\n\nconst kZerosInStartSequence = 2;\nconst kEmulationByte = 3;\n\nexport function writeRbsp(data_in: Uint8Array): Uint8Array {\n const dataOut: number[] = [];\n var numConsecutiveZeros = 0;\n for (var i = 0; i < data_in.length; ++i) {\n var byte = data_in[i];\n if (byte <= kEmulationByte && numConsecutiveZeros >= kZerosInStartSequence) {\n // Need to escape.\n dataOut.push(kEmulationByte);\n numConsecutiveZeros = 0;\n }\n dataOut.push(byte);\n if (byte == 0) {\n ++numConsecutiveZeros;\n } else {\n numConsecutiveZeros = 0;\n }\n }\n return new Uint8Array(dataOut);\n}\n","import { MAX_SIF_COUNT, MAX_SIF_DURATION } from '../constants';\n\nexport class SifGuard {\n private consecutiveSifCount = 0;\n\n private sifSequenceStartedAt: number | undefined;\n\n private lastSifReceivedAt: number = 0;\n\n private userFramesSinceSif: number = 0;\n\n recordSif() {\n this.consecutiveSifCount += 1;\n this.sifSequenceStartedAt ??= Date.now();\n this.lastSifReceivedAt = Date.now();\n }\n\n recordUserFrame() {\n if (this.sifSequenceStartedAt === undefined) {\n return;\n } else {\n this.userFramesSinceSif += 1;\n }\n if (\n // reset if we received more user frames than SIFs\n this.userFramesSinceSif > this.consecutiveSifCount ||\n // also reset if we got a new user frame and the latest SIF frame hasn't been updated in a while\n Date.now() - this.lastSifReceivedAt > MAX_SIF_DURATION\n ) {\n this.reset();\n }\n }\n\n isSifAllowed() {\n return (\n this.consecutiveSifCount < MAX_SIF_COUNT &&\n (this.sifSequenceStartedAt === undefined ||\n Date.now() - this.sifSequenceStartedAt < MAX_SIF_DURATION)\n );\n }\n\n reset() {\n this.userFramesSinceSif = 0;\n this.consecutiveSifCount = 0;\n this.sifSequenceStartedAt = undefined;\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n// TODO code inspired by https://github.com/webrtc/samples/blob/gh-pages/src/content/insertable-streams/endtoend-encryption/js/worker.js\nimport { EventEmitter } from 'events';\nimport type TypedEventEmitter from 'typed-emitter';\nimport { workerLogger } from '../../logger';\nimport type { VideoCodec } from '../../room/track/options';\nimport { ENCRYPTION_ALGORITHM, IV_LENGTH, UNENCRYPTED_BYTES } from '../constants';\nimport { CryptorError, CryptorErrorReason } from '../errors';\nimport { type CryptorCallbacks, CryptorEvent } from '../events';\nimport type { DecodeRatchetOptions, KeyProviderOptions, KeySet } from '../types';\nimport { deriveKeys, isVideoFrame, needsRbspUnescaping, parseRbsp, writeRbsp } from '../utils';\nimport type { ParticipantKeyHandler } from './ParticipantKeyHandler';\nimport { SifGuard } from './SifGuard';\n\nexport const encryptionEnabledMap: Map<string, boolean> = new Map();\n\nexport interface FrameCryptorConstructor {\n new (opts?: unknown): BaseFrameCryptor;\n}\n\nexport interface TransformerInfo {\n readable: ReadableStream;\n writable: WritableStream;\n transformer: TransformStream;\n abortController: AbortController;\n}\n\nexport class BaseFrameCryptor extends (EventEmitter as new () => TypedEventEmitter<CryptorCallbacks>) {\n protected encodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ): Promise<any> {\n throw Error('not implemented for subclass');\n }\n\n protected decodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ): Promise<any> {\n throw Error('not implemented for subclass');\n }\n}\n\n/**\n * Cryptor is responsible for en-/decrypting media frames.\n * Each Cryptor instance is responsible for en-/decrypting a single mediaStreamTrack.\n */\nexport class FrameCryptor extends BaseFrameCryptor {\n private sendCounts: Map<number, number>;\n\n private participantIdentity: string | undefined;\n\n private trackId: string | undefined;\n\n private keys: ParticipantKeyHandler;\n\n private videoCodec?: VideoCodec;\n\n private rtpMap: Map<number, VideoCodec>;\n\n private keyProviderOptions: KeyProviderOptions;\n\n /**\n * used for detecting server injected unencrypted frames\n */\n private sifTrailer: Uint8Array;\n\n private sifGuard: SifGuard;\n\n private detectedCodec?: VideoCodec;\n\n constructor(opts: {\n keys: ParticipantKeyHandler;\n participantIdentity: string;\n keyProviderOptions: KeyProviderOptions;\n sifTrailer?: Uint8Array;\n }) {\n super();\n this.sendCounts = new Map();\n this.keys = opts.keys;\n this.participantIdentity = opts.participantIdentity;\n this.rtpMap = new Map();\n this.keyProviderOptions = opts.keyProviderOptions;\n this.sifTrailer = opts.sifTrailer ?? Uint8Array.from([]);\n this.sifGuard = new SifGuard();\n }\n\n private get logContext() {\n return {\n participant: this.participantIdentity,\n mediaTrackId: this.trackId,\n fallbackCodec: this.videoCodec,\n };\n }\n\n /**\n * Assign a different participant to the cryptor.\n * useful for transceiver re-use\n * @param id\n * @param keys\n */\n setParticipant(id: string, keys: ParticipantKeyHandler) {\n workerLogger.debug('setting new participant on cryptor', {\n ...this.logContext,\n participant: id,\n });\n if (this.participantIdentity) {\n workerLogger.error(\n 'cryptor has already a participant set, participant should have been unset before',\n {\n ...this.logContext,\n },\n );\n }\n this.participantIdentity = id;\n this.keys = keys;\n this.sifGuard.reset();\n }\n\n unsetParticipant() {\n workerLogger.debug('unsetting participant', this.logContext);\n this.participantIdentity = undefined;\n }\n\n isEnabled() {\n if (this.participantIdentity) {\n return encryptionEnabledMap.get(this.participantIdentity);\n } else {\n return undefined;\n }\n }\n\n getParticipantIdentity() {\n return this.participantIdentity;\n }\n\n getTrackId() {\n return this.trackId;\n }\n\n /**\n * Update the video codec used by the mediaStreamTrack\n * @param codec\n */\n setVideoCodec(codec: VideoCodec) {\n this.videoCodec = codec;\n }\n\n /**\n * rtp payload type map used for figuring out codec of payload type when encoding\n * @param map\n */\n setRtpMap(map: Map<number, VideoCodec>) {\n this.rtpMap = map;\n }\n\n setupTransform(\n operation: 'encode' | 'decode',\n readable: ReadableStream<RTCEncodedVideoFrame | RTCEncodedAudioFrame>,\n writable: WritableStream<RTCEncodedVideoFrame | RTCEncodedAudioFrame>,\n trackId: string,\n codec?: VideoCodec,\n ) {\n if (codec) {\n workerLogger.info('setting codec on cryptor to', { codec });\n this.videoCodec = codec;\n }\n\n workerLogger.debug('Setting up frame cryptor transform', {\n operation,\n passedTrackId: trackId,\n codec,\n ...this.logContext,\n });\n\n const transformFn = operation === 'encode' ? this.encodeFunction : this.decodeFunction;\n const transformStream = new TransformStream({\n transform: transformFn.bind(this),\n });\n\n readable\n .pipeThrough(transformStream)\n .pipeTo(writable)\n .catch((e) => {\n workerLogger.warn(e);\n this.emit(\n CryptorEvent.Error,\n e instanceof CryptorError\n ? e\n : new CryptorError(e.message, undefined, this.participantIdentity),\n );\n });\n this.trackId = trackId;\n }\n\n setSifTrailer(trailer: Uint8Array) {\n workerLogger.debug('setting SIF trailer', { ...this.logContext, trailer });\n this.sifTrailer = trailer;\n }\n\n /**\n * Function that will be injected in a stream and will encrypt the given encoded frames.\n *\n * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame.\n * @param {TransformStreamDefaultController} controller - TransportStreamController.\n *\n * The VP8 payload descriptor described in\n * https://tools.ietf.org/html/rfc7741#section-4.2\n * is part of the RTP packet and not part of the frame and is not controllable by us.\n * This is fine as the SFU keeps having access to it for routing.\n *\n * The encrypted frame is formed as follows:\n * 1) Find unencrypted byte length, depending on the codec, frame type and kind.\n * 2) Form the GCM IV for the frame as described above.\n * 3) Encrypt the rest of the frame using AES-GCM.\n * 4) Allocate space for the encrypted frame.\n * 5) Copy the unencrypted bytes to the start of the encrypted frame.\n * 6) Append the ciphertext to the encrypted frame.\n * 7) Append the IV.\n * 8) Append a single byte for the key identifier.\n * 9) Enqueue the encrypted frame for sending.\n */\n protected async encodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ) {\n if (\n !this.isEnabled() ||\n // skip for encryption for empty dtx frames\n encodedFrame.data.byteLength === 0\n ) {\n return controller.enqueue(encodedFrame);\n }\n const keySet = this.keys.getKeySet();\n if (!keySet) {\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `key set not found for ${\n this.participantIdentity\n } at index ${this.keys.getCurrentKeyIndex()}`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n return;\n }\n const { encryptionKey } = keySet;\n const keyIndex = this.keys.getCurrentKeyIndex();\n\n if (encryptionKey) {\n const iv = this.makeIV(\n encodedFrame.getMetadata().synchronizationSource ?? -1,\n encodedFrame.timestamp,\n );\n let frameInfo = this.getUnencryptedBytes(encodedFrame);\n\n // Thіs is not encrypted and contains the VP8 payload descriptor or the Opus TOC byte.\n const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);\n\n // Frame trailer contains the R|IV_LENGTH and key index\n const frameTrailer = new Uint8Array(2);\n\n frameTrailer[0] = IV_LENGTH;\n frameTrailer[1] = keyIndex;\n\n // Construct frame trailer. Similar to the frame header described in\n // https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2\n // but we put it at the end.\n //\n // ---------+-------------------------+-+---------+----\n // payload |IV...(length = IV_LENGTH)|R|IV_LENGTH|KID |\n // ---------+-------------------------+-+---------+----\n try {\n const cipherText = await crypto.subtle.encrypt(\n {\n name: ENCRYPTION_ALGORITHM,\n iv,\n additionalData: new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength),\n },\n encryptionKey,\n new Uint8Array(encodedFrame.data, frameInfo.unencryptedBytes),\n );\n\n let newDataWithoutHeader = new Uint8Array(\n cipherText.byteLength + iv.byteLength + frameTrailer.byteLength,\n );\n newDataWithoutHeader.set(new Uint8Array(cipherText)); // add ciphertext.\n newDataWithoutHeader.set(new Uint8Array(iv), cipherText.byteLength); // append IV.\n newDataWithoutHeader.set(frameTrailer, cipherText.byteLength + iv.byteLength); // append frame trailer.\n\n if (frameInfo.isH264) {\n newDataWithoutHeader = writeRbsp(newDataWithoutHeader);\n }\n\n var newData = new Uint8Array(frameHeader.byteLength + newDataWithoutHeader.byteLength);\n newData.set(frameHeader);\n newData.set(newDataWithoutHeader, frameHeader.byteLength);\n\n encodedFrame.data = newData.buffer;\n\n return controller.enqueue(encodedFrame);\n } catch (e: any) {\n // TODO: surface this to the app.\n workerLogger.error(e);\n }\n } else {\n workerLogger.debug('failed to encrypt, emitting error', this.logContext);\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `encryption key missing for encoding`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n }\n }\n\n /**\n * Function that will be injected in a stream and will decrypt the given encoded frames.\n *\n * @param {RTCEncodedVideoFrame|RTCEncodedAudioFrame} encodedFrame - Encoded video frame.\n * @param {TransformStreamDefaultController} controller - TransportStreamController.\n */\n protected async decodeFunction(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n controller: TransformStreamDefaultController,\n ) {\n if (\n !this.isEnabled() ||\n // skip for decryption for empty dtx frames\n encodedFrame.data.byteLength === 0\n ) {\n workerLogger.debug('skipping empty frame', this.logContext);\n this.sifGuard.recordUserFrame();\n return controller.enqueue(encodedFrame);\n }\n\n if (isFrameServerInjected(encodedFrame.data, this.sifTrailer)) {\n workerLogger.debug('enqueue SIF', this.logContext);\n this.sifGuard.recordSif();\n\n if (this.sifGuard.isSifAllowed()) {\n encodedFrame.data = encodedFrame.data.slice(\n 0,\n encodedFrame.data.byteLength - this.sifTrailer.byteLength,\n );\n return controller.enqueue(encodedFrame);\n } else {\n workerLogger.warn('SIF limit reached, dropping frame');\n return;\n }\n } else {\n this.sifGuard.recordUserFrame();\n }\n const data = new Uint8Array(encodedFrame.data);\n const keyIndex = data[encodedFrame.data.byteLength - 1];\n\n if (this.keys.hasInvalidKeyAtIndex(keyIndex)) {\n // drop frame\n return;\n }\n\n if (this.keys.getKeySet(keyIndex)) {\n try {\n const decodedFrame = await this.decryptFrame(encodedFrame, keyIndex);\n this.keys.decryptionSuccess(keyIndex);\n if (decodedFrame) {\n return controller.enqueue(decodedFrame);\n }\n } catch (error) {\n if (error instanceof CryptorError && error.reason === CryptorErrorReason.InvalidKey) {\n // emit an error if the key handler thinks we have a valid key\n if (this.keys.hasValidKey) {\n this.emit(CryptorEvent.Error, error);\n this.keys.decryptionFailure(keyIndex);\n }\n } else {\n workerLogger.warn('decoding frame failed', { error });\n }\n }\n } else {\n // emit an error if the key index is out of bounds but the key handler thinks we still have a valid key\n workerLogger.warn(`skipping decryption due to missing key at index ${keyIndex}`);\n this.emit(\n CryptorEvent.Error,\n new CryptorError(\n `missing key at index ${keyIndex} for participant ${this.participantIdentity}`,\n CryptorErrorReason.MissingKey,\n this.participantIdentity,\n ),\n );\n this.keys.decryptionFailure(keyIndex);\n }\n }\n\n /**\n * Function that will decrypt the given encoded frame. If the decryption fails, it will\n * ratchet the key for up to RATCHET_WINDOW_SIZE times.\n */\n private async decryptFrame(\n encodedFrame: RTCEncodedVideoFrame | RTCEncodedAudioFrame,\n keyIndex: number,\n initialMaterial: KeySet | undefined = undefined,\n ratchetOpts: DecodeRatchetOptions = { ratchetCount: 0 },\n ): Promise<RTCEncodedVideoFrame | RTCEncodedAudioFrame | undefined> {\n const keySet = this.keys.getKeySet(keyIndex);\n if (!ratchetOpts.encryptionKey && !keySet) {\n throw new TypeError(`no encryption key found for decryption of ${this.participantIdentity}`);\n }\n let frameInfo = this.getUnencryptedBytes(encodedFrame);\n\n // Construct frame trailer. Similar to the frame header described in\n // https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2\n // but we put it at the end.\n //\n // ---------+-------------------------+-+---------+----\n // payload |IV...(length = IV_LENGTH)|R|IV_LENGTH|KID |\n // ---------+-------------------------+-+---------+----\n\n try {\n const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);\n var encryptedData = new Uint8Array(\n encodedFrame.data,\n frameHeader.length,\n encodedFrame.data.byteLength - frameHeader.length,\n );\n if (frameInfo.isH264 && needsRbspUnescaping(encryptedData)) {\n encryptedData = parseRbsp(encryptedData);\n const newUint8 = new Uint8Array(frameHeader.byteLength + encryptedData.byteLength);\n newUint8.set(frameHeader);\n newUint8.set(encryptedData, frameHeader.byteLength);\n encodedFrame.data = newUint8.buffer;\n }\n\n const frameTrailer = new Uint8Array(encodedFrame.data, encodedFrame.data.byteLength - 2, 2);\n\n const ivLength = frameTrailer[0];\n const iv = new Uint8Array(\n encodedFrame.data,\n encodedFrame.data.byteLength - ivLength - frameTrailer.byteLength,\n ivLength,\n );\n\n const cipherTextStart = frameHeader.byteLength;\n const cipherTextLength =\n encodedFrame.data.byteLength -\n (frameHeader.byteLength + ivLength + frameTrailer.byteLength);\n\n const plainText = await crypto.subtle.decrypt(\n {\n name: ENCRYPTION_ALGORITHM,\n iv,\n additionalData: new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength),\n },\n ratchetOpts.encryptionKey ?? keySet!.encryptionKey,\n new Uint8Array(encodedFrame.data, cipherTextStart, cipherTextLength),\n );\n\n const newData = new ArrayBuffer(frameHeader.byteLength + plainText.byteLength);\n const newUint8 = new Uint8Array(newData);\n\n newUint8.set(new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength));\n newUint8.set(new Uint8Array(plainText), frameHeader.byteLength);\n\n encodedFrame.data = newData;\n\n return encodedFrame;\n } catch (error: any) {\n if (this.keyProviderOptions.ratchetWindowSize > 0) {\n if (ratchetOpts.ratchetCount < this.keyProviderOptions.ratchetWindowSize) {\n workerLogger.debug(\n `ratcheting key attempt ${ratchetOpts.ratchetCount} of ${\n this.keyProviderOptions.ratchetWindowSize\n }, for kind ${encodedFrame instanceof RTCEncodedAudioFrame ? 'audio' : 'video'}`,\n );\n\n let ratchetedKeySet: KeySet | undefined;\n if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {\n // only ratchet if the currently set key is still the same as the one used to decrypt this frame\n // if not, it might be that a different frame has already ratcheted and we try with that one first\n const newMaterial = await this.keys.ratchetKey(keyIndex, false);\n\n ratchetedKeySet = await deriveKeys(newMaterial, this.keyProviderOptions.ratchetSalt);\n }\n\n const frame = await this.decryptFrame(encodedFrame, keyIndex, initialMaterial || keySet, {\n ratchetCount: ratchetOpts.ratchetCount + 1,\n encryptionKey: ratchetedKeySet?.encryptionKey,\n });\n if (frame && ratchetedKeySet) {\n // before updating the keys, make sure that the keySet used for this frame is still the same as the currently set key\n // if it's not, a new key might have been set already, which we don't want to override\n if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {\n this.keys.setKeySet(ratchetedKeySet, keyIndex, true);\n // decryption was successful, set the new key index to reflect the ratcheted key set\n this.keys.setCurrentKeyIndex(keyIndex);\n }\n }\n return frame;\n } else {\n /**\n * Because we only set a new key once decryption has been successful,\n * we can be sure that we don't need to reset the key to the initial material at this point\n * as the key has not been updated on the keyHandler instance\n */\n\n workerLogger.warn('maximum ratchet attempts exceeded');\n throw new CryptorError(\n `valid key missing for participant ${this.participantIdentity}`,\n CryptorErrorReason.InvalidKey,\n this.participantIdentity,\n );\n }\n } else {\n throw new CryptorError(\n `Decryption failed: ${error.message}`,\n CryptorErrorReason.InvalidKey,\n this.participantIdentity,\n );\n }\n }\n }\n\n /**\n * Construct the IV used for AES-GCM and sent (in plain) with the packet similar to\n * https://tools.ietf.org/html/rfc7714#section-8.1\n * It concatenates\n * - the 32 bit synchronization source (SSRC) given on the encoded frame,\n * - the 32 bit rtp timestamp given on the encoded frame,\n * - a send counter that is specific to the SSRC. Starts at a random number.\n * The send counter is essentially the pictureId but we currently have to implement this ourselves.\n * There is no XOR with a salt. Note that this IV leaks the SSRC to the receiver but since this is\n * randomly generated and SFUs may not rewrite this is considered acceptable.\n * The SSRC is used to allow demultiplexing multiple streams with the same key, as described in\n * https://tools.ietf.org/html/rfc3711#section-4.1.1\n * The RTP timestamp is 32 bits and advances by the codec clock rate (90khz for video, 48khz for\n * opus audio) every second. For video it rolls over roughly every 13 hours.\n * The send counter will advance at the frame rate (30fps for video, 50fps for 20ms opus audio)\n * every second. It will take a long time to roll over.\n *\n * See also https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams\n */\n private makeIV(synchronizationSource: number, timestamp: number) {\n const iv = new ArrayBuffer(IV_LENGTH);\n const ivView = new DataView(iv);\n\n // having to keep our own send count (similar to a picture id) is not ideal.\n if (!this.sendCounts.has(synchronizationSource)) {\n // Initialize with a random offset, similar to the RTP sequence number.\n this.sendCounts.set(synchronizationSource, Math.floor(Math.random() * 0xffff));\n }\n\n const sendCount = this.sendCounts.get(synchronizationSource) ?? 0;\n\n ivView.setUint32(0, synchronizationSource);\n ivView.setUint32(4, timestamp);\n ivView.setUint32(8, timestamp - (sendCount % 0xffff));\n\n this.sendCounts.set(synchronizationSource, sendCount + 1);\n\n return iv;\n }\n\n private getUnencryptedBytes(frame: RTCEncodedVideoFrame | RTCEncodedAudioFrame): {\n unencryptedBytes: number;\n isH264: boolean;\n } {\n var frameInfo = { unencryptedBytes: 0, isH264: false };\n if (isVideoFrame(frame)) {\n let detectedCodec = this.getVideoCodec(frame) ?? this.videoCodec;\n if (detectedCodec !== this.detectedCodec) {\n workerLogger.debug('detected different codec', {\n detectedCodec,\n oldCodec: this.detectedCodec,\n ...this.logContext,\n });\n this.detectedCodec = detectedCodec;\n }\n\n if (detectedCodec === 'av1') {\n throw new Error(`${detectedCodec} is not yet supported for end to end encryption`);\n }\n\n if (detectedCodec === 'vp8') {\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];\n } else if (detectedCodec === 'vp9') {\n frameInfo.unencryptedBytes = 0;\n return frameInfo;\n }\n\n const data = new Uint8Array(frame.data);\n try {\n const naluIndices = findNALUIndices(data);\n\n // if the detected codec is undefined we test whether it _looks_ like a h264 frame as a best guess\n frameInfo.isH264 =\n detectedCodec === 'h264' ||\n naluIndices.some((naluIndex) =>\n [NALUType.SLICE_IDR, NALUType.SLICE_NON_IDR].includes(parseNALUType(data[naluIndex])),\n );\n\n if (frameInfo.isH264) {\n for (const index of naluIndices) {\n let type = parseNALUType(data[index]);\n switch (type) {\n case NALUType.SLICE_IDR:\n case NALUType.SLICE_NON_IDR:\n frameInfo.unencryptedBytes = index + 2;\n return frameInfo;\n default:\n break;\n }\n }\n throw new TypeError('Could not find NALU');\n }\n } catch (e) {\n // no op, we just continue and fallback to vp8\n }\n\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];\n return frameInfo;\n } else {\n frameInfo.unencryptedBytes = UNENCRYPTED_BYTES.audio;\n return frameInfo;\n }\n }\n\n /**\n * inspects frame payloadtype if available and maps it to the codec specified in rtpMap\n */\n private getVideoCodec(frame: RTCEncodedVideoFrame): VideoCodec | undefined {\n if (this.rtpMap.size === 0) {\n return undefined;\n }\n const payloadType = frame.getMetadata().payloadType;\n const codec = payloadType ? this.rtpMap.get(payloadType) : undefined;\n return codec;\n }\n}\n\n/**\n * Slice the NALUs present in the supplied buffer, assuming it is already byte-aligned\n * code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only\n */\nexport function findNALUIndices(stream: Uint8Array): number[] {\n const result: number[] = [];\n let start = 0,\n pos = 0,\n searchLength = stream.length - 2;\n while (pos < searchLength) {\n // skip until end of current NALU\n while (\n pos < searchLength &&\n !(stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 1)\n )\n pos++;\n if (pos >= searchLength) pos = stream.length;\n // remove trailing zeros from current NALU\n let end = pos;\n while (end > start && stream[end - 1] === 0) end--;\n // save current NALU\n if (start === 0) {\n if (end !== start) throw TypeError('byte stream contains leading data');\n } else {\n result.push(start);\n }\n // begin new NALU\n start = pos = pos + 3;\n }\n return result;\n}\n\nexport function parseNALUType(startByte: number): NALUType {\n return startByte & kNaluTypeMask;\n}\n\nconst kNaluTypeMask = 0x1f;\n\nexport enum NALUType {\n /** Coded slice of a non-IDR picture */\n SLICE_NON_IDR = 1,\n /** Coded slice data partition A */\n SLICE_PARTITION_A = 2,\n /** Coded slice data partition B */\n SLICE_PARTITION_B = 3,\n /** Coded slice data partition C */\n SLICE_PARTITION_C = 4,\n /** Coded slice of an IDR picture */\n SLICE_IDR = 5,\n /** Supplemental enhancement information */\n SEI = 6,\n /** Sequence parameter set */\n SPS = 7,\n /** Picture parameter set */\n PPS = 8,\n /** Access unit delimiter */\n AUD = 9,\n /** End of sequence */\n END_SEQ = 10,\n /** End of stream */\n END_STREAM = 11,\n /** Filler data */\n FILLER_DATA = 12,\n /** Sequence parameter set extension */\n SPS_EXT = 13,\n /** Prefix NAL unit */\n PREFIX_NALU = 14,\n /** Subset sequence parameter set */\n SUBSET_SPS = 15,\n /** Depth parameter set */\n DPS = 16,\n\n // 17, 18 reserved\n\n /** Coded slice of an auxiliary coded picture without partitioning */\n SLICE_AUX = 19,\n /** Coded slice extension */\n SLICE_EXT = 20,\n /** Coded slice extension for a depth view component or a 3D-AVC texture view component */\n SLICE_LAYER_EXT = 21,\n\n // 22, 23 reserved\n}\n\n/**\n * we use a magic frame trailer to detect whether a frame is injected\n * by the livekit server and thus to be treated as unencrypted\n * @internal\n */\nexport function isFrameServerInjected(frameData: ArrayBuffer, trailerBytes: Uint8Array): boolean {\n if (trailerBytes.byteLength === 0) {\n return false;\n }\n const frameTrailer = new Uint8Array(\n frameData.slice(frameData.byteLength - trailerBytes.byteLength),\n );\n return trailerBytes.every((value, index) => value === frameTrailer[index]);\n}\n","import { EventEmitter } from 'events';\nimport type TypedEventEmitter from 'typed-emitter';\nimport { workerLogger } from '../../logger';\nimport { KeyHandlerEvent, type ParticipantKeyHandlerCallbacks } from '../events';\nimport type { KeyProviderOptions, KeySet } from '../types';\nimport { deriveKeys, importKey, ratchet } from '../utils';\n\n// TODO ParticipantKeyHandlers currently don't get destroyed on participant disconnect\n// we could do this by having a separate worker message on participant disconnected.\n\n/**\n * ParticipantKeyHandler is responsible for providing a cryptor instance with the\n * en-/decryption key of a participant. It assumes that all tracks of a specific participant\n * are encrypted with the same key.\n * Additionally it exposes a method to ratchet a key which can be used by the cryptor either automatically\n * if decryption fails or can be triggered manually on both sender and receiver side.\n *\n */\nexport class ParticipantKeyHandler extends (EventEmitter as new () => TypedEventEmitter<ParticipantKeyHandlerCallbacks>) {\n private currentKeyIndex: number;\n\n private cryptoKeyRing: Array<KeySet | undefined>;\n\n private decryptionFailureCounts: Array<number>;\n\n private keyProviderOptions: KeyProviderOptions;\n\n private ratchetPromiseMap: Map<number, Promise<CryptoKey>>;\n\n private participantIdentity: string;\n\n /**\n * true if the current key has not been marked as invalid\n */\n get hasValidKey(): boolean {\n return !this.hasInvalidKeyAtIndex(this.currentKeyIndex);\n }\n\n constructor(participantIdentity: string, keyProviderOptions: KeyProviderOptions) {\n super();\n this.currentKeyIndex = 0;\n if (keyProviderOptions.keyringSize < 1 || keyProviderOptions.keyringSize > 256) {\n throw new TypeError('Keyring size needs to be between 1 and 256');\n }\n this.cryptoKeyRing = new Array(keyProviderOptions.keyringSize).fill(undefined);\n this.decryptionFailureCounts = new Array(keyProviderOptions.keyringSize).fill(0);\n this.keyProviderOptions = keyProviderOptions;\n this.ratchetPromiseMap = new Map();\n this.participantIdentity = participantIdentity;\n }\n\n /**\n * Returns true if the key at the given index is marked as invalid.\n *\n * @param keyIndex the index of the key\n */\n hasInvalidKeyAtIndex(keyIndex: number): boolean {\n return (\n this.keyProviderOptions.failureTolerance >= 0 &&\n this.decryptionFailureCounts[keyIndex] > this.keyProviderOptions.failureTolerance\n );\n }\n\n /**\n * Informs the key handler that a decryption failure occurred for an encryption key.\n * @internal\n * @param keyIndex the key index for which the failure occurred. Defaults to the current key index.\n */\n decryptionFailure(keyIndex: number = this.currentKeyIndex): void {\n if (this.keyProviderOptions.failureTolerance < 0) {\n return;\n }\n\n this.decryptionFailureCounts[keyIndex] += 1;\n\n if (this.decryptionFailureCounts[keyIndex] > this.keyProviderOptions.failureTolerance) {\n workerLogger.warn(\n `key for ${this.participantIdentity} at index ${keyIndex} is being marked as invalid`,\n );\n }\n }\n\n /**\n * Informs the key handler that a frame was successfully decrypted using an encryption key.\n * @internal\n * @param keyIndex the key index for which the success occurred. Defaults to the current key index.\n */\n decryptionSuccess(keyIndex: number = this.currentKeyIndex): void {\n this.resetKeyStatus(keyIndex);\n }\n\n /**\n * Call this after user initiated ratchet or a new key has been set in order to make sure to mark potentially\n * invalid keys as valid again\n *\n * @param keyIndex the index of the key. Defaults to the current key index.\n */\n resetKeyStatus(keyIndex?: number): void {\n if (keyIndex === undefined) {\n this.decryptionFailureCounts.fill(0);\n } else {\n this.decryptionFailureCounts[keyIndex] = 0;\n }\n }\n\n /**\n * Ratchets the current key (or the one at keyIndex if provided) and\n * returns the ratcheted material\n * if `setKey` is true (default), it will also set the ratcheted key directly on the crypto key ring\n * @param keyIndex\n * @param setKey\n */\n ratchetKey(keyIndex?: number, setKey = true): Promise<CryptoKey> {\n const currentKeyIndex = keyIndex ?? this.getCurrentKeyIndex();\n\n const existingPromise = this.ratchetPromiseMap.get(currentKeyIndex);\n if (typeof existingPromise !== 'undefined') {\n return existingPromise;\n }\n const ratchetPromise = new Promise<CryptoKey>(async (resolve, reject) => {\n try {\n const keySet = this.getKeySet(currentKeyIndex);\n if (!keySet) {\n throw new TypeError(\n `Cannot ratchet key without a valid keyset of participant ${this.participantIdentity}`,\n );\n }\n const currentMaterial = keySet.material;\n const newMaterial = await importKey(\n await ratchet(currentMaterial, this.keyProviderOptions.ratchetSalt),\n currentMaterial.algorithm.name,\n 'derive',\n );\n\n if (setKey) {\n await this.setKeyFromMaterial(newMaterial, currentKeyIndex, true);\n this.emit(\n KeyHandlerEvent.KeyRatcheted,\n newMaterial,\n this.participantIdentity,\n currentKeyIndex,\n );\n }\n resolve(newMaterial);\n } catch (e) {\n reject(e);\n } finally {\n this.ratchetPromiseMap.delete(currentKeyIndex);\n }\n });\n this.ratchetPromiseMap.set(currentKeyIndex, ratchetPromise);\n return ratchetPromise;\n }\n\n /**\n * takes in a key material with `deriveBits` and `deriveKey` set as key usages\n * and derives encryption keys from the material and sets it on the key ring buffer\n * together with the material\n * also resets the valid key property and updates the currentKeyIndex\n */\n async setKey(material: CryptoKey, keyIndex = 0) {\n await this.setKeyFromMaterial(material, keyIndex);\n this.resetKeyStatus(keyIndex);\n }\n\n /**\n * takes in a key material with `deriveBits` and `deriveKey` set as key usages\n * and derives encryption keys from the material and sets it on the key ring buffers\n * together with the material\n * also updates the currentKeyIndex\n */\n async setKeyFromMaterial(material: CryptoKey, keyIndex: number, emitRatchetEvent = false) {\n const keySet = await deriveKeys(material, this.keyProviderOptions.ratchetSalt);\n const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : this.currentKeyIndex;\n workerLogger.debug(`setting new key with index ${keyIndex}`, {\n usage: material.usages,\n algorithm: material.algorithm,\n ratchetSalt: this.keyProviderOptions.ratchetSalt,\n });\n this.setKeySet(keySet, newIndex, emitRatchetEvent);\n if (newIndex >= 0) this.currentKeyIndex = newIndex;\n }\n\n setKeySet(keySet: KeySet, keyIndex: number, emitRatchetEvent = false) {\n this.cryptoKeyRing[keyIndex % this.cryptoKeyRing.length] = keySet;\n\n if (emitRatchetEvent) {\n this.emit(KeyHandlerEvent.KeyRatcheted, keySet.material, this.participantIdentity, keyIndex);\n }\n }\n\n async setCurrentKeyIndex(index: number) {\n this.currentKeyIndex = index % this.cryptoKeyRing.length;\n this.resetKeyStatus(index);\n }\n\n getCurrentKeyIndex() {\n return this.currentKeyIndex;\n }\n\n /**\n * returns currently used KeySet or the one at `keyIndex` if provided\n * @param keyIndex\n * @returns\n */\n getKeySet(keyIndex?: number) {\n return this.cryptoKeyRing[keyIndex ?? this.currentKeyIndex];\n }\n}\n","import { workerLogger } from '../../logger';\nimport type { VideoCodec } from '../../room/track/options';\nimport { AsyncQueue } from '../../utils/AsyncQueue';\nimport { KEY_PROVIDER_DEFAULTS } from '../constants';\nimport { CryptorErrorReason } from '../errors';\nimport { CryptorEvent, KeyHandlerEvent } from '../events';\nimport type {\n E2EEWorkerMessage,\n ErrorMessage,\n InitAck,\n KeyProviderOptions,\n RatchetMessage,\n RatchetRequestMessage,\n} from '../types';\nimport { FrameCryptor, encryptionEnabledMap } from './FrameCryptor';\nimport { ParticipantKeyHandler } from './ParticipantKeyHandler';\n\nconst participantCryptors: FrameCryptor[] = [];\nconst participantKeys: Map<string, ParticipantKeyHandler> = new Map();\nlet sharedKeyHandler: ParticipantKeyHandler | undefined;\nlet messageQueue = new AsyncQueue();\n\nlet isEncryptionEnabled: boolean = false;\n\nlet useSharedKey: boolean = false;\n\nlet sifTrailer: Uint8Array | undefined;\n\nlet keyProviderOptions: KeyProviderOptions = KEY_PROVIDER_DEFAULTS;\n\nlet rtpMap: Map<number, VideoCodec> = new Map();\n\nworkerLogger.setDefaultLevel('info');\n\nonmessage = (ev) => {\n messageQueue.run(async () => {\n const { kind, data }: E2EEWorkerMessage = ev.data;\n\n switch (kind) {\n case 'init':\n workerLogger.setLevel(data.loglevel);\n workerLogger.info('worker initialized');\n keyProviderOptions = data.keyProviderOptions;\n useSharedKey = !!data.keyProviderOptions.sharedKey;\n // acknowledge init successful\n const ackMsg: InitAck = {\n kind: 'initAck',\n data: { enabled: isEncryptionEnabled },\n };\n postMessage(ackMsg);\n break;\n case 'enable':\n setEncryptionEnabled(data.enabled, data.participantIdentity);\n workerLogger.info(\n `updated e2ee enabled status for ${data.participantIdentity} to ${data.enabled}`,\n );\n // acknowledge enable call successful\n postMessage(ev.data);\n break;\n case 'decode':\n let cryptor = getTrackCryptor(data.participantIdentity, data.trackId);\n cryptor.setupTransform(\n kind,\n data.readableStream,\n data.writableStream,\n data.trackId,\n data.codec,\n );\n break;\n case 'encode':\n let pubCryptor = getTrackCryptor(data.participantIdentity, data.trackId);\n pubCryptor.setupTransform(\n kind,\n data.readableStream,\n data.writableStream,\n data.trackId,\n data.codec,\n );\n break;\n case 'setKey':\n if (useSharedKey) {\n await setSharedKey(data.key, data.keyIndex);\n } else if (data.participantIdentity) {\n workerLogger.info(\n `set participant sender key ${data.participantIdentity} index ${data.keyIndex}`,\n );\n await getParticipantKeyHandler(data.participantIdentity).setKey(data.key, data.keyIndex);\n } else {\n workerLogger.error('no participant Id was provided and shared key usage is disabled');\n }\n break;\n case 'removeTransform':\n unsetCryptorParticipant(data.trackId, data.participantIdentity);\n break;\n case 'updateCodec':\n getTrackCryptor(data.participantIdentity, data.trackId).setVideoCodec(data.codec);\n break;\n case 'setRTPMap':\n // this is only used for the local participant\n rtpMap = data.map;\n participantCryptors.forEach((cr) => {\n if (cr.getParticipantIdentity() === data.participantIdentity) {\n cr.setRtpMap(data.map);\n }\n });\n break;\n case 'ratchetRequest':\n handleRatchetRequest(data);\n break;\n case 'setSifTrailer':\n handleSifTrailer(data.trailer);\n break;\n default:\n break;\n }\n });\n};\n\nasync function handleRatchetRequest(data: RatchetRequestMessage['data']) {\n if (useSharedKey) {\n const keyHandler = getSharedKeyHandler();\n await keyHandler.ratchetKey(data.keyIndex);\n keyHandler.resetKeyStatus();\n } else if (data.participantIdentity) {\n const keyHandler = getParticipantKeyHandler(data.participantIdentity);\n await keyHandler.ratchetKey(data.keyIndex);\n keyHandler.resetKeyStatus();\n } else {\n workerLogger.error(\n 'no participant Id was provided for ratchet request and shared key usage is disabled',\n );\n }\n}\n\nfunction getTrackCryptor(participantIdentity: string, trackId: string) {\n let cryptors = participantCryptors.filter((c) => c.getTrackId() === trackId);\n if (cryptors.length > 1) {\n const debugInfo = cryptors\n .map((c) => {\n return { participant: c.getParticipantIdentity() };\n })\n .join(',');\n workerLogger.error(\n `Found multiple cryptors for the same trackID ${trackId}. target participant: ${participantIdentity} `,\n { participants: debugInfo },\n );\n }\n let cryptor = cryptors[0];\n if (!cryptor) {\n workerLogger.info('creating new cryptor for', { participantIdentity });\n if (!keyProviderOptions) {\n throw Error('Missing keyProvider options');\n }\n cryptor = new FrameCryptor({\n participantIdentity,\n keys: getParticipantKeyHandler(participantIdentity),\n keyProviderOptions,\n sifTrailer,\n });\n cryptor.setRtpMap(rtpMap);\n setupCryptorErrorEvents(cryptor);\n participantCryptors.push(cryptor);\n } else if (participantIdentity !== cryptor.getParticipantIdentity()) {\n // assign new participant id to track cryptor and pass in correct key handler\n cryptor.setParticipant(participantIdentity, getParticipantKeyHandler(participantIdentity));\n }\n\n return cryptor;\n}\n\nfunction getParticipantKeyHandler(participantIdentity: string) {\n if (useSharedKey) {\n return getSharedKeyHandler();\n }\n let keys = participantKeys.get(participantIdentity);\n if (!keys) {\n keys = new ParticipantKeyHandler(participantIdentity, keyProviderOptions);\n keys.on(KeyHandlerEvent.KeyRatcheted, emitRatchetedKeys);\n participantKeys.set(participantIdentity, keys);\n }\n return keys;\n}\n\nfunction getSharedKeyHandler() {\n if (!sharedKeyHandler) {\n workerLogger.debug('creating new shared key handler');\n sharedKeyHandler = new ParticipantKeyHandler('shared-key', keyProviderOptions);\n }\n return sharedKeyHandler;\n}\n\nfunction unsetCryptorParticipant(trackId: string, participantIdentity: string) {\n const cryptors = participantCryptors.filter(\n (c) => c.getParticipantIdentity() === participantIdentity && c.getTrackId() === trackId,\n );\n if (cryptors.length > 1) {\n workerLogger.error('Found multiple cryptors for the same participant and trackID combination', {\n trackId,\n participantIdentity,\n });\n }\n const cryptor = cryptors[0];\n if (!cryptor) {\n workerLogger.warn('Could not unset participant on cryptor', { trackId, participantIdentity });\n } else {\n cryptor.unsetParticipant();\n }\n}\n\nfunction setEncryptionEnabled(enable: boolean, participantIdentity: string) {\n workerLogger.debug(`setting encryption enabled for all tracks of ${participantIdentity}`, {\n enable,\n });\n encryptionEnabledMap.set(participantIdentity, enable);\n}\n\nasync function setSharedKey(key: CryptoKey, index?: number) {\n workerLogger.info('set shared key', { index });\n await getSharedKeyHandler().setKey(key, index);\n}\n\nfunction setupCryptorErrorEvents(cryptor: FrameCryptor) {\n cryptor.on(CryptorEvent.Error, (error) => {\n const msg: ErrorMessage = {\n kind: 'error',\n data: { error: new Error(`${CryptorErrorReason[error.reason]}: ${error.message}`) },\n };\n postMessage(msg);\n });\n}\n\nfunction emitRatchetedKeys(material: CryptoKey, participantIdentity: string, keyIndex?: number) {\n const msg: RatchetMessage = {\n kind: `ratchetKey`,\n data: {\n participantIdentity,\n keyIndex,\n material,\n },\n };\n postMessage(msg);\n}\n\nfunction handleSifTrailer(trailer: Uint8Array) {\n sifTrailer = trailer;\n participantCryptors.forEach((c) => {\n c.setSifTrailer(trailer);\n });\n}\n\n// Operations using RTCRtpScriptTransform.\n// @ts-ignore\nif (self.RTCTransformEvent) {\n workerLogger.debug('setup transform event');\n // @ts-ignore\n self.onrtctransform = (event: RTCTransformEvent) => {\n // @ts-ignore .transformer property is part of RTCTransformEvent\n const transformer = event.transformer;\n workerLogger.debug('transformer', transformer);\n // @ts-ignore monkey patching non standard flag\n transformer.handled = true;\n const { kind, participantIdentity, trackId, codec } = transformer.options;\n const cryptor = getTrackCryptor(participantIdentity, trackId);\n workerLogger.debug('transform', { codec });\n cryptor.setupTransform(kind, transformer.readable, transformer.writable, trackId, codec);\n };\n}\n"],"names":["root","definition","LogLevel","LoggerNames","noop","undefinedType","isIE","window","navigator","test","userAgent","logMethods","_loggersByName","defaultLogger","bindMethod","obj","methodName","method","bind","Function","prototype","call","e","apply","arguments","traceForIE","console","log","trace","replaceLoggingMethods","level","this","getLevel","i","length","methodFactory","name","debug","levels","SILENT","enableLoggingWhenConsoleArrives","defaultMethodFactory","_level","_loggerName","undefined","realMethod","Logger","factory","inheritedLevel","defaultLevel","userLevel","self","storageKey","getPersistedLevel","storedLevel","localStorage","ignore","cookie","document","cookieName","encodeURIComponent","location","indexOf","exec","slice","normalizeLevel","input","toUpperCase","TypeError","TRACE","DEBUG","INFO","WARN","ERROR","setLevel","persist","levelNum","levelName","persistLevelIfPossible","setDefaultLevel","resetLevel","removeItem","clearPersistedLevel","enableAll","disableAll","rebuild","childName","initialLevel","getLogger","logger","_log","noConflict","getLoggers","exports","module","livekitLogger","Object","values","map","info","workerLogger","QueueTaskStatus","h","constructor","l","_locking","Promise","resolve","_locks","isLocked","lock","o","c","unlockNext","t","then","ENCRYPTION_ALGORITHM","UNENCRYPTED_BYTES","key","delta","audio","empty","KEY_PROVIDER_DEFAULTS","sharedKey","ratchetSalt","ratchetWindowSize","failureTolerance","keyringSize","LivekitError","Error","code","message","super","ConnectionErrorReason","MediaDeviceFailure","CryptorErrorReason","KeyProviderEvent","KeyHandlerEvent","EncryptionEvent","CryptorEvent","getFailure","error","NotFound","PermissionDenied","DeviceInUse","Other","CryptorError","reason","InternalError","participantIdentity","ReflectOwnKeys","R","Reflect","ReflectApply","target","receiver","args","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","concat","NumberIsNaN","Number","isNaN","value","EventEmitter","init","eventsModule","once","emitter","reject","errorListener","err","removeListener","resolver","eventTargetAgnosticAddListener","handler","flags","on","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","_getMaxListeners","that","_addListener","type","prepend","m","events","existing","warning","create","newListener","emit","unshift","push","warned","w","String","count","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","_listeners","unwrap","evlistener","arr","ret","Array","unwrapListeners","arrayClone","listenerCount","n","copy","addEventListener","wrapListener","arg","removeEventListener","defineProperty","enumerable","get","set","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","context","len","listeners","addListener","prependListener","prependOnceListener","list","position","originalListener","shift","index","pop","spliceOne","off","removeAllListeners","keys","rawListeners","eventNames","getAlgoOptions","algorithmName","salt","encodedSalt","TextEncoder","encode","hash","ArrayBuffer","iterations","deriveKeys","material","algorithmOptions","algorithm","encryptionKey","crypto","subtle","deriveKey","SifGuard","consecutiveSifCount","lastSifReceivedAt","userFramesSinceSif","recordSif","_a","sifSequenceStartedAt","Date","now","recordUserFrame","reset","isSifAllowed","encryptionEnabledMap","Map","BaseFrameCryptor","encodeFunction","encodedFrame","controller","decodeFunction","FrameCryptor","opts","sendCounts","rtpMap","keyProviderOptions","sifTrailer","Uint8Array","from","sifGuard","logContext","participant","mediaTrackId","trackId","fallbackCodec","videoCodec","setParticipant","id","assign","unsetParticipant","isEnabled","getParticipantIdentity","getTrackId","setVideoCodec","codec","setRtpMap","setupTransform","operation","readable","writable","passedTrackId","transformFn","transformStream","TransformStream","transform","pipeThrough","pipeTo","catch","setSifTrailer","trailer","data","byteLength","enqueue","keySet","getKeySet","getCurrentKeyIndex","MissingKey","keyIndex","iv","makeIV","getMetadata","synchronizationSource","timestamp","frameInfo","getUnencryptedBytes","frameHeader","unencryptedBytes","frameTrailer","cipherText","encrypt","additionalData","newDataWithoutHeader","isH264","data_in","dataOut","numConsecutiveZeros","byte","writeRbsp","newData","buffer","frameData","trailerBytes","every","isFrameServerInjected","hasInvalidKeyAtIndex","decodedFrame","decryptFrame","decryptionSuccess","InvalidKey","hasValidKey","decryptionFailure","encodedFrame_1","keyIndex_1","_this","initialMaterial","ratchetOpts","ratchetCount","encryptedData","needsRbspUnescaping","stream","parseRbsp","newUint8","ivLength","cipherTextStart","cipherTextLength","plainText","decrypt","ratchetedKeySet","RTCEncodedAudioFrame","newMaterial","ratchetKey","frame","setKeySet","setCurrentKeyIndex","ivView","DataView","has","Math","floor","random","sendCount","setUint32","isVideoFrame","detectedCodec","getVideoCodec","oldCodec","naluIndices","result","start","pos","searchLength","end","findNALUIndices","some","naluIndex","NALUType","SLICE_IDR","SLICE_NON_IDR","includes","parseNALUType","size","payloadType","startByte","kNaluTypeMask","ParticipantKeyHandler","currentKeyIndex","cryptoKeyRing","fill","decryptionFailureCounts","ratchetPromiseMap","resetKeyStatus","setKey","existingPromise","ratchetPromise","__awaiter","currentMaterial","keyBytes_1","keyBytes","usage","importKey","deriveBits","ratchet","setKeyFromMaterial","KeyRatcheted","delete","material_1","_this2","emitRatchetEvent","newIndex","usages","participantCryptors","participantKeys","sharedKeyHandler","messageQueue","pendingTasks","taskMutex","Mutex","nextTaskIndex","run","task","taskInfo","enqueuedAt","status","WAITING","unlock","executedAt","RUNNING","COMPLETED","flush","snapshot","useSharedKey","getTrackCryptor","cryptors","filter","debugInfo","join","participants","cryptor","getParticipantKeyHandler","msg","kind","postMessage","setupCryptorErrorEvents","getSharedKeyHandler","emitRatchetedKeys","onmessage","ev","loglevel","enabled","enable","readableStream","writableStream","setSharedKey","unsetCryptorParticipant","forEach","cr","keyHandler","handleRatchetRequest","RTCTransformEvent","onrtctransform","event","transformer","handled","options"],"mappings":"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","x_google_ignoreList":[0,3,8]}