diff --git a/ElectronNET.API/BridgeConnector.cs b/ElectronNET.API/BridgeConnector.cs index 50ca7d2..937a587 100644 --- a/ElectronNET.API/BridgeConnector.cs +++ b/ElectronNET.API/BridgeConnector.cs @@ -425,6 +425,11 @@ namespace ElectronNET.API { if (_socket is null) { + if(string.IsNullOrWhiteSpace(AuthKey)) + { + throw new Exception("You must call Electron.ReadAuth() first thing on your main entry point."); + } + if (HybridSupport.IsElectronActive) { lock (_syncRoot) @@ -448,8 +453,12 @@ namespace ElectronNET.API socket.OnConnected += (_, __) => { - _connectedSocketEvent.Set(); - Log("ElectronNET socket {1} connected on port {0}!", BridgeSettings.SocketPort, socket.Id); + Task.Run(async () => + { + await socket.EmitAsync("auth", AuthKey); + _connectedSocketEvent.Set(); + Log("ElectronNET socket {1} connected on port {0}!", BridgeSettings.SocketPort, socket.Id); + }); }; socket.OnReconnectAttempt += (_, __) => @@ -511,6 +520,7 @@ namespace ElectronNET.API } internal static ILogger Logger { private get; set; } + internal static string AuthKey { private get; set; } private class CamelCaseNewtonsoftJsonSerializer : NewtonsoftJsonSerializer { diff --git a/ElectronNET.API/Electron.cs b/ElectronNET.API/Electron.cs index 1dab7d9..d0ed8ad 100644 --- a/ElectronNET.API/Electron.cs +++ b/ElectronNET.API/Electron.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using System.Runtime.Versioning; +using System; namespace ElectronNET.API { @@ -10,6 +11,23 @@ namespace ElectronNET.API { private static ILoggerFactory loggerFactory; + /// + /// Reads the auth key from the command line. This method must be called first thing. + /// + /// + public static void ReadAuth() + { + var line = Console.ReadLine(); + if(line.StartsWith("Auth=")) + { + BridgeConnector.AuthKey = line.Substring("Auth=".Length); + } + else + { + throw new Exception("The call to Electron.ReadAuth must be the first thing your app entry point does"); + } + } + /// /// Sets the logger factory to be used by Electron, if any /// diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index b0d3dfc..ea6309a 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -5,9 +5,12 @@ const process = require('process'); const portscanner = require('portscanner'); const { imageSize } = require('image-size'); const { connect } = require('http2'); +const crypto = require('crypto'); fixPath(); //For macOS and Linux packaged-apps, the path variable might be missing +const auth = crypto.randomBytes(32).toString('hex'); + let io, server, browserWindows, ipc, apiProcess, loadURL; let appApi, menu, dialogApi, notification, tray, webContents; let globalShortcut, shellApi, screen, clipboard, autoUpdater; @@ -263,85 +266,92 @@ function startSocketApiBridge(port) { } }); - //We only hook to events on app on the first initialization of each component - let firstTime = (global['electronsocket'] == undefined); + socket.on("auth", function (authKey) { - global['electronsocket'] = socket; - socket.setMaxListeners(0); - - console.log('.NET connected on socket ' + socket.id + ' on ' + new Date()); - - appApi = require('./api/app')(socket, app, firstTime); - browserWindows = require('./api/browserWindows')(socket, app, firstTime); - commandLine = require('./api/commandLine')(socket, app); - autoUpdater = require('./api/autoUpdater')(socket, app); - ipc = require('./api/ipc')(socket); - menu = require('./api/menu')(socket); - dialogApi = require('./api/dialog')(socket); - notification = require('./api/notification')(socket); - tray = require('./api/tray')(socket); - webContents = require('./api/webContents')(socket); - globalShortcut = require('./api/globalShortcut')(socket); - shellApi = require('./api/shell')(socket); - screen = require('./api/screen')(socket); - clipboard = require('./api/clipboard')(socket); - browserView = require('./api/browserView').browserViewApi(socket); - powerMonitor = require('./api/powerMonitor')(socket); - nativeThemeApi = require('./api/nativeTheme')(socket); - dock = require('./api/dock')(socket); - - socket.on('splashscreen-destroy', () => { - if (splashScreen) { - splashScreen.destroy(); - splashScreen = null; + if (authKey != auth) { + throw new Error("Invalid auth key"); } - }); - socket.on('register-app-open-file-event', (id) => { + //We only hook to events on app on the first initialization of each component + let firstTime = (global['electronsocket'] == undefined); + global['electronsocket'] = socket; + socket.setMaxListeners(0); - app.on('open-file', (event, file) => { - event.preventDefault(); - global['electronsocket'].emit('app-open-file' + id, file); + console.log('.NET connected on socket ' + socket.id + ' on ' + new Date()); + + appApi = require('./api/app')(socket, app, firstTime); + browserWindows = require('./api/browserWindows')(socket, app, firstTime); + commandLine = require('./api/commandLine')(socket, app); + autoUpdater = require('./api/autoUpdater')(socket, app); + ipc = require('./api/ipc')(socket); + menu = require('./api/menu')(socket); + dialogApi = require('./api/dialog')(socket); + notification = require('./api/notification')(socket); + tray = require('./api/tray')(socket); + webContents = require('./api/webContents')(socket); + globalShortcut = require('./api/globalShortcut')(socket); + shellApi = require('./api/shell')(socket); + screen = require('./api/screen')(socket); + clipboard = require('./api/clipboard')(socket); + browserView = require('./api/browserView').browserViewApi(socket); + powerMonitor = require('./api/powerMonitor')(socket); + nativeThemeApi = require('./api/nativeTheme')(socket); + dock = require('./api/dock')(socket); + + socket.on('splashscreen-destroy', () => { + if (splashScreen) { + splashScreen.destroy(); + splashScreen = null; + } }); - if (launchFile) { - socket.emit('app-open-file' + id, launchFile); - } - }); + socket.on('register-app-open-file-event', (id) => { + global['electronsocket'] = socket; - socket.on('register-app-open-url-event', (id) => { - global['electronsocket'] = socket; + app.on('open-file', (event, file) => { + event.preventDefault(); + global['electronsocket'].emit('app-open-file' + id, file); + }); - app.on('open-url', (event, url) => { - event.preventDefault(); - global['electronsocket'].emit('app-open-url' + id, url); + if (launchFile) { + socket.emit('app-open-file' + id, launchFile); + } }); - if (launchUrl) { - socket.emit('app-open-url' + id, launchUrl); + socket.on('register-app-open-url-event', (id) => { + global['electronsocket'] = socket; + + app.on('open-url', (event, url) => { + event.preventDefault(); + global['electronsocket'].emit('app-open-url' + id, url); + }); + + if (launchUrl) { + socket.emit('app-open-url' + id, launchUrl); + } + }); + + socket.on('console-stdout', (data) => { + console.log(`stdout: ${data.toString()}`); + }); + + socket.on('console-stderr', (data) => { + console.log(`stderr: ${data.toString()}`); + }); + + try { + const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js'); + + if (isModuleAvailable(hostHookScriptFilePath) && hostHook === undefined) { + const { HookService } = require(hostHookScriptFilePath); + hostHook = new HookService(socket, app); + hostHook.onHostReady(); + } + } catch (error) { + console.error(error.message); } }); - - socket.on('console-stdout', (data) => { - console.log(`stdout: ${data.toString()}`); - }); - - socket.on('console-stderr', (data) => { - console.log(`stderr: ${data.toString()}`); - }); - - try { - const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js'); - - if (isModuleAvailable(hostHookScriptFilePath) && hostHook === undefined) { - const { HookService } = require(hostHookScriptFilePath); - hostHook = new HookService(socket, app); - hostHook.onHostReady(); - } - } catch (error) { - console.error(error.message); - } }); } @@ -417,6 +427,10 @@ function startAspCoreBackend(electronPort) { console.log('Detached from .NET process'); apiProcess.unref(); } + + apiProcess.stdin.setEncoding = 'utf-8'; + apiProcess.stdin.write('Auth=' + auth + '\n'); + apiProcess.stdin.end(); } } @@ -488,7 +502,6 @@ function getEnvironmentParameter() { } - //This code is derived from gh/sindresorhus/shell-path/, gh/sindresorhus/shell-env/, gh/sindresorhus/default-shell/, gh/chalk/ansi-regex, all under MIT license function fixPath() { if (process.platform === 'win32') { diff --git a/ElectronNET.WebApp/Program.cs b/ElectronNET.WebApp/Program.cs index c79b260..5af0fa6 100644 --- a/ElectronNET.WebApp/Program.cs +++ b/ElectronNET.WebApp/Program.cs @@ -11,6 +11,7 @@ namespace ElectronNET.WebApp public static void Main(string[] args) { Debugger.Launch(); + Electron.ReadAuth(); CreateWebHostBuilder(args).Build().Run(); }