UNPKG

nemeeting-electron-sdk

Version:

NetEase Meeting Electron SDK

296 lines 9.97 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var path = require('path'); var fs = require('fs'); var fileURLToPath = require('url').fileURLToPath; var SAFE_HTTP_PROTOCOLS = new Set(['http:', 'https:']); var runtimeTrustedOrigins = new Set(); var hasRegisteredTrustedOriginIpc = false; var BLOCKED_PROTOCOLS = new Set([ 'file:', 'media:', 'javascript:', 'data:', 'vbscript:', 'about:', ]); function normalizePath(filePath) { if (!filePath || typeof filePath !== 'string') { return ''; } return path.resolve(filePath); } function isSubPath(filePath, rootPath) { var normalizedFilePath = normalizePath(filePath); var normalizedRootPath = normalizePath(rootPath); if (!normalizedFilePath || !normalizedRootPath) { return false; } var relativePath = path.relative(normalizedRootPath, normalizedFilePath); return (relativePath === '' || (!!relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath))); } function normalizeOrigin(url) { if (!url || typeof url !== 'string') { return ''; } try { var parsedUrl = new URL(url); if (!SAFE_HTTP_PROTOCOLS.has(parsedUrl.protocol)) { return ''; } return parsedUrl.origin; } catch (_a) { return ''; } } function getElectronApp() { try { var electron = require('electron'); return electron && typeof electron !== 'string' ? electron.app : null; } catch (_a) { return null; } } function readJsonFile(filePath) { if (!filePath || typeof filePath !== 'string' || !fs.existsSync(filePath)) { return null; } try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch (error) { console.warn('[security] failed to read trusted config:', error.message); return null; } } function getPrivateConfigPaths(extraPaths) { if (extraPaths === void 0) { extraPaths = []; } var app = getElectronApp(); var configPaths = __spreadArray([ process.env.MEETING_PRIVATE_CONFIG_PATH ], __read(extraPaths), false).filter(Boolean); try { if (app === null || app === void 0 ? void 0 : app.getPath) { configPaths.push(path.join(app.getPath('userData'), 'xkit_server_private.json')); } } catch (_a) { // app.getPath may be unavailable in unit checks outside Electron. } configPaths.push(path.join(__dirname, '../../xkit_server_private.json')); return __spreadArray([], __read(new Set(configPaths.map(normalizePath).filter(Boolean))), false); } function getTrustedPrivateConfigOrigins(extraConfigPaths) { if (extraConfigPaths === void 0) { extraConfigPaths = []; } var origins = []; getPrivateConfigPaths(extraConfigPaths).forEach(function (configPath) { var _a; var config = readJsonFile(configPath); origins.push((_a = config === null || config === void 0 ? void 0 : config.meeting) === null || _a === void 0 ? void 0 : _a.serverUrl, config === null || config === void 0 ? void 0 : config.meetingServerDomain, config === null || config === void 0 ? void 0 : config.serverUrl); }); return origins.filter(Boolean); } function buildTrustedOrigins(extraOrigins) { if (extraOrigins === void 0) { extraOrigins = []; } var origins = __spreadArray(__spreadArray(__spreadArray([ process.env.MEETING_DOMAIN, process.env.WEBSITE_URL, 'https://meeting.163.com', 'https://trial.yunxinroom.com' ], __read(getTrustedPrivateConfigOrigins()), false), __read(runtimeTrustedOrigins), false), __read(extraOrigins), false); return new Set(origins.map(normalizeOrigin).filter(Boolean)); } function addRuntimeTrustedOrigin(origin) { var normalizedOrigin = normalizeOrigin(origin); if (normalizedOrigin) { runtimeTrustedOrigins.add(normalizedOrigin); } return !!normalizedOrigin; } function registerTrustedOriginIpc(ipcMain) { if (!ipcMain || hasRegisteredTrustedOriginIpc) { return; } hasRegisteredTrustedOriginIpc = true; ipcMain.on('register-trusted-meeting-origin', function (_, origin) { addRuntimeTrustedOrigin(origin); }); } function isLoopbackHost(hostname) { return hostname === 'localhost' || hostname === '127.0.0.1'; } function isLocalhostAllowed(options) { if (options === void 0) { options = {}; } return options.allowLocalhost === true || process.env.ENV_MODE === 'local'; } function safeFileURLToPath(parsedUrl) { try { return fileURLToPath(parsedUrl); } catch (_a) { return ''; } } function isSafeNavigationUrl(rawUrl, options) { if (options === void 0) { options = {}; } if (!rawUrl || typeof rawUrl !== 'string') { return false; } var parsedUrl; try { parsedUrl = new URL(rawUrl); } catch (_a) { return false; } if (BLOCKED_PROTOCOLS.has(parsedUrl.protocol)) { var filePath = safeFileURLToPath(parsedUrl); if (parsedUrl.protocol === 'file:' && options.allowFileRoot && filePath && isSubPath(filePath, options.allowFileRoot)) { return true; } return false; } if (!SAFE_HTTP_PROTOCOLS.has(parsedUrl.protocol)) { return false; } if (isLoopbackHost(parsedUrl.hostname)) { return isLocalhostAllowed(options); } var trustedOrigins = buildTrustedOrigins(options.trustedHttpOrigins); return trustedOrigins.has(parsedUrl.origin); } function isSafeWindowOpenUrl(rawUrl, options) { if (options === void 0) { options = {}; } if (!rawUrl || typeof rawUrl !== 'string') { return false; } var url = rawUrl.trim(); if (url.startsWith('#/')) { return true; } var parsedUrl; try { parsedUrl = new URL(url); } catch (_a) { return false; } if (!parsedUrl.hash.startsWith('#/')) { return false; } if (parsedUrl.protocol === 'file:') { var filePath = safeFileURLToPath(parsedUrl); return (!!options.allowFileRoot && !!filePath && isSubPath(filePath, options.allowFileRoot)); } return (SAFE_HTTP_PROTOCOLS.has(parsedUrl.protocol) && isLoopbackHost(parsedUrl.hostname) && isLocalhostAllowed(options)); } function registerNavigationGuards(win, options) { var _a; if (options === void 0) { options = {}; } if (!win || ((_a = win.isDestroyed) === null || _a === void 0 ? void 0 : _a.call(win)) || win.hasNavigationGuard) { return; } win.hasNavigationGuard = true; function guard(event, url, isInPlace, isMainFrame) { if (isMainFrame === false) { return; } var isSafe = false; try { isSafe = isSafeNavigationUrl(url, options); } catch (error) { console.warn('[security] navigation guard failed:', error.message); } if (!isSafe) { event.preventDefault(); console.warn('[security] blocked navigation:', url); } } win.webContents.on('will-navigate', guard); win.webContents.on('will-redirect', guard); } function resolveAllowedFilePath(rawUrl, allowedRoots) { if (allowedRoots === void 0) { allowedRoots = []; } if (!rawUrl || typeof rawUrl !== 'string') { return ''; } var filePath = ''; try { var parsedUrl = new URL(rawUrl); if (parsedUrl.protocol !== 'media:') { return ''; } if (process.platform === 'win32') { var rawPath = rawUrl.replace(/^media:\/\//, ''); if (/^[a-zA-Z]:[\\/]/.test(rawPath)) { filePath = rawPath; } else if (/^\/[a-zA-Z]:\//.test(parsedUrl.pathname || '')) { filePath = decodeURIComponent(parsedUrl.pathname).slice(1); } } if (!filePath) { var pathname = decodeURIComponent(parsedUrl.pathname || ''); var host = parsedUrl.hostname ? "".concat(path.sep).concat(parsedUrl.hostname) : ''; filePath = path.normalize("".concat(host).concat(pathname)); } } catch (_a) { filePath = path.normalize(rawUrl.replace(/^media:\/\//, '')); } if (!filePath || !path.isAbsolute(filePath)) { return ''; } var normalizedFilePath = normalizePath(filePath); return allowedRoots.some(function (root) { return isSubPath(normalizedFilePath, root); }) ? normalizedFilePath : ''; } module.exports = { addRuntimeTrustedOrigin: addRuntimeTrustedOrigin, buildTrustedOrigins: buildTrustedOrigins, getTrustedPrivateConfigOrigins: getTrustedPrivateConfigOrigins, isSafeNavigationUrl: isSafeNavigationUrl, isSafeWindowOpenUrl: isSafeWindowOpenUrl, registerTrustedOriginIpc: registerTrustedOriginIpc, isSubPath: isSubPath, registerNavigationGuards: registerNavigationGuards, resolveAllowedFilePath: resolveAllowedFilePath, };