nemeeting-electron-sdk
Version:
NetEase Meeting Electron SDK
296 lines • 9.97 kB
JavaScript
;
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,
};