mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-21 22:45:20 +00:00
Add simple socket auth via stdin exchange
This commit is contained in:
@@ -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<App> Logger { private get; set; }
|
||||
internal static string AuthKey { private get; set; }
|
||||
|
||||
private class CamelCaseNewtonsoftJsonSerializer : NewtonsoftJsonSerializer
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the auth key from the command line. This method must be called first thing.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception"></exception>
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the logger factory to be used by Electron, if any
|
||||
/// </summary>
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace ElectronNET.WebApp
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Debugger.Launch();
|
||||
Electron.ReadAuth();
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user