"use strict"; /*!--------------------------------------------------------- * Copyright (C) Microsoft Corporation. All rights reserved. *----------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeProcessProviderHostProxy = void 0; var tslib_1 = require("tslib"); // Work around the Node security bug where the user code can load a node module from outside the packaged app's resource path // We reset search path of modules to prevent loading modules outside our predefined directories var path = require("path"); var os = require("os"); var fs_1 = require("fs"); /** * Resolve symlinks to absolute paths and remove paths that don't exist. * @param paths Array of paths to be resolved to absolute paths. Each path can be either a symlink path or an absolute path. */ function resolveAndFilterSymlinks(paths) { return paths.map(function (path) { try { // If path doesn't exist, realpathSync will throw. We mark this path to be removed from the input array. return fs_1.realpathSync(path); } catch (error) { return ""; } }).filter(function (p) { return p !== ""; }); } var Module = require("module"); var nodeModuleRootStr = process.argv.filter(function (val) { return val.startsWith("--nodeModuleRoots="); })[0]; var nodeModuleRoots = nodeModuleRootStr ? nodeModuleRootStr.substr(18).split(",") : []; var filterFunc; if (os.platform() === "win32") { filterFunc = function (pathValue) { return nodeModuleRoots === null || nodeModuleRoots === void 0 ? void 0 : nodeModuleRoots.some(function (root) { return pathValue.toLowerCase().startsWith(root.toLowerCase()); }); }; } else { filterFunc = function (pathValue) { return nodeModuleRoots === null || nodeModuleRoots === void 0 ? void 0 : nodeModuleRoots.some(function (root) { return pathValue.startsWith(root); }); }; } nodeModuleRoots = resolveAndFilterSymlinks(nodeModuleRoots); var originalFindPaths = Module._findPath; // Patch Module._findPath so that we won't load node module except under nodeModuleRoots Module._findPath = function (request, paths, isMain) { if (!!nodeModuleRoots) { paths = resolveAndFilterSymlinks(paths); paths = paths.filter(filterFunc); } return originalFindPaths(request, paths, isMain); }; var se_exception_serializer_1 = require("se-exception-serializer"); var EventListenerProvider_1 = require("../providers/EventListenerProvider"); var Provider_1 = require("../providers/Provider"); var ParentProcessProxy_1 = require("../main/NodeChildProcess/ParentProcessProxy"); var DEBUG_PREFIX = process.pid + " (NodeProcessHostProxy) >>> "; /** * A proxy to the RPC host for Node processes. */ var NodeProcessHostProxy = /** @class */ (function () { function NodeProcessHostProxy() { var _this = this; this._registeredOperations = {}; this._idCount = 0; this._requests = {}; this._parentProcess = new ParentProcessProxy_1.ParentProcessProxy(); this._parentProcess.onMessage(function (message) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var error_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this._handleMessage(message)]; case 1: _a.sent(); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); console.error("" + DEBUG_PREFIX + error_1); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }); } NodeProcessHostProxy.prototype.init = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var SdkRequireInterceptor, sdkRequireInterceptor; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promise.resolve().then(function () { return require("../SdkLoading/SdkRequireInterceptor"); })]; case 1: SdkRequireInterceptor = (_a.sent()).SdkRequireInterceptor; sdkRequireInterceptor = new SdkRequireInterceptor(); return [4 /*yield*/, sdkRequireInterceptor.activate()]; case 2: _a.sent(); this._parentProcess.initProcess().then(function () { console.log(DEBUG_PREFIX + "Node host in process " + process.pid + " has started successfully"); }); return [2 /*return*/]; } }); }); }; NodeProcessHostProxy.prototype.executeOperation = function (operation, args) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib_1.__generator(this, function (_a) { return [2 /*return*/, new Promise(function (resolve, reject) { var id = _this._getNextID(); var message = { type: "execute", id: id, operation: operation, args: args }; _this._addRequest(id, { resolve: resolve, reject: reject, message: message }); _this._parentProcess.sendMessage(message); })]; }); }); }; NodeProcessHostProxy.prototype.raiseEvent = function (event, args) { var _this = this; return new Promise(function (resolve, reject) { var id = _this._getNextID(); var message = { type: "raise", id: id, event: event, args: args }; _this._addRequest(id, { resolve: resolve, reject: reject, message: message }); _this._parentProcess.sendMessage(message); }); }; NodeProcessHostProxy.prototype.addListener = function (event, listener) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!!this._registeredOperations[event]) return [3 /*break*/, 2]; this._registeredOperations[event] = []; // If this is the first listener for an event, the proxy needs to // notify the host that the proxy needs notifications. return [4 /*yield*/, new Promise(function (resolve, reject) { var id = _this._getNextID(); var message = { id: id, type: "add-listener", listenerPid: process.pid, event: event }; _this._addRequest(id, { resolve: resolve, reject: reject, message: message }); _this._parentProcess.sendMessage(message); })]; case 1: // If this is the first listener for an event, the proxy needs to // notify the host that the proxy needs notifications. _a.sent(); _a.label = 2; case 2: this._registeredOperations[event].push(new EventListenerProvider_1.EventListenerProvider(listener)); return [2 /*return*/, listener]; } }); }); }; NodeProcessHostProxy.prototype.removeListener = function (event, listener) { return tslib_1.__awaiter(this, void 0, void 0, function () { var provider; var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!!this._registeredOperations[event] && this._registeredOperations[event].length > 0) { provider = this._registeredOperations[event].filter(function (provider) { return (provider instanceof EventListenerProvider_1.EventListenerProvider) && provider.listener === listener; })[0]; this._registeredOperations[event].splice(this._registeredOperations[event].indexOf(provider), 1); } if (!(!!this._registeredOperations[event] && this._registeredOperations[event].length === 0)) return [3 /*break*/, 2]; delete this._registeredOperations[event]; return [4 /*yield*/, new Promise(function (resolve, reject) { var id = _this._getNextID(); var message = { id: id, type: "remove-listener", listenerPid: process.pid, event: event }; _this._addRequest(id, { resolve: resolve, reject: reject, message: message }); _this._parentProcess.sendMessage(message); })]; case 1: return [2 /*return*/, _a.sent()]; case 2: return [2 /*return*/]; } }); }); }; NodeProcessHostProxy.prototype._getNextID = function () { return process.pid + "_" + process.argv[2] + "_" + (this._idCount = (this._idCount + 1) % 65535); }; NodeProcessHostProxy.prototype._handleMessage = function (message) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: _a = message.type; switch (_a) { case "init": return [3 /*break*/, 1]; case "execute": return [3 /*break*/, 3]; case "raise": return [3 /*break*/, 5]; case "response": return [3 /*break*/, 7]; } return [3 /*break*/, 9]; case 1: return [4 /*yield*/, this._handleInitRequest(message)]; case 2: return [2 /*return*/, _b.sent()]; case 3: return [4 /*yield*/, this._handleExecuteRequest(message)]; case 4: return [2 /*return*/, _b.sent()]; case 5: return [4 /*yield*/, this._handleRaiseRequest(message)]; case 6: return [2 /*return*/, _b.sent()]; case 7: return [4 /*yield*/, this._handleResponse(message)]; case 8: return [2 /*return*/, _b.sent()]; case 9: throw new Error("Unhandled or unrecognized message format:\n" + JSON.stringify(message)); } }); }); }; NodeProcessHostProxy.prototype._handleInitRequest = function (message) { var _this = this; this._config = message.config; var response = { type: "response", id: this._getNextID(), request: message }; try { var modulePath = path.resolve(__dirname, "../..", this._config.source.module); console.log(DEBUG_PREFIX + "Loading '" + modulePath + "'"); var provider_1 = new Provider_1.Provider(message.config); message.config.operations.forEach(function (operation) { if (!_this._registeredOperations[operation]) { _this._registeredOperations[operation] = [provider_1]; } else { _this._registeredOperations[operation].push(provider_1); var warning = "Provider '" + message.config.name + "' defines operation '" + operation + "', which is already defined by another provider." + " If you are not registering this operation as an event listener, consider changing the name of the operation."; console.warn(warning); } }); } catch (error) { response.error = se_exception_serializer_1.ExceptionSerializer.serialize(error); } finally { this._parentProcess.sendMessage(response); } }; NodeProcessHostProxy.prototype._handleExecuteRequest = function (message) { return tslib_1.__awaiter(this, void 0, void 0, function () { var response, _a, error_2; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: response = { type: "response", id: this._getNextID(), request: message }; _b.label = 1; case 1: _b.trys.push([1, 3, 4, 5]); _a = response; return [4 /*yield*/, this._registeredOperations[message.operation][0].executeOperation(message.operation, message.args)]; case 2: _a.result = _b.sent(); return [3 /*break*/, 5]; case 3: error_2 = _b.sent(); response.error = se_exception_serializer_1.ExceptionSerializer.serialize(error_2); return [3 /*break*/, 5]; case 4: this._parentProcess.sendMessage(response); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; NodeProcessHostProxy.prototype._handleRaiseRequest = function (message) { return tslib_1.__awaiter(this, void 0, void 0, function () { var response, error_3; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: response = { type: "response", id: this._getNextID(), request: message }; _a.label = 1; case 1: _a.trys.push([1, 4, 5, 6]); if (!!!this._registeredOperations[message.event]) return [3 /*break*/, 3]; return [4 /*yield*/, Promise.all(this._registeredOperations[message.event].map(function (provider) { return provider.raiseEvent(message.event, message.args); }))]; case 2: _a.sent(); _a.label = 3; case 3: return [3 /*break*/, 6]; case 4: error_3 = _a.sent(); response.error = se_exception_serializer_1.ExceptionSerializer.serialize(error_3); return [3 /*break*/, 6]; case 5: this._parentProcess.sendMessage(response); return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; NodeProcessHostProxy.prototype._handleResponse = function (message) { return tslib_1.__awaiter(this, void 0, void 0, function () { var request; return tslib_1.__generator(this, function (_a) { request = this._requests[message.request.id]; if (!request) { throw new Error(DEBUG_PREFIX + "Received response to unknown request"); } if (!!message.error) { request.reject(se_exception_serializer_1.ExceptionSerializer.deserialize(message.error)); } else { request.resolve(message.result); } delete this._requests[message.request.id]; return [2 /*return*/]; }); }); }; NodeProcessHostProxy.prototype._addRequest = function (id, request) { if (!!this._requests[id]) { console.error(!this._requests[id], "Overwriting existing request with ID " + id + ". This should not happen!"); } this._requests[id] = request; var outstandingRequests = Object.getOwnPropertyNames(this._requests).length; if (outstandingRequests > Math.pow(2, 16)) { console.error(outstandingRequests < Math.pow(2, 16), "Request overflow (" + outstandingRequests + "). This should not happen!"); } }; return NodeProcessHostProxy; }()); var instance = new NodeProcessHostProxy(); exports.NodeProcessProviderHostProxy = instance; global.host = instance; instance.init();