livekit-client 2.6.1 → 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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":"+cAMWA,EAAMC,ECJLC,EASAC,aDLDH,YAAMC,EAST,WAIJ,IAAIG,EAAO,aACPC,EAAgB,YAChBC,SAAeC,SAAWF,UAA0BE,OAAOC,YAAcH,GACzE,kBAAkBI,KAAKF,OAAOC,UAAUE,WAGxCC,EAAa,CACb,QACA,QACA,OACA,OACA,SAGAC,EAAiB,CAAA,EACjBC,EAAgB,KAGpB,SAASC,EAAWC,EAAKC,GACrB,IAAIC,EAASF,EAAIC,GACjB,GAA2B,mBAAhBC,EAAOC,KACd,OAAOD,EAAOC,KAAKH,GAEnB,IACI,OAAOI,SAASC,UAAUF,KAAKG,KAAKJ,EAAQF,EAC/C,CAAC,MAAOO,GAEL,OAAO,WACH,OAAOH,SAASC,UAAUG,MAAMA,MAAMN,EAAQ,CAACF,EAAKS,YAE3D,CAER,CAGD,SAASC,IACDC,QAAQC,MACJD,QAAQC,IAAIJ,MACZG,QAAQC,IAAIJ,MAAMG,QAASF,WAG3BL,SAASC,UAAUG,MAAMA,MAAMG,QAAQC,IAAK,CAACD,QAASF,aAG1DE,QAAQE,OAAOF,QAAQE,OAC9B,CAwBD,SAASC,IAKL,IAHA,IAAIC,EAAQC,KAAKC,WAGRC,EAAI,EAAGA,EAAItB,EAAWuB,OAAQD,IAAK,CACxC,IAAIjB,EAAaL,EAAWsB,GAC5BF,KAAKf,GAAeiB,EAAIH,EACpB1B,EACA2B,KAAKI,cAAcnB,EAAYc,EAAOC,KAAKK,KAClD,CAMD,GAHAL,KAAKJ,IAAMI,KAAKM,aAGLX,UAAYrB,GAAiByB,EAAQC,KAAKO,OAAOC,OACxD,MAAO,kCAEd,CAID,SAASC,EAAgCxB,GACrC,OAAO,kBACQU,UAAYrB,IACnBwB,EAAsBR,KAAKU,MAC3BA,KAAKf,GAAYO,MAAMQ,KAAMP,YAGxC,CAID,SAASiB,EAAqBzB,EAAY0B,EAAQC,GAE9C,OAxDJ,SAAoB3B,GAKhB,MAJmB,UAAfA,IACAA,EAAa,cAGNU,UAAYrB,IAEG,UAAfW,GAA0BV,EAC1BmB,OACwBmB,IAAxBlB,QAAQV,GACRF,EAAWY,QAASV,QACJ4B,IAAhBlB,QAAQC,IACRb,EAAWY,QAAS,OAEpBtB,EAEd,CAwCUyC,CAAW7B,IACXwB,EAAgCjB,MAAMQ,KAAMP,UACtD,CAED,SAASsB,EAAOV,EAAMW,GAEpB,IASIC,EAMAC,EAMAC,EArBAC,EAAOpB,KAuBPqB,EAAa,WAyBjB,SAASC,IACL,IAAIC,EAEJ,UAAW/C,SAAWF,GAAkB+C,EAAxC,CAEA,IACIE,EAAc/C,OAAOgD,aAAaH,EAChD,CAAY,MAAOI,GAAU,CAGnB,UAAWF,IAAgBjD,EACvB,IACI,IAAIoD,EAASlD,OAAOmD,SAASD,OACzBE,EAAaC,mBAAmBR,GAChCS,EAAWJ,EAAOK,QAAQH,EAAa,MACzB,IAAdE,IACAP,EAAc,WAAWS,KACrBN,EAAOO,MAAMH,EAAWF,EAAWzB,OAAS,IAC9C,GAExB,CAAgB,MAAOsB,GAAU,CAQvB,YAJiCZ,IAA7BO,EAAKb,OAAOgB,KACZA,OAAcV,GAGXU,CAzB6C,CA0BvD,CAiBD,SAASW,EAAeC,GACpB,IAAIpC,EAAQoC,EAIZ,GAHqB,iBAAVpC,QAA2Dc,IAArCO,EAAKb,OAAOR,EAAMqC,iBAC/CrC,EAAQqB,EAAKb,OAAOR,EAAMqC,gBAET,iBAAVrC,GAAsBA,GAAS,GAAKA,GAASqB,EAAKb,OAAOC,OAChE,OAAOT,EAEP,MAAM,IAAIsC,UAAU,6CAA+CF,EAE1E,CAhFmB,iBAAT9B,EACTgB,GAAc,IAAMhB,EACK,iBAATA,IAChBgB,OAAaR,GAqFfO,EAAKf,KAAOA,EAEZe,EAAKb,OAAS,CAAE+B,MAAS,EAAGC,MAAS,EAAGC,KAAQ,EAAGC,KAAQ,EACvDC,MAAS,EAAGlC,OAAU,GAE1BY,EAAKhB,cAAgBY,GAAWN,EAEhCU,EAAKnB,SAAW,WACZ,OAAiB,MAAbkB,EACKA,EACkB,MAAhBD,EACFA,EAEAD,GAIbG,EAAKuB,SAAW,SAAU5C,EAAO6C,GAO7B,OANAzB,EAAYe,EAAenC,IACX,IAAZ6C,GArGR,SAAgCC,GAC5B,IAAIC,GAAalE,EAAWiE,IAAa,UAAUT,cAEnD,UAAW5D,SAAWF,GAAkB+C,EAAxC,CAGA,IAEI,YADA7C,OAAOgD,aAAaH,GAAcyB,EAEhD,CAAY,MAAOrB,GAAU,CAGnB,IACIjD,OAAOmD,SAASD,OACdG,mBAAmBR,GAAc,IAAMyB,EAAY,GACnE,CAAY,MAAOrB,GAAU,CAZiC,CAavD,CAsFOsB,CAAuB5B,GAIpBrB,EAAsBR,KAAK8B,IAGtCA,EAAK4B,gBAAkB,SAAUjD,GAC7BmB,EAAegB,EAAenC,GACzBuB,KACDF,EAAKuB,SAAS5C,GAAO,IAI7BqB,EAAK6B,WAAa,WACd9B,EAAY,KApEhB,WACI,UAAW3C,SAAWF,GAAkB+C,EAAxC,CAGA,IACI7C,OAAOgD,aAAa0B,WAAW7B,EAC7C,CAAY,MAAOI,GAAU,CAGnB,IACIjD,OAAOmD,SAASD,OACdG,mBAAmBR,GAAc,0CACjD,CAAY,MAAOI,GAAU,CAXiC,CAYvD,CAwDG0B,GACArD,EAAsBR,KAAK8B,IAG/BA,EAAKgC,UAAY,SAASR,GACtBxB,EAAKuB,SAASvB,EAAKb,OAAO+B,MAAOM,IAGrCxB,EAAKiC,WAAa,SAAST,GACvBxB,EAAKuB,SAASvB,EAAKb,OAAOC,OAAQoC,IAGtCxB,EAAKkC,QAAU,WAMX,GALIxE,IAAkBsC,IAClBH,EAAiBiB,EAAepD,EAAcmB,aAElDH,EAAsBR,KAAK8B,GAEvBtC,IAAkBsC,EAClB,IAAK,IAAImC,KAAa1E,EACpBA,EAAe0E,GAAWD,WAMpCrC,EAAiBiB,EACbpD,EAAgBA,EAAcmB,WAAa,QAE/C,IAAIuD,EAAelC,IACC,MAAhBkC,IACArC,EAAYe,EAAesB,IAE/B1D,EAAsBR,KAAK8B,EAC5B,EAQDtC,EAAgB,IAAIiC,GAEN0C,UAAY,SAAmBpD,GACzC,GAAqB,iBAATA,GAAqC,iBAATA,GAA+B,KAATA,EAC1D,MAAM,IAAIgC,UAAU,kDAGxB,IAAIqB,EAAS7E,EAAewB,GAO5B,OANKqD,IACDA,EAAS7E,EAAewB,GAAQ,IAAIU,EAChCV,EACAvB,EAAcsB,gBAGfsD,GAIX,IAAIC,SAAenF,SAAWF,EAAiBE,OAAOoB,SAAMiB,EAiB5D,OAhBA/B,EAAc8E,WAAa,WAMvB,cALWpF,SAAWF,GACfE,OAAOoB,MAAQd,IAClBN,OAAOoB,IAAM+D,GAGV7E,GAGXA,EAAc+E,WAAa,WACvB,OAAOhF,GAIXC,EAAuB,QAAIA,EAEpBA,CACX,QA1VoDgF,QAC5CC,EAAAD,QAAiB5F,IAEjBD,EAAK2B,IAAM1B,iBCXnB,SAAYC,GACVA,EAAAA,EAAA,MAAA,GAAA,QACAA,EAAAA,EAAA,MAAA,GAAA,QACAA,EAAAA,EAAA,KAAA,GAAA,OACAA,EAAAA,EAAA,KAAA,GAAA,OACAA,EAAAA,EAAA,MAAA,GAAA,QACAA,EAAAA,EAAA,OAAA,GAAA,QACD,CAPD,CAAYA,IAAAA,EAOX,CAAA,IAED,SAAYC,GACVA,EAAA,QAAA,UACAA,EAAA,KAAA,eACAA,EAAA,YAAA,sBACAA,EAAA,MAAA,gBACAA,EAAA,YAAA,4BACAA,EAAA,OAAA,iBACAA,EAAA,OAAA,iBACAA,EAAA,UAAA,qBACAA,EAAA,YAAA,uBACAA,EAAA,KAAA,SACD,CAXD,CAAYA,IAAAA,EAWX,CAAA,IAeD,IAAI4F,EAAgBpE,EAAAA,UAAc,WACXqE,OAAOC,OAAO9F,GAAa+F,KAAK9D,GAAST,EAAAA,UAAcS,KAE9E2D,EAAchB,gBAAgB7E,EAASiG,MAqDhC,MAAMC,EAAezE,EAAa6D,UAAC,eCzFrCa,wJCJE,MAAMC,EAKXC,WAAAA,GAJQC,EAAAzE,KAAA,YAEAyE,EAAAzE,KAAA,UAGDA,KAAA0E,SAAWC,QAAQC,UACxB5E,KAAK6E,OAAS,CAChB,CAEAC,QAAAA,GACE,OAAO9E,KAAK6E,OAAS,CACvB,CAEAE,IAAAA,GAGM,IAAAC,EAFJhF,KAAK6E,QAAU,EAIf,MAAMI,EAAW,IAAIN,SAClBzE,GACE8E,EAAaE,KACZlF,KAAK6E,QAAU,EACP3E,GAAA,IAIRiF,EAAanF,KAAK0E,SAASU,MAAK,IAAMJ,IAE5C,OAAKN,KAAAA,SAAW1E,KAAK0E,SAASU,MAAK,IAAMH,IAElCE,CACT,GD5BF,SAAKb,GACHA,EAAAA,EAAA,QAAA,GAAA,UACAA,EAAAA,EAAA,QAAA,GAAA,UACAA,EAAAA,EAAA,UAAA,GAAA,WACD,CAJD,CAAKA,IAAAA,EAIJ,CAAA,IENM,MAAMe,EAAuB,UAevBC,EAAoB,CAC/BC,IAAK,GACLC,MAAO,EACPC,MAAO,EACPC,MAAO,GAYIC,EAA4C,CACvDC,WAAW,EACXC,YAJkB,uBAKlBC,kBAAmB,EACnBC,iBAhC0C,GAiC1CC,YAAa,ICpCT,MAAOC,UAAqBC,MAGhC1B,WAAAA,CAAY2B,EAAcC,GACxBC,MAAMD,GAAW,wBACjBpG,KAAKmG,KAAOA,CACd,EAGF,IAAkBG,EAqENC,EC9EAC,ECEAC,EAYAC,EAYAC,EAiBAC,GFlCZ,SAAkBN,GAChBA,EAAAA,EAAA,WAAA,GAAA,aACAA,EAAAA,EAAA,kBAAA,GAAA,oBACAA,EAAAA,EAAA,cAAA,GAAA,gBACAA,EAAAA,EAAA,UAAA,GAAA,YACAA,EAAAA,EAAA,aAAA,GAAA,cACD,CAND,CAAkBA,IAAAA,EAMjB,CAAA,IA+DD,SAAYC,GAEVA,EAAA,iBAAA,mBAEAA,EAAA,SAAA,WAEAA,EAAA,YAAA,cACAA,EAAA,MAAA,OACD,CARD,CAAYA,IAAAA,EAQX,CAAA,IAED,SAAiBA,GACCA,EAAAM,WAAhB,SAA2BC,GACzB,GAAIA,GAAS,SAAUA,EACrB,MAAmB,kBAAfA,EAAMzG,MAA2C,yBAAfyG,EAAMzG,KACnCkG,EAAmBQ,SAET,oBAAfD,EAAMzG,MAA6C,0BAAfyG,EAAMzG,KACrCkG,EAAmBS,iBAET,qBAAfF,EAAMzG,MAA8C,oBAAfyG,EAAMzG,KACtCkG,EAAmBU,YAErBV,EAAmBW,KAE9B,CACD,CAfD,CAAiBX,IAAAA,EAehB,CAAA,ICvGD,SAAYC,GACVA,EAAAA,EAAA,WAAA,GAAA,aACAA,EAAAA,EAAA,WAAA,GAAA,aACAA,EAAAA,EAAA,cAAA,GAAA,eACD,CAJD,CAAYA,IAAAA,EAIX,CAAA,IAEK,MAAOW,UAAqBlB,EAKhCzB,WAAAA,CACE4B,GAE4B,IAD5BgB,EAAA3H,UAAAU,OAAAV,QAAAoB,IAAApB,UAAAoB,GAAApB,UAA6B+G,GAAAA,EAAmBa,cAChDC,EAA4B7H,UAAAU,OAAAV,EAAAA,kBAAAoB,EAE5BwF,MAAM,GAAID,GACVpG,KAAKoH,OAASA,EACdpH,KAAKsH,oBAAsBA,CAC7B,GCjBF,SAAYb,GACVA,EAAA,OAAA,SACAA,EAAA,eAAA,iBACAA,EAAA,aAAA,cACD,CAJD,CAAYA,IAAAA,EAIX,CAAA,IAQD,SAAYC,GACVA,EAAA,aAAA,cACD,CAFD,CAAYA,IAAAA,EAEX,CAAA,IAUD,SAAYC,GACVA,EAAA,mCAAA,qCACAA,EAAA,gBAAA,iBACD,CAHD,CAAYA,IAAAA,EAGX,CAAA,IAcD,SAAYC,GACVA,EAAA,MAAA,cACD,CAFD,CAAYA,IAAAA,EAEX,CAAA,oECxBD,IAOIW,EAPAC,EAAuB,iBAAZC,QAAuBA,QAAU,KAC5CC,EAAeF,GAAwB,mBAAZA,EAAEhI,MAC7BgI,EAAEhI,MACF,SAAsBmI,EAAQC,EAAUC,GACxC,OAAOzI,SAASC,UAAUG,MAAMF,KAAKqI,EAAQC,EAAUC,IAKzDN,EADEC,GAA0B,mBAAdA,EAAEM,QACCN,EAAEM,QACV7D,OAAO8D,sBACC,SAAwBJ,GACvC,OAAO1D,OAAO+D,oBAAoBL,GAC/BM,OAAOhE,OAAO8D,sBAAsBJ,KAGxB,SAAwBA,GACvC,OAAO1D,OAAO+D,oBAAoBL,IAQtC,IAAIO,EAAcC,OAAOC,OAAS,SAAqBC,GACrD,OAAOA,GAAUA,GAGnB,SAASC,IACPA,EAAaC,KAAKjJ,KAAKU,KACzB,CACcwI,EAAA1E,QAAGwE,EACEE,EAAA1E,QAAA2E,KAwYnB,SAAcC,EAASrI,GACrB,OAAO,IAAIsE,SAAQ,SAAUC,EAAS+D,GACpC,SAASC,EAAcC,GACrBH,EAAQI,eAAezI,EAAM0I,GAC7BJ,EAAOE,EACR,CAED,SAASE,IAC+B,mBAA3BL,EAAQI,gBACjBJ,EAAQI,eAAe,QAASF,GAElChE,EAAQ,GAAG3C,MAAM3C,KAAKG,WAC5B,CAEIuJ,EAA+BN,EAASrI,EAAM0I,EAAU,CAAEN,MAAM,IACnD,UAATpI,GAMR,SAAuCqI,EAASO,EAASC,GAC7B,mBAAfR,EAAQS,IACjBH,EAA+BN,EAAS,QAASO,EAASC,EAE9D,CATME,CAA8BV,EAASE,EAAe,CAAEH,MAAM,GAEpE,GACA,EAxZAH,EAAaA,aAAeA,EAE5BA,EAAajJ,UAAUgK,aAAUxI,EACjCyH,EAAajJ,UAAUiK,aAAe,EACtChB,EAAajJ,UAAUkK,mBAAgB1I,EAIvC,IAAI2I,EAAsB,GAE1B,SAASC,EAAcC,GACrB,GAAwB,mBAAbA,EACT,MAAM,IAAIrH,UAAU,0EAA4EqH,EAEpG,CAoCA,SAASC,EAAiBC,GACxB,YAA2B/I,IAAvB+I,EAAKL,cACAjB,EAAakB,oBACfI,EAAKL,aACd,CAkDA,SAASM,EAAalC,EAAQmC,EAAMJ,EAAUK,GAC5C,IAAIC,EACAC,EACAC,EA1HsBC,EAgJ1B,GApBAV,EAAcC,QAGC7I,KADfoJ,EAAStC,EAAO0B,UAEdY,EAAStC,EAAO0B,QAAUpF,OAAOmG,OAAO,MACxCzC,EAAO2B,aAAe,SAIKzI,IAAvBoJ,EAAOI,cACT1C,EAAO2C,KAAK,cAAeR,EACfJ,EAASA,SAAWA,EAASA,SAAWA,GAIpDO,EAAStC,EAAO0B,SAElBa,EAAWD,EAAOH,SAGHjJ,IAAbqJ,EAEFA,EAAWD,EAAOH,GAAQJ,IACxB/B,EAAO2B,kBAeT,GAbwB,mBAAbY,EAETA,EAAWD,EAAOH,GAChBC,EAAU,CAACL,EAAUQ,GAAY,CAACA,EAAUR,GAErCK,EACTG,EAASK,QAAQb,GAEjBQ,EAASM,KAAKd,IAIhBM,EAAIL,EAAiBhC,IACb,GAAKuC,EAAS/J,OAAS6J,IAAME,EAASO,OAAQ,CACpDP,EAASO,QAAS,EAGlB,IAAIC,EAAI,IAAIxE,MAAM,+CACEgE,EAAS/J,OAAS,IAAMwK,OAAOb,GADjC,qEAIlBY,EAAErK,KAAO,8BACTqK,EAAEhC,QAAUf,EACZ+C,EAAEZ,KAAOA,EACTY,EAAEE,MAAQV,EAAS/J,OA7KGgK,EA8KHO,EA7KnB/K,SAAWA,QAAQkL,MAAMlL,QAAQkL,KAAKV,EA8KvC,CAGH,OAAOxC,CACT,CAaA,SAASmD,IACP,IAAK9K,KAAK+K,MAGR,OAFA/K,KAAK2H,OAAOmB,eAAe9I,KAAK8J,KAAM9J,KAAKgL,QAC3ChL,KAAK+K,OAAQ,EACY,IAArBtL,UAAUU,OACLH,KAAK0J,SAASpK,KAAKU,KAAK2H,QAC1B3H,KAAK0J,SAASlK,MAAMQ,KAAK2H,OAAQlI,UAE5C,CAEA,SAASwL,EAAUtD,EAAQmC,EAAMJ,GAC/B,IAAIwB,EAAQ,CAAEH,OAAO,EAAOC,YAAQnK,EAAW8G,OAAQA,EAAQmC,KAAMA,EAAMJ,SAAUA,GACjFyB,EAAUL,EAAY3L,KAAK+L,GAG/B,OAFAC,EAAQzB,SAAWA,EACnBwB,EAAMF,OAASG,EACRA,CACT,CAyHA,SAASC,EAAWzD,EAAQmC,EAAMuB,GAChC,IAAIpB,EAAStC,EAAO0B,QAEpB,QAAexI,IAAXoJ,EACF,MAAO,GAET,IAAIqB,EAAarB,EAAOH,GACxB,YAAmBjJ,IAAfyK,EACK,GAEiB,mBAAfA,EACFD,EAAS,CAACC,EAAW5B,UAAY4B,GAAc,CAACA,GAElDD,EAsDT,SAAyBE,GAEvB,IADA,IAAIC,EAAM,IAAIC,MAAMF,EAAIpL,QACfD,EAAI,EAAGA,EAAIsL,EAAIrL,SAAUD,EAChCsL,EAAItL,GAAKqL,EAAIrL,GAAGwJ,UAAY6B,EAAIrL,GAElC,OAAOsL,CACT,CA3DIE,CAAgBJ,GAAcK,EAAWL,EAAYA,EAAWnL,OACpE,CAmBA,SAASyL,EAAc9B,GACrB,IAAIG,EAASjK,KAAKqJ,QAElB,QAAexI,IAAXoJ,EAAsB,CACxB,IAAIqB,EAAarB,EAAOH,GAExB,GAA0B,mBAAfwB,EACT,OAAO,EACF,QAAmBzK,IAAfyK,EACT,OAAOA,EAAWnL,MAErB,CAED,OAAO,CACT,CAMA,SAASwL,EAAWJ,EAAKM,GAEvB,IADA,IAAIC,EAAO,IAAIL,MAAMI,GACZ3L,EAAI,EAAGA,EAAI2L,IAAK3L,EACvB4L,EAAK5L,GAAKqL,EAAIrL,GAChB,OAAO4L,CACT,CA2CA,SAAS9C,EAA+BN,EAASrI,EAAMqJ,EAAUR,GAC/D,GAA0B,mBAAfR,EAAQS,GACbD,EAAMT,KACRC,EAAQD,KAAKpI,EAAMqJ,GAEnBhB,EAAQS,GAAG9I,EAAMqJ,OAEd,IAAwC,mBAA7BhB,EAAQqD,iBAYxB,MAAM,IAAI1J,UAAU,6EAA+EqG,GATnGA,EAAQqD,iBAAiB1L,GAAM,SAAS2L,EAAaC,GAG/C/C,EAAMT,MACRC,EAAQwD,oBAAoB7L,EAAM2L,GAEpCtC,EAASuC,EACf,GAGG,CACH,QAraAhI,OAAOkI,eAAe7D,EAAc,sBAAuB,CACzD8D,YAAY,EACZC,IAAK,WACH,OAAO7C,CACR,EACD8C,IAAK,SAASL,GACZ,GAAmB,iBAARA,GAAoBA,EAAM,GAAK/D,EAAY+D,GACpD,MAAM,IAAIM,WAAW,kGAAoGN,EAAM,KAEjIzC,EAAsByC,CACvB,IAGH3D,EAAaC,KAAO,gBAEG1H,IAAjBb,KAAKqJ,SACLrJ,KAAKqJ,UAAYpF,OAAOuI,eAAexM,MAAMqJ,UAC/CrJ,KAAKqJ,QAAUpF,OAAOmG,OAAO,MAC7BpK,KAAKsJ,aAAe,GAGtBtJ,KAAKuJ,cAAgBvJ,KAAKuJ,oBAAiB1I,GAK7CyH,EAAajJ,UAAUoN,gBAAkB,SAAyBZ,GAChE,GAAiB,iBAANA,GAAkBA,EAAI,GAAK3D,EAAY2D,GAChD,MAAM,IAAIU,WAAW,gFAAkFV,EAAI,KAG7G,OADA7L,KAAKuJ,cAAgBsC,EACd7L,MASTsI,EAAajJ,UAAUqN,gBAAkB,WACvC,OAAO/C,EAAiB3J,OAG1BsI,EAAajJ,UAAUiL,KAAO,SAAcR,GAE1C,IADA,IAAIjC,EAAO,GACF3H,EAAI,EAAGA,EAAIT,UAAUU,OAAQD,IAAK2H,EAAK2C,KAAK/K,UAAUS,IAC/D,IAAIyM,EAAoB,UAAT7C,EAEXG,EAASjK,KAAKqJ,QAClB,QAAexI,IAAXoJ,EACF0C,EAAWA,QAA4B9L,IAAjBoJ,EAAOnD,WAC1B,IAAK6F,EACR,OAAO,EAGT,GAAIA,EAAS,CACX,IAAIC,EAGJ,GAFI/E,EAAK1H,OAAS,IAChByM,EAAK/E,EAAK,IACR+E,aAAc1G,MAGhB,MAAM0G,EAGR,IAAI/D,EAAM,IAAI3C,MAAM,oBAAsB0G,EAAK,KAAOA,EAAGxG,QAAU,IAAM,KAEzE,MADAyC,EAAIgE,QAAUD,EACR/D,CACP,CAED,IAAII,EAAUgB,EAAOH,GAErB,QAAgBjJ,IAAZoI,EACF,OAAO,EAET,GAAuB,mBAAZA,EACTvB,EAAauB,EAASjJ,KAAM6H,OAE5B,KAAIiF,EAAM7D,EAAQ9I,OACd4M,EAAYpB,EAAW1C,EAAS6D,GACpC,IAAS5M,EAAI,EAAGA,EAAI4M,IAAO5M,EACzBwH,EAAaqF,EAAU7M,GAAIF,KAAM6H,EAHX,CAM1B,OAAO,GAiETS,EAAajJ,UAAU2N,YAAc,SAAqBlD,EAAMJ,GAC9D,OAAOG,EAAa7J,KAAM8J,EAAMJ,GAAU,IAG5CpB,EAAajJ,UAAU8J,GAAKb,EAAajJ,UAAU2N,YAEnD1E,EAAajJ,UAAU4N,gBACnB,SAAyBnD,EAAMJ,GAC7B,OAAOG,EAAa7J,KAAM8J,EAAMJ,GAAU,IAqBhDpB,EAAajJ,UAAUoJ,KAAO,SAAcqB,EAAMJ,GAGhD,OAFAD,EAAcC,GACd1J,KAAKmJ,GAAGW,EAAMmB,EAAUjL,KAAM8J,EAAMJ,IAC7B1J,MAGTsI,EAAajJ,UAAU6N,oBACnB,SAA6BpD,EAAMJ,GAGjC,OAFAD,EAAcC,GACd1J,KAAKiN,gBAAgBnD,EAAMmB,EAAUjL,KAAM8J,EAAMJ,IAC1C1J,MAIbsI,EAAajJ,UAAUyJ,eACnB,SAAwBgB,EAAMJ,GAC5B,IAAIyD,EAAMlD,EAAQmD,EAAUlN,EAAGmN,EAK/B,GAHA5D,EAAcC,QAGC7I,KADfoJ,EAASjK,KAAKqJ,SAEZ,OAAOrJ,KAGT,QAAaa,KADbsM,EAAOlD,EAAOH,IAEZ,OAAO9J,KAET,GAAImN,IAASzD,GAAYyD,EAAKzD,WAAaA,EACb,KAAtB1J,KAAKsJ,aACTtJ,KAAKqJ,QAAUpF,OAAOmG,OAAO,cAEtBH,EAAOH,GACVG,EAAOnB,gBACT9I,KAAKsK,KAAK,iBAAkBR,EAAMqD,EAAKzD,UAAYA,SAElD,GAAoB,mBAATyD,EAAqB,CAGrC,IAFAC,GAAY,EAEPlN,EAAIiN,EAAKhN,OAAS,EAAGD,GAAK,EAAGA,IAChC,GAAIiN,EAAKjN,KAAOwJ,GAAYyD,EAAKjN,GAAGwJ,WAAaA,EAAU,CACzD2D,EAAmBF,EAAKjN,GAAGwJ,SAC3B0D,EAAWlN,EACX,KACD,CAGH,GAAIkN,EAAW,EACb,OAAOpN,KAEQ,IAAboN,EACFD,EAAKG,QAiIf,SAAmBH,EAAMI,GACvB,KAAOA,EAAQ,EAAIJ,EAAKhN,OAAQoN,IAC9BJ,EAAKI,GAASJ,EAAKI,EAAQ,GAC7BJ,EAAKK,KACP,CAnIUC,CAAUN,EAAMC,GAGE,IAAhBD,EAAKhN,SACP8J,EAAOH,GAAQqD,EAAK,SAEQtM,IAA1BoJ,EAAOnB,gBACT9I,KAAKsK,KAAK,iBAAkBR,EAAMuD,GAAoB3D,EACzD,CAED,OAAO1J,MAGbsI,EAAajJ,UAAUqO,IAAMpF,EAAajJ,UAAUyJ,eAEpDR,EAAajJ,UAAUsO,mBACnB,SAA4B7D,GAC1B,IAAIiD,EAAW9C,EAAQ/J,EAGvB,QAAeW,KADfoJ,EAASjK,KAAKqJ,SAEZ,OAAOrJ,KAGT,QAA8Ba,IAA1BoJ,EAAOnB,eAUT,OATyB,IAArBrJ,UAAUU,QACZH,KAAKqJ,QAAUpF,OAAOmG,OAAO,MAC7BpK,KAAKsJ,aAAe,QACMzI,IAAjBoJ,EAAOH,KACY,KAAtB9J,KAAKsJ,aACTtJ,KAAKqJ,QAAUpF,OAAOmG,OAAO,aAEtBH,EAAOH,IAEX9J,KAIT,GAAyB,IAArBP,UAAUU,OAAc,CAC1B,IACIoF,EADAqI,EAAO3J,OAAO2J,KAAK3D,GAEvB,IAAK/J,EAAI,EAAGA,EAAI0N,EAAKzN,SAAUD,EAEjB,oBADZqF,EAAMqI,EAAK1N,KAEXF,KAAK2N,mBAAmBpI,GAK1B,OAHAvF,KAAK2N,mBAAmB,kBACxB3N,KAAKqJ,QAAUpF,OAAOmG,OAAO,MAC7BpK,KAAKsJ,aAAe,EACbtJ,IACR,CAID,GAAyB,mBAFzB+M,EAAY9C,EAAOH,IAGjB9J,KAAK8I,eAAegB,EAAMiD,QACrB,QAAkBlM,IAAdkM,EAET,IAAK7M,EAAI6M,EAAU5M,OAAS,EAAGD,GAAK,EAAGA,IACrCF,KAAK8I,eAAegB,EAAMiD,EAAU7M,IAIxC,OAAOF,MAoBbsI,EAAajJ,UAAU0N,UAAY,SAAmBjD,GACpD,OAAOsB,EAAWpL,KAAM8J,GAAM,IAGhCxB,EAAajJ,UAAUwO,aAAe,SAAsB/D,GAC1D,OAAOsB,EAAWpL,KAAM8J,GAAM,IAGhCxB,EAAasD,cAAgB,SAASlD,EAASoB,GAC7C,MAAqC,mBAA1BpB,EAAQkD,cACVlD,EAAQkD,cAAc9B,GAEtB8B,EAActM,KAAKoJ,EAASoB,IAIvCxB,EAAajJ,UAAUuM,cAAgBA,EAiBvCtD,EAAajJ,UAAUyO,WAAa,WAClC,OAAO9N,KAAKsJ,aAAe,EAAI/B,EAAevH,KAAKqJ,SAAW,iBCvWhE,SAAS0E,EAAeC,EAAuBC,GAC7C,MACMC,GADc,IAAIC,aACQC,OAAOH,GACvC,OAAQD,GACN,IAAK,OACH,MAAO,CACL3N,KAAM,OACN4N,KAAMC,EACNG,KAAM,UACNjK,KAAM,IAAIkK,YAAY,MAE1B,IAAK,SACH,MAAO,CACLjO,KAAM,SACN4N,KAAMC,EACNG,KAAM,UACNE,WAAY,KAGhB,QACE,MAAM,IAAIrI,MAAK,aAAA+B,OAAc+F,gCAEnC,CAMsB,SAAAQ,EAAWC,EAAqBR,4CACpD,MAAMS,EAAmBX,EAAeU,EAASE,UAAUtO,KAAM4N,GAI3DW,QAAsBC,OAAOC,OAAOC,UACxCL,EACAD,EACA,CACEpO,KAAMgF,EACNlF,OAAQ,MAEV,EACA,CAAC,UAAW,YAGd,MAAO,CAAEsO,WAAUG,gBACrB,GAAC,OC5GYI,EAAbxK,WAAAA,GACUxE,KAAmBiP,oBAAG,EAItBjP,KAAiBkP,kBAAW,EAE5BlP,KAAkBmP,mBAAW,CAqCvC,CAnCEC,SAAAA,SACEpP,KAAKiP,qBAAuB,EACH,QAAzBI,EAAArP,KAAKsP,4BAAoB,IAAAD,IAAzBrP,KAAKsP,qBAAyBC,KAAKC,OACnCxP,KAAKkP,kBAAoBK,KAAKC,KAChC,CAEAC,eAAAA,QACoC5O,IAA9Bb,KAAKsP,uBAGPtP,KAAKmP,oBAAsB,GAI3BnP,KAAKmP,mBAAqBnP,KAAKiP,qBAE/BM,KAAKC,MAAQxP,KAAKkP,kBNeQ,MMb1BlP,KAAK0P,QAET,CAEAC,YAAAA,GACE,OACE3P,KAAKiP,oBNMkB,WMLQpO,IAA9Bb,KAAKsP,sBACJC,KAAKC,MAAQxP,KAAKsP,qBNKM,IMH9B,CAEAI,KAAAA,GACE1P,KAAKmP,mBAAqB,EAC1BnP,KAAKiP,oBAAsB,EAC3BjP,KAAKsP,0BAAuBzO,CAC9B,EC/BK,MAAM+O,EAA6C,IAAIC,IAaxD,MAAOC,UAA0BxH,EAAAA,aAC3ByH,cAAAA,CACRC,EACAC,GAEA,MAAM/J,MAAM,+BACd,CAEUgK,cAAAA,CACRF,EACAC,GAEA,MAAM/J,MAAM,+BACd,EAOI,MAAOiK,UAAqBL,EAwBhCtL,WAAAA,CAAY4L,SAMV/J,QACArG,KAAKqQ,WAAa,IAAIR,IACtB7P,KAAK4N,KAAOwC,EAAKxC,KACjB5N,KAAKsH,oBAAsB8I,EAAK9I,oBAChCtH,KAAKsQ,OAAS,IAAIT,IAClB7P,KAAKuQ,mBAAqBH,EAAKG,mBAC/BvQ,KAAKwQ,WAAgC,QAAnBnB,EAAAe,EAAKI,kBAAc,IAAAnB,EAAAA,EAAAoB,WAAWC,KAAK,IACrD1Q,KAAK2Q,SAAW,IAAI3B,CACtB,CAEA,cAAY4B,GACV,MAAO,CACLC,YAAa7Q,KAAKsH,oBAClBwJ,aAAc9Q,KAAK+Q,QACnBC,cAAehR,KAAKiR,WAExB,CAQAC,cAAAA,CAAeC,EAAYvD,GACzBvJ,EAAa/D,MAAM,qCACd2D,OAAAmN,OAAAnN,OAAAmN,OAAA,CAAA,EAAApR,KAAK4Q,YACR,CAAAC,YAAaM,KAEXnR,KAAKsH,qBACPjD,EAAayC,MACX,oGAEK9G,KAAK4Q,aAId5Q,KAAKsH,oBAAsB6J,EAC3BnR,KAAK4N,KAAOA,EACZ5N,KAAK2Q,SAASjB,OAChB,CAEA2B,gBAAAA,GACEhN,EAAa/D,MAAM,wBAAyBN,KAAK4Q,YACjD5Q,KAAKsH,yBAAsBzG,CAC7B,CAEAyQ,SAAAA,GACE,OAAItR,KAAKsH,oBACAsI,EAAqBvD,IAAIrM,KAAKsH,0BAErC,CAEJ,CAEAiK,sBAAAA,GACE,OAAOvR,KAAKsH,mBACd,CAEAkK,UAAAA,GACE,OAAOxR,KAAK+Q,OACd,CAMAU,aAAAA,CAAcC,GACZ1R,KAAKiR,WAAaS,CACpB,CAMAC,SAAAA,CAAUxN,GACRnE,KAAKsQ,OAASnM,CAChB,CAEAyN,cAAAA,CACEC,EACAC,EACAC,EACAhB,EACAW,GAEIA,IACFrN,EAAaD,KAAK,8BAA+B,CAAEsN,UACnD1R,KAAKiR,WAAaS,GAGpBrN,EAAa/D,MAAM,qCAAoC2D,OAAAmN,OAAA,CACrDS,YACAG,cAAejB,EACfW,SACG1R,KAAK4Q,aAGV,MAAMqB,EAA4B,WAAdJ,EAAyB7R,KAAK+P,eAAiB/P,KAAKkQ,eAClEgC,EAAkB,IAAIC,gBAAgB,CAC1CC,UAAWH,EAAY9S,KAAKa,QAG9B8R,EACGO,YAAYH,GACZI,OAAOP,GACPQ,OAAOhT,IACN8E,EAAawG,KAAKtL,GAClBS,KAAKsK,KACH1D,EAAaV,MACb3G,aAAa4H,EACT5H,EACA,IAAI4H,EAAa5H,EAAE6G,aAASvF,EAAWb,KAAKsH,qBACjD,IAELtH,KAAK+Q,QAAUA,CACjB,CAEAyB,aAAAA,CAAcC,GACZpO,EAAa/D,MAAM,sBAAqB2D,OAAAmN,OAAAnN,OAAAmN,OAAA,CAAA,EAAOpR,KAAK4Q,YAAU,CAAE6B,aAChEzS,KAAKwQ,WAAaiC,CACpB,CAwBgB1C,cAAAA,CACdC,EACAC,kDAEA,IACGjQ,KAAKsR,aAE2B,IAAjCtB,EAAa0C,KAAKC,WAElB,OAAO1C,EAAW2C,QAAQ5C,GAE5B,MAAM6C,EAAS7S,KAAK4N,KAAKkF,YACzB,IAAKD,EAWH,YAVA7S,KAAKsK,KACH1D,EAAaV,MACb,IAAIiB,2BAAYc,OAEZjI,KAAKsH,oBACPW,cAAAA,OAAajI,KAAK4N,KAAKmF,sBACvBvM,EAAmBwM,WACnBhT,KAAKsH,sBAKX,MAAMsH,cAAEA,GAAkBiE,EACpBI,EAAWjT,KAAK4N,KAAKmF,qBAE3B,GAAInE,EAAe,CACjB,MAAMsE,EAAKlT,KAAKmT,eACd9D,EAAAW,EAAaoD,cAAcC,sCAA0B,EACrDrD,EAAasD,WAEf,IAAIC,EAAYvT,KAAKwT,oBAAoBxD,GAGzC,MAAMyD,EAAc,IAAIhD,WAAWT,EAAa0C,KAAM,EAAGa,EAAUG,kBAG7DC,EAAe,IAAIlD,WAAW,GAEpCkD,EAAa,GP7OM,GO8OnBA,EAAa,GAAKV,EASlB,IACE,MAAMW,QAAmB/E,OAAOC,OAAO+E,QACrC,CACExT,KAAMgF,EACN6N,KACAY,eAAgB,IAAIrD,WAAWT,EAAa0C,KAAM,EAAGe,EAAYd,aAEnE/D,EACA,IAAI6B,WAAWT,EAAa0C,KAAMa,EAAUG,mBAG9C,IAAIK,EAAuB,IAAItD,WAC7BmD,EAAWjB,WAAaO,EAAGP,WAAagB,EAAahB,YAEvDoB,EAAqBzH,IAAI,IAAImE,WAAWmD,IACxCG,EAAqBzH,IAAI,IAAImE,WAAWyC,GAAKU,EAAWjB,YACxDoB,EAAqBzH,IAAIqH,EAAcC,EAAWjB,WAAaO,EAAGP,YAE9DY,EAAUS,SACZD,EFrIJ,SAAoBE,GACxB,MAAMC,EAAoB,GAE1B,IADA,IAAIC,EAAsB,EACjBjU,EAAI,EAAGA,EAAI+T,EAAQ9T,SAAUD,EAAG,CACvC,IAAIkU,EAAOH,EAAQ/T,GACfkU,GAPe,GAOWD,GARJ,IAUxBD,EAAQ1J,KATS,GAUjB2J,EAAsB,GAExBD,EAAQ1J,KAAK4J,GACD,GAARA,IACAD,EAEFA,EAAsB,CAE1B,CACA,OAAO,IAAI1D,WAAWyD,EACxB,CEmHiCG,CAAUN,IAGnC,IAAIO,EAAU,IAAI7D,WAAWgD,EAAYd,WAAaoB,EAAqBpB,YAM3E,OALA2B,EAAQhI,IAAImH,GACZa,EAAQhI,IAAIyH,EAAsBN,EAAYd,YAE9C3C,EAAa0C,KAAO4B,EAAQC,OAErBtE,EAAW2C,QAAQ5C,EAC3B,CAAC,MAAOzQ,GAEP8E,EAAayC,MAAMvH,EACrB,CACF,MACE8E,EAAa/D,MAAM,oCAAqCN,KAAK4Q,YAC7D5Q,KAAKsK,KACH1D,EAAaV,MACb,IAAIiB,EAEFX,sCAAAA,EAAmBwM,WACnBhT,KAAKsH,qBAIb,GAAC,CAQe4I,cAAAA,CACdF,EACAC,4CAEA,IACGjQ,KAAKsR,aAE2B,IAAjCtB,EAAa0C,KAAKC,WAIlB,OAFAtO,EAAa/D,MAAM,uBAAwBN,KAAK4Q,YAChD5Q,KAAK2Q,SAASlB,kBACPQ,EAAW2C,QAAQ5C,GAG5B,GAwYY,SAAsBwE,EAAwBC,GAC5D,GAAgC,IAA5BA,EAAa9B,WACf,OAAO,EAET,MAAMgB,EAAe,IAAIlD,WACvB+D,EAAUvS,MAAMuS,EAAU7B,WAAa8B,EAAa9B,aAEtD,OAAO8B,EAAaC,OAAM,CAACrM,EAAOkF,IAAUlF,IAAUsL,EAAapG,IACrE,CAhZQoH,CAAsB3E,EAAa0C,KAAM1S,KAAKwQ,YAIhD,OAHAnM,EAAa/D,MAAM,cAAeN,KAAK4Q,YACvC5Q,KAAK2Q,SAASvB,YAEVpP,KAAK2Q,SAAShB,gBAChBK,EAAa0C,KAAO1C,EAAa0C,KAAKzQ,MACpC,EACA+N,EAAa0C,KAAKC,WAAa3S,KAAKwQ,WAAWmC,YAE1C1C,EAAW2C,QAAQ5C,SAE1B3L,EAAawG,KAAK,qCAIpB7K,KAAK2Q,SAASlB,kBAEhB,MACMwD,EADO,IAAIxC,WAAWT,EAAa0C,MACnB1C,EAAa0C,KAAKC,WAAa,GAErD,IAAI3S,KAAK4N,KAAKgH,qBAAqB3B,GAKnC,GAAIjT,KAAK4N,KAAKkF,UAAUG,GACtB,IACE,MAAM4B,QAAqB7U,KAAK8U,aAAa9E,EAAciD,GAE3D,GADAjT,KAAK4N,KAAKmH,kBAAkB9B,GACxB4B,EACF,OAAO5E,EAAW2C,QAAQiC,EAE7B,CAAC,MAAO/N,GACHA,aAAiBK,GAAgBL,EAAMM,SAAWZ,EAAmBwO,WAEnEhV,KAAK4N,KAAKqH,cACZjV,KAAKsK,KAAK1D,EAAaV,MAAOY,GAC9B9G,KAAK4N,KAAKsH,kBAAkBjC,IAG9B5O,EAAawG,KAAK,wBAAyB,CAAE/D,SAEjD,MAGAzC,EAAawG,KAAI,mDAAA5C,OAAoDgL,IACrEjT,KAAKsK,KACH1D,EAAaV,MACb,IAAIiB,EAAY,wBAAAc,OACUgL,EAAQ,qBAAAhL,OAAoBjI,KAAKsH,qBACzDd,EAAmBwM,WACnBhT,KAAKsH,sBAGTtH,KAAK4N,KAAKsH,kBAAkBjC,EAEhC,GAAC,CAMa6B,YAAAA,CAAYK,EAAAC,4CACxBpF,EACAiD,GAAgB,IAAAoC,EAAArV,KAAA,IAChBsV,EAAsC7V,UAAAU,OAAA,QAAAU,IAAApB,UAAA,GAAAA,UAAA,QAAAoB,EACtC0U,EAAA9V,UAAAU,OAAAV,QAAAoB,IAAApB,UAAAoB,GAAApB,UAAoC,GAAA,CAAE+V,aAAc,GAAG,OAAA,kBAEvD,MAAM3C,EAASwC,EAAKzH,KAAKkF,UAAUG,GACnC,IAAKsC,EAAY3G,gBAAkBiE,EACjC,MAAM,IAAIxQ,UAAS4F,6CAAAA,OAA8CoN,EAAK/N,sBAExE,IAAIiM,EAAY8B,EAAK7B,oBAAoBxD,GAUzC,IACE,MAAMyD,EAAc,IAAIhD,WAAWT,EAAa0C,KAAM,EAAGa,EAAUG,kBACnE,IAAI+B,EAAgB,IAAIhF,WACtBT,EAAa0C,KACbe,EAAYtT,OACZ6P,EAAa0C,KAAKC,WAAac,EAAYtT,QAE7C,GAAIoT,EAAUS,QF7Sd,SAA8BQ,GAClC,IAAK,IAAItU,EAAI,EAAGA,EAAIsU,EAAUrU,OAAS,EAAGD,IACxC,GAAoB,GAAhBsU,EAAUtU,IAA+B,GAApBsU,EAAUtU,EAAI,IAA+B,GAApBsU,EAAUtU,EAAI,GAAS,OAAO,EAElF,OAAO,CACT,CEwS8BwV,CAAoBD,GAAgB,CAC1DA,EFvSF,SAAoBE,GACxB,MAAMzB,EAAoB,GAE1B,IADA,IAAI/T,EAASwV,EAAOxV,OACXD,EAAI,EAAGA,EAAIyV,EAAOxV,QAKrBA,EAASD,GAAK,IAAMyV,EAAOzV,KAAOyV,EAAOzV,EAAI,IAAuB,GAAjByV,EAAOzV,EAAI,IAEhEgU,EAAQ1J,KAAKmL,EAAOzV,MACpBgU,EAAQ1J,KAAKmL,EAAOzV,MAEpBA,KAGAgU,EAAQ1J,KAAKmL,EAAOzV,MAGxB,OAAO,IAAIuQ,WAAWyD,EACxB,CEmRwB0B,CAAUH,GAC1B,MAAMI,EAAW,IAAIpF,WAAWgD,EAAYd,WAAa8C,EAAc9C,YACvEkD,EAASvJ,IAAImH,GACboC,EAASvJ,IAAImJ,EAAehC,EAAYd,YACxC3C,EAAa0C,KAAOmD,EAAStB,MAC/B,CAEA,MAAMZ,EAAe,IAAIlD,WAAWT,EAAa0C,KAAM1C,EAAa0C,KAAKC,WAAa,EAAG,GAEnFmD,EAAWnC,EAAa,GACxBT,EAAK,IAAIzC,WACbT,EAAa0C,KACb1C,EAAa0C,KAAKC,WAAamD,EAAWnC,EAAahB,WACvDmD,GAGIC,EAAkBtC,EAAYd,WAC9BqD,EACJhG,EAAa0C,KAAKC,YACjBc,EAAYd,WAAamD,EAAWnC,EAAahB,YAE9CsD,QAAkBpH,OAAOC,OAAOoH,QACpC,CACE7V,KAAMgF,EACN6N,KACAY,eAAgB,IAAIrD,WAAWT,EAAa0C,KAAM,EAAGe,EAAYd,qBAEnEtD,EAAAkG,EAAY3G,6BAAiBiE,EAAQjE,cACrC,IAAI6B,WAAWT,EAAa0C,KAAMqD,EAAiBC,IAG/C1B,EAAU,IAAIhG,YAAYmF,EAAYd,WAAasD,EAAUtD,YAC7DkD,EAAW,IAAIpF,WAAW6D,GAOhC,OALAuB,EAASvJ,IAAI,IAAImE,WAAWT,EAAa0C,KAAM,EAAGe,EAAYd,aAC9DkD,EAASvJ,IAAI,IAAImE,WAAWwF,GAAYxC,EAAYd,YAEpD3C,EAAa0C,KAAO4B,EAEbtE,CACR,CAAC,MAAOlJ,GACP,GAAIuO,EAAK9E,mBAAmBzK,kBAAoB,EAAG,CACjD,GAAIyP,EAAYC,aAAeH,EAAK9E,mBAAmBzK,kBAAmB,CAOxE,IAAIqQ,EACJ,GAPA9R,EAAa/D,MAAK,0BAAA2H,OACUsN,EAAYC,aAAY,QAAAvN,OAChDoN,EAAK9E,mBAAmBzK,kBAC1B,eAAAmC,OAAc+H,aAAwBoG,qBAAuB,QAAU,WAIpEd,QAAAA,EAAmBzC,KAAYwC,EAAKzH,KAAKkF,UAAUG,GAAW,CAGjE,MAAMoD,QAAoBhB,EAAKzH,KAAK0I,WAAWrD,GAAU,GAEzDkD,QAAwB3H,EAAW6H,EAAahB,EAAK9E,mBAAmB1K,YAC1E,CAEA,MAAM0Q,QAAclB,EAAKP,aAAa9E,EAAciD,EAAUqC,GAAmBzC,EAAQ,CACvF2C,aAAcD,EAAYC,aAAe,EACzC5G,cAAeuH,aAAA,EAAAA,EAAiBvH,gBAWlC,OATI2H,GAASJ,IAGNb,QAAAA,EAAmBzC,KAAYwC,EAAKzH,KAAKkF,UAAUG,KACtDoC,EAAKzH,KAAK4I,UAAUL,EAAiBlD,GAAU,GAE/CoC,EAAKzH,KAAK6I,mBAAmBxD,IAG1BsD,CACT,CAQE,MADAlS,EAAawG,KAAK,qCACZ,IAAI1D,EAAY,qCAAAc,OACiBoN,EAAK/N,qBAC1Cd,EAAmBwO,WACnBK,EAAK/N,oBAGX,CACE,MAAM,IAAIH,EAAY,sBAAAc,OACEnB,EAAMV,SAC5BI,EAAmBwO,WACnBK,EAAK/N,oBAGX,EArHuD,KAsHxD,CAqBO6L,MAAAA,CAAOE,EAA+BC,SAC5C,MAAMJ,EAAK,IAAI5E,YPvgBM,IOwgBfoI,EAAS,IAAIC,SAASzD,GAGvBlT,KAAKqQ,WAAWuG,IAAIvD,IAEvBrT,KAAKqQ,WAAW/D,IAAI+G,EAAuBwD,KAAKC,MAAsB,MAAhBD,KAAKE,WAG7D,MAAMC,EAAsD,QAA1C3H,EAAArP,KAAKqQ,WAAWhE,IAAIgH,UAAsB,IAAAhE,EAAAA,EAAI,EAQhE,OANAqH,EAAOO,UAAU,EAAG5D,GACpBqD,EAAOO,UAAU,EAAG3D,GACpBoD,EAAOO,UAAU,EAAG3D,EAAa0D,EAAY,OAE7ChX,KAAKqQ,WAAW/D,IAAI+G,EAAuB2D,EAAY,GAEhD9D,CACT,CAEQM,mBAAAA,CAAoB+C,SAItBhD,EAAY,CAAEG,iBAAkB,EAAGM,QAAQ,GAC/C,GFviBE,SACJuC,GAEA,MAAO,SAAUA,CACnB,CEmiBQW,CAAaX,GAAQ,CACvB,IAAIY,EAAyC,QAAzB9H,EAAArP,KAAKoX,cAAcb,UAAM,IAAAlH,EAAAA,EAAIrP,KAAKiR,WAUtD,GATIkG,IAAkBnX,KAAKmX,gBACzB9S,EAAa/D,MAAM,2BAA0B2D,OAAAmN,OAAA,CAC3C+F,gBACAE,SAAUrX,KAAKmX,eACZnX,KAAK4Q,aAEV5Q,KAAKmX,cAAgBA,GAGD,QAAlBA,EACF,MAAM,IAAIjR,MAAK,GAAA+B,OAAIkP,sDAGrB,GAAsB,QAAlBA,EACF5D,EAAUG,iBAAmBpO,EAAkBiR,EAAMzM,WAChD,GAAsB,QAAlBqN,EAET,OADA5D,EAAUG,iBAAmB,EACtBH,EAGT,MAAMb,EAAO,IAAIjC,WAAW8F,EAAM7D,MAClC,IACE,MAAM4E,EAoDR,SAA0B3B,GAC9B,MAAM4B,EAAmB,GACzB,IAAIC,EAAQ,EACVC,EAAM,EACNC,EAAe/B,EAAOxV,OAAS,EACjC,KAAOsX,EAAMC,GAAc,CAEzB,KACED,EAAMC,IACY,IAAhB/B,EAAO8B,IAAkC,IAApB9B,EAAO8B,EAAM,IAAgC,IAApB9B,EAAO8B,EAAM,KAE7DA,IACEA,GAAOC,IAAcD,EAAM9B,EAAOxV,QAEtC,IAAIwX,EAAMF,EACV,KAAOE,EAAMH,GAA6B,IAApB7B,EAAOgC,EAAM,IAAUA,IAE7C,GAAc,IAAVH,GACF,GAAIG,IAAQH,EAAO,MAAMnV,UAAU,0CAEnCkV,EAAO/M,KAAKgN,GAGdA,EAAQC,GAAY,CACtB,CACA,OAAOF,CACT,CA9E4BK,CAAgBlF,GASpC,GANAa,EAAUS,OACU,SAAlBmD,GACAG,EAAYO,MAAMC,GAChB,CAACC,EAASC,UAAWD,EAASE,eAAeC,SAASC,EAAczF,EAAKoF,OAGzEvE,EAAUS,OAAQ,CACpB,IAAK,MAAMzG,KAAS+J,EAAa,CAE/B,OADWa,EAAczF,EAAKnF,KAE5B,KAAKwK,EAASC,UACd,KAAKD,EAASE,cAEZ,OADA1E,EAAUG,iBAAmBnG,EAAQ,EAC9BgG,EAIb,CACA,MAAM,IAAIlR,UAAU,sBACtB,CACD,CAAC,MAAO9C,GACP,CAIF,OADAgU,EAAUG,iBAAmBpO,EAAkBiR,EAAMzM,MAC9CyJ,CACT,CAEE,OADAA,EAAUG,iBAAmBpO,EAAkBG,MACxC8N,CAEX,CAKQ6D,aAAAA,CAAcb,GACpB,GAAyB,IAArBvW,KAAKsQ,OAAO8H,KACd,OAEF,MAAMC,EAAc9B,EAAMnD,cAAciF,YAExC,OADcA,EAAcrY,KAAKsQ,OAAOjE,IAAIgM,QAAexX,CAE7D,EAmCI,SAAUsX,EAAcG,GAC5B,OAAOA,EAAYC,CACrB,CAEA,MAAMA,EAAgB,GAEtB,IAAYR,GAAZ,SAAYA,GAEVA,EAAAA,EAAA,cAAA,GAAA,gBAEAA,EAAAA,EAAA,kBAAA,GAAA,oBAEAA,EAAAA,EAAA,kBAAA,GAAA,oBAEAA,EAAAA,EAAA,kBAAA,GAAA,oBAEAA,EAAAA,EAAA,UAAA,GAAA,YAEAA,EAAAA,EAAA,IAAA,GAAA,MAEAA,EAAAA,EAAA,IAAA,GAAA,MAEAA,EAAAA,EAAA,IAAA,GAAA,MAEAA,EAAAA,EAAA,IAAA,GAAA,MAEAA,EAAAA,EAAA,QAAA,IAAA,UAEAA,EAAAA,EAAA,WAAA,IAAA,aAEAA,EAAAA,EAAA,YAAA,IAAA,cAEAA,EAAAA,EAAA,QAAA,IAAA,UAEAA,EAAAA,EAAA,YAAA,IAAA,cAEAA,EAAAA,EAAA,WAAA,IAAA,aAEAA,EAAAA,EAAA,IAAA,IAAA,MAKAA,EAAAA,EAAA,UAAA,IAAA,YAEAA,EAAAA,EAAA,UAAA,IAAA,YAEAA,EAAAA,EAAA,gBAAA,IAAA,iBAGD,CA5CD,CAAYA,IAAAA,EA4CX,CAAA,IClsBK,MAAOS,UAA+BlQ,EAAAA,aAgB1C,eAAI2M,GACF,OAAQjV,KAAK4U,qBAAqB5U,KAAKyY,gBACzC,CAEAjU,WAAAA,CAAY8C,EAA6BiJ,GAGvC,GAFAlK,QACArG,KAAKyY,gBAAkB,EACnBlI,EAAmBvK,YAAc,GAAKuK,EAAmBvK,YAAc,IACzE,MAAM,IAAI3D,UAAU,8CAEtBrC,KAAK0Y,cAAgB,IAAIjN,MAAM8E,EAAmBvK,aAAa2S,UAAK9X,GACpEb,KAAK4Y,wBAA0B,IAAInN,MAAM8E,EAAmBvK,aAAa2S,KAAK,GAC9E3Y,KAAKuQ,mBAAqBA,EAC1BvQ,KAAK6Y,kBAAoB,IAAIhJ,IAC7B7P,KAAKsH,oBAAsBA,CAC7B,CAOAsN,oBAAAA,CAAqB3B,GACnB,OACEjT,KAAKuQ,mBAAmBxK,kBAAoB,GAC5C/F,KAAK4Y,wBAAwB3F,GAAYjT,KAAKuQ,mBAAmBxK,gBAErE,CAOAmP,iBAAAA,GAAyD,IAAvCjC,EAAAxT,UAAAU,OAAAV,QAAAoB,IAAApB,UAAAoB,GAAApB,UAAmB,GAAAO,KAAKyY,gBACpCzY,KAAKuQ,mBAAmBxK,iBAAmB,IAI/C/F,KAAK4Y,wBAAwB3F,IAAa,EAEtCjT,KAAK4Y,wBAAwB3F,GAAYjT,KAAKuQ,mBAAmBxK,kBACnE1B,EAAawG,KAAI5C,WAAAA,OACJjI,KAAKsH,oBAAmBW,cAAAA,OAAagL,kCAGtD,CAOA8B,iBAAAA,GAAyD,IAAvC9B,EAAAxT,UAAAU,OAAAV,QAAAoB,IAAApB,UAAAoB,GAAApB,UAAmB,GAAAO,KAAKyY,gBACxCzY,KAAK8Y,eAAe7F,EACtB,CAQA6F,cAAAA,CAAe7F,QACIpS,IAAboS,EACFjT,KAAK4Y,wBAAwBD,KAAK,GAElC3Y,KAAK4Y,wBAAwB3F,GAAY,CAE7C,CASAqD,UAAAA,CAAWrD,GAAgC,IAAb8F,IAAMtZ,UAAAU,OAAA,QAAAU,IAAApB,UAAA,KAAAA,UAAA,GAClC,MAAMgZ,EAAkBxF,QAAAA,EAAYjT,KAAK+S,qBAEnCiG,EAAkBhZ,KAAK6Y,kBAAkBxM,IAAIoM,GACnD,QAA+B,IAApBO,EACT,OAAOA,EAET,MAAMC,EAAiB,IAAItU,SAAmB,CAAOC,EAAS+D,IAAUuQ,EAAAlZ,UAAA,OAAA,GAAA,YACtE,IACE,MAAM6S,EAAS7S,KAAK8S,UAAU2F,GAC9B,IAAK5F,EACH,MAAM,IAAIxQ,UAAS4F,4DAAAA,OAC2CjI,KAAKsH,sBAGrE,MAAM6R,EAAkBtG,EAAOpE,SACzB4H,iBHvGiB+C,4CAC7BC,GAAkC,IAClC1K,sDAAuC,GAAA,CAAEtO,KAAMgF,GAC/CiU,EAAA7Z,UAAAU,OAAA,QAAAU,IAAApB,UAAA,GAAAA,UAAA,GAA8B,UAAS,OAAA,YAGvC,OAAOoP,OAAOC,OAAOyK,UACnB,MACAF,EACA1K,GACA,EACU,WAAV2K,EAAqB,CAAC,aAAc,aAAe,CAAC,UAAW,YAR1B,KAUxC,CG0FiCC,OHRZ,SAAQ9K,EAAqBR,4CACjD,MAAMS,EAAmBX,EAAeU,EAASE,UAAUtO,KAAM4N,GAGjE,OAAOY,OAAOC,OAAO0K,WAAW9K,EAAkBD,EAAU,IAC9D,GAAC,CGIegL,CAAQN,EAAiBnZ,KAAKuQ,mBAAmB1K,aACvDsT,EAAgBxK,UAAUtO,KAC1B,UAGE0Y,UACI/Y,KAAK0Z,mBAAmBrD,EAAaoC,GAAiB,GAC5DzY,KAAKsK,KACH5D,EAAgBiT,aAChBtD,EACArW,KAAKsH,oBACLmR,IAGJ7T,EAAQyR,EACT,CAAC,MAAO9W,GACPoJ,EAAOpJ,EACT,CAAU,QACRS,KAAK6Y,kBAAkBe,OAAOnB,EAChC,CACD,MAED,OADAzY,KAAK6Y,kBAAkBvM,IAAImM,EAAiBQ,GACrCA,CACT,CAQMF,MAAAA,CAAMc,4CAACpL,GAAmB,IAAA4G,EAAArV,KAAA,IAAEiT,EAAQxT,UAAAU,OAAA,QAAAU,IAAApB,UAAA,GAAAA,UAAA,GAAG,EAAC,OAAA,kBACtC4V,EAAKqE,mBAAmBjL,EAAUwE,GACxCoC,EAAKyD,eAAe7F,GAFwB,KAG7C,CAQKyG,kBAAAA,CAAkBG,EAAAzE,GAAC,OAAA8D,EAAAlZ,KAAAP,eAAA,GAAA,SAAAgP,EAAqBwE,GAAgB,IAAA6G,EAAA9Z,KAAA,IAAE+Z,EAAgBta,UAAAU,OAAA,QAAAU,IAAApB,UAAA,IAAAA,UAAA,GAAQ,OAAA,YACtF,MAAMoT,QAAerE,EAAWC,EAAUqL,EAAKvJ,mBAAmB1K,aAC5DmU,EAAW/G,GAAY,EAAIA,EAAW6G,EAAKpB,cAAcvY,OAAS2Z,EAAKrB,gBAC7EpU,EAAa/D,MAAK,8BAAA2H,OAA+BgL,GAAY,CAC3DqG,MAAO7K,EAASwL,OAChBtL,UAAWF,EAASE,UACpB9I,YAAaiU,EAAKvJ,mBAAmB1K,cAEvCiU,EAAKtD,UAAU3D,EAAQmH,EAAUD,GAC7BC,GAAY,IAAGF,EAAKrB,gBAAkBuB,GAT4C,KAUvF,CAEDxD,SAAAA,CAAU3D,EAAgBI,GAA0C,IAAxB8G,EAAgBta,UAAAU,OAAA,QAAAU,IAAApB,UAAA,IAAAA,UAAA,GAC1DO,KAAK0Y,cAAczF,EAAWjT,KAAK0Y,cAAcvY,QAAU0S,EAEvDkH,GACF/Z,KAAKsK,KAAK5D,EAAgBiT,aAAc9G,EAAOpE,SAAUzO,KAAKsH,oBAAqB2L,EAEvF,CAEMwD,kBAAAA,CAAmBlJ,4CACvBvN,KAAKyY,gBAAkBlL,EAAQvN,KAAK0Y,cAAcvY,OAClDH,KAAK8Y,eAAevL,EACtB,GAAC,CAEDwF,kBAAAA,GACE,OAAO/S,KAAKyY,eACd,CAOA3F,SAAAA,CAAUG,GACR,OAAOjT,KAAK0Y,cAAczF,QAAAA,EAAYjT,KAAKyY,gBAC7C,EC9LF,MAAMyB,EAAsC,GACtCC,EAAsD,IAAItK,IAChE,IAAIuK,EAOA5J,EANA6J,EAAe,UXIjB7V,WAAAA,GACExE,KAAKsa,aAAe,IAAIzK,IACxB7P,KAAKua,UAAY,IAAIC,EACrBxa,KAAKya,cAAgB,CACvB,CAEMC,GAAAA,CAAOC,4CACX,MAAMC,EAA0B,CAC9BzJ,GAAInR,KAAKya,gBACTI,WAAYtL,KAAKC,MACjBsL,OAAQxW,EAAgByW,SAE1B/a,KAAKsa,aAAahO,IAAIsO,EAASzJ,GAAIyJ,GACnC,MAAMI,QAAehb,KAAKua,UAAUxV,OACpC,IAGE,OAFA6V,EAASK,WAAa1L,KAAKC,MAC3BoL,EAASE,OAASxW,EAAgB4W,cACrBP,GACf,CAAU,QACRC,EAASE,OAASxW,EAAgB6W,UAClCnb,KAAKsa,aAAaV,OAAOgB,EAASzJ,IAClC6J,GACF,CACF,GAAC,CAEKI,KAAAA,4CACJ,OAAOpb,KAAK0a,KAAI,IAAaxB,EAAAlZ,UAAA,OAAA,GAAA,YAAC,KAChC,GAAC,CAEDqb,QAAAA,GACE,OAAO5P,MAAMiF,KAAK1Q,KAAKsa,aAAapW,SACtC,GW/BEoX,GAAwB,EAIxB/K,EAAyC5K,EAEzC2K,EAAkC,IAAIT,IAwG1C,SAAS0L,EAAgBjU,EAA6ByJ,GACpD,IAAIyK,EAAWtB,EAAoBuB,QAAQxW,GAAMA,EAAEuM,eAAiBT,IACpE,GAAIyK,EAASrb,OAAS,EAAG,CACvB,MAAMub,EAAYF,EACfrX,KAAKc,IACG,CAAE4L,YAAa5L,EAAEsM,6BAEzBoK,KAAK,KACRtX,EAAayC,MAAK,gDAAAmB,OACgC8I,EAAO9I,0BAAAA,OAAyBX,EAChF,KAAA,CAAEsU,aAAcF,GAEpB,CACA,IAAIG,EAAUL,EAAS,GACvB,GAAKK,EAcMvU,IAAwBuU,EAAQtK,0BAEzCsK,EAAQ3K,eAAe5J,EAAqBwU,EAAyBxU,QAhBzD,CAEZ,GADAjD,EAAaD,KAAK,2BAA4B,CAAEkD,yBAC3CiJ,EACH,MAAMrK,MAAM,+BAEd2V,EAAU,IAAI1L,EAAa,CACzB7I,sBACAsG,KAAMkO,EAAyBxU,GAC/BiJ,qBACAC,eAEFqL,EAAQlK,UAAUrB,GA8DtB,SAAiCuL,GAC/BA,EAAQ1S,GAAGvC,EAAaV,OAAQY,IAC9B,MAAMiV,EAAoB,CACxBC,KAAM,QACNtJ,KAAM,CAAE5L,MAAO,IAAIZ,SAAK+B,OAAIzB,EAAmBM,EAAMM,QAAOa,MAAAA,OAAKnB,EAAMV,YAEzE6V,YAAYF,EAAI,GAEpB,CArEIG,CAAwBL,GACxB3B,EAAoB1P,KAAKqR,EAC1B,CAKD,OAAOA,CACT,CAEA,SAASC,EAAyBxU,GAChC,GAAIgU,EACF,OAAOa,IAET,IAAIvO,EAAOuM,EAAgB9N,IAAI/E,GAM/B,OALKsG,IACHA,EAAO,IAAI4K,EAAsBlR,EAAqBiJ,GACtD3C,EAAKzE,GAAGzC,EAAgBiT,aAAcyC,GACtCjC,EAAgB7N,IAAIhF,EAAqBsG,IAEpCA,CACT,CAEA,SAASuO,IAKP,OAJK/B,IACH/V,EAAa/D,MAAM,mCACnB8Z,EAAmB,IAAI5B,EAAsB,aAAcjI,IAEtD6J,CACT,CA0CA,SAASgC,EAAkB3N,EAAqBnH,EAA6B2L,GAS3EgJ,YAR4B,CAC1BD,KAAkB,aAClBtJ,KAAM,CACJpL,sBACA2L,WACAxE,aAIN,CAjNApK,EAAarB,gBAAgB,QAE7BqZ,UAAaC,IACXjC,EAAaK,KAAI,IAAWxB,OAAA,OAAA,OAAA,GAAA,YAC1B,MAAM8C,KAAEA,EAAItJ,KAAEA,GAA4B4J,EAAG5J,KAE7C,OAAQsJ,GACN,IAAK,OACH3X,EAAa1B,SAAS+P,EAAK6J,UAC3BlY,EAAaD,KAAK,sBAClBmM,EAAqBmC,EAAKnC,mBAC1B+K,IAAiB5I,EAAKnC,mBAAmB3K,UAMzCqW,YAJwB,CACtBD,KAAM,UACNtJ,KAAM,CAAE8J,QAzBiB,SA4B3B,MACF,IAAK,SA8JmBC,EA7JD/J,EAAK8J,QA6JalV,EA7JJoL,EAAKpL,oBA8J9CjD,EAAa/D,MAAK,gDAAA2H,OAAiDX,GAAuB,CACxFmV,WAEF7M,EAAqBtD,IAAIhF,EAAqBmV,GAhKxCpY,EAAaD,KAAI6D,mCAAAA,OACoByK,EAAKpL,oBAAmB,QAAAW,OAAOyK,EAAK8J,UAGzEP,YAAYK,EAAG5J,MACf,MACF,IAAK,SACW6I,EAAgB7I,EAAKpL,oBAAqBoL,EAAK3B,SACrDa,eACNoK,EACAtJ,EAAKgK,eACLhK,EAAKiK,eACLjK,EAAK3B,QACL2B,EAAKhB,OAEP,MACF,IAAK,SACc6J,EAAgB7I,EAAKpL,oBAAqBoL,EAAK3B,SACrDa,eACToK,EACAtJ,EAAKgK,eACLhK,EAAKiK,eACLjK,EAAK3B,QACL2B,EAAKhB,OAEP,MACF,IAAK,SACC4J,QAwIZ,SAA4B/V,EAAgBgI,4CAC1ClJ,EAAaD,KAAK,iBAAkB,CAAEmJ,gBAChC4O,IAAsBpD,OAAOxT,EAAKgI,EAC1C,GAAC,CA1IeqP,CAAalK,EAAKnN,IAAKmN,EAAKO,UACzBP,EAAKpL,qBACdjD,EAAaD,KAAI6D,8BAAAA,OACeyK,EAAKpL,oBAAmB,WAAAW,OAAUyK,EAAKO,iBAEjE6I,EAAyBpJ,EAAKpL,qBAAqByR,OAAOrG,EAAKnN,IAAKmN,EAAKO,WAE/E5O,EAAayC,MAAM,mEAErB,MACF,IAAK,mBAoGX,SAAiCiK,EAAiBzJ,GAChD,MAAMkU,EAAWtB,EAAoBuB,QAClCxW,GAAMA,EAAEsM,2BAA6BjK,GAAuBrC,EAAEuM,eAAiBT,IAE9EyK,EAASrb,OAAS,GACpBkE,EAAayC,MAAM,2EAA4E,CAC7FiK,UACAzJ,wBAGJ,MAAMuU,EAAUL,EAAS,GACpBK,EAGHA,EAAQxK,mBAFRhN,EAAawG,KAAK,yCAA0C,CAAEkG,UAASzJ,uBAI3E,CAnHQuV,CAAwBnK,EAAK3B,QAAS2B,EAAKpL,qBAC3C,MACF,IAAK,cACHiU,EAAgB7I,EAAKpL,oBAAqBoL,EAAK3B,SAASU,cAAciB,EAAKhB,OAC3E,MACF,IAAK,YAEHpB,EAASoC,EAAKvO,IACd+V,EAAoB4C,SAASC,IACvBA,EAAGxL,2BAA6BmB,EAAKpL,qBACvCyV,EAAGpL,UAAUe,EAAKvO,IACpB,IAEF,MACF,IAAK,kBAYX,SAAoCuO,qCAClC,GAAI4I,EAAc,CAChB,MAAM0B,EAAab,UACba,EAAW1G,WAAW5D,EAAKO,UACjC+J,EAAWlE,gBACb,MAAO,GAAIpG,EAAKpL,oBAAqB,CACnC,MAAM0V,EAAalB,EAAyBpJ,EAAKpL,2BAC3C0V,EAAW1G,WAAW5D,EAAKO,UACjC+J,EAAWlE,gBACb,MACEzU,EAAayC,MACX,sFAGN,GAAC,CAzBOmW,CAAqBvK,GACrB,MACF,IAAK,gBAsIeD,EArIDC,EAAKD,QAsI5BjC,EAAaiC,EACbyH,EAAoB4C,SAAS7X,IAC3BA,EAAEuN,cAAcC,EAAQ,IAH5B,IAA0BA,EAlCIgK,EAAiBnV,CA9F5C,KAAC,EAyIAlG,KAAK8b,oBACP7Y,EAAa/D,MAAM,yBAEnBc,KAAK+b,eAAkBC,IAErB,MAAMC,EAAcD,EAAMC,YAC1BhZ,EAAa/D,MAAM,cAAe+c,GAElCA,EAAYC,SAAU,EACtB,MAAMtB,KAAEA,EAAI1U,oBAAEA,EAAmByJ,QAAEA,EAAOW,MAAEA,GAAU2L,EAAYE,QAC5D1B,EAAUN,EAAgBjU,EAAqByJ,GACrD1M,EAAa/D,MAAM,YAAa,CAAEoR,UAClCmK,EAAQjK,eAAeoK,EAAMqB,EAAYvL,SAAUuL,EAAYtL,SAAUhB,EAASW,EAAM","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 { DisconnectReason, 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 context?: unknown | DisconnectReason;\n\n reason: ConnectionErrorReason;\n\n constructor(\n message: string,\n reason: ConnectionErrorReason,\n status?: number,\n context?: unknown | DisconnectReason,\n ) {\n super(1, message);\n this.status = status;\n this.reason = reason;\n this.context = context;\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]}