mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-04-08 15:19:46 +00:00
Compute auth token in Node
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
|
||||
public static string ElectronExtraArguments { get; set; }
|
||||
|
||||
public static string ElectronAuthToken { get; internal set; }
|
||||
|
||||
public static int? ElectronSocketPort { get; internal set; }
|
||||
|
||||
public static int? AspNetWebPort { get; internal set; }
|
||||
|
||||
@@ -58,8 +58,9 @@
|
||||
private void ElectronProcess_Ready(object sender, EventArgs e)
|
||||
{
|
||||
var port = ElectronNetRuntime.ElectronSocketPort.Value;
|
||||
var token = ElectronNetRuntime.ElectronAuthToken;
|
||||
this.TransitionState(LifetimeState.Started);
|
||||
this.socketBridge = new SocketBridgeService(port, "");
|
||||
this.socketBridge = new SocketBridgeService(port, token);
|
||||
this.socketBridge.Ready += this.SocketBridge_Ready;
|
||||
this.socketBridge.Stopped += this.SocketBridge_Stopped;
|
||||
this.socketBridge.Start();
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
{
|
||||
private ElectronProcessBase electronProcess;
|
||||
private SocketBridgeService socketBridge;
|
||||
private int? port;
|
||||
|
||||
public RuntimeControllerElectronFirst()
|
||||
{
|
||||
@@ -36,12 +35,8 @@
|
||||
|
||||
protected override Task StartCore()
|
||||
{
|
||||
this.port = ElectronNetRuntime.ElectronSocketPort;
|
||||
|
||||
if (!this.port.HasValue)
|
||||
{
|
||||
throw new Exception("No port has been specified by Electron!");
|
||||
}
|
||||
var port = ElectronNetRuntime.ElectronSocketPort.Value;
|
||||
var token = ElectronNetRuntime.ElectronAuthToken;
|
||||
|
||||
if (!ElectronNetRuntime.ElectronProcessId.HasValue)
|
||||
{
|
||||
@@ -49,7 +44,7 @@
|
||||
}
|
||||
|
||||
this.TransitionState(LifetimeState.Starting);
|
||||
this.socketBridge = new SocketBridgeService(this.port!.Value, "");
|
||||
this.socketBridge = new SocketBridgeService(port, token);
|
||||
this.socketBridge.Ready += this.SocketBridge_Ready;
|
||||
this.socketBridge.Stopped += this.SocketBridge_Stopped;
|
||||
this.socketBridge.Start();
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.Common;
|
||||
using ElectronNET.Runtime.Data;
|
||||
@@ -15,6 +17,7 @@
|
||||
[Localizable(false)]
|
||||
internal class ElectronProcessActive : ElectronProcessBase
|
||||
{
|
||||
private readonly Regex extractor = new Regex("^Electron Socket: listening on port (\\d+) at .* using ([a-f0-9]+)$");
|
||||
private readonly bool isUnpackaged;
|
||||
private readonly string electronBinaryName;
|
||||
private readonly string extraArguments;
|
||||
@@ -159,37 +162,31 @@
|
||||
{
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
void Read_SocketIO_Port(object sender, string line)
|
||||
void Read_SocketIO_Parameters(object sender, string line)
|
||||
{
|
||||
// Look for "Electron Socket: listening on port %s at"
|
||||
var prefix = "Electron Socket: listening on port ";
|
||||
// Look for "Electron Socket: listening on port %s at ..."
|
||||
var match = extractor.Match(line);
|
||||
|
||||
if (line.StartsWith(prefix))
|
||||
if (match?.Success ?? false)
|
||||
{
|
||||
var start = prefix.Length;
|
||||
var end = line.IndexOf(' ', start + 1);
|
||||
var port = line[start..end];
|
||||
var port = int.Parse(match.Groups[1].Value);
|
||||
var token = match.Groups[2].Value;
|
||||
|
||||
if (int.TryParse(port, out var p))
|
||||
{
|
||||
// We got the port, so no more need for reading this
|
||||
this.process.LineReceived -= Read_SocketIO_Port;
|
||||
ElectronNetRuntime.ElectronSocketPort = p;
|
||||
tcs.SetResult();
|
||||
}
|
||||
this.process.LineReceived -= Read_SocketIO_Parameters;
|
||||
ElectronNetRuntime.ElectronAuthToken = token;
|
||||
ElectronNetRuntime.ElectronSocketPort = port;
|
||||
tcs.SetResult();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(10.ms()).ConfigureAwait(false);
|
||||
|
||||
Console.Error.WriteLine("[StartInternal]: startCmd: {0}", startCmd);
|
||||
Console.Error.WriteLine("[StartInternal]: args: {0}", args);
|
||||
|
||||
this.process = new ProcessRunner("ElectronRunner");
|
||||
this.process.ProcessExited += this.Process_Exited;
|
||||
this.process.LineReceived += Read_SocketIO_Port;
|
||||
this.process.LineReceived += Read_SocketIO_Parameters;
|
||||
this.process.Run(startCmd, args, directoriy);
|
||||
|
||||
await tcs.Task.ConfigureAwait(false);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Bridge;
|
||||
using ElectronNET.AspNet.Services;
|
||||
using ElectronNET.Common;
|
||||
using ElectronNET.Runtime.Controllers;
|
||||
using ElectronNET.Runtime.Data;
|
||||
@@ -17,12 +18,14 @@
|
||||
{
|
||||
private readonly IServer server;
|
||||
private readonly AspNetLifetimeAdapter aspNetLifetimeAdapter;
|
||||
private readonly IElectronAuthenticationService authenticationService;
|
||||
private SocketBridgeService socketBridge;
|
||||
|
||||
protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter)
|
||||
protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null)
|
||||
{
|
||||
this.server = server;
|
||||
this.aspNetLifetimeAdapter = aspNetLifetimeAdapter;
|
||||
this.authenticationService = authenticationService;
|
||||
this.aspNetLifetimeAdapter.Ready += this.AspNetLifetimeAdapter_Ready;
|
||||
this.aspNetLifetimeAdapter.Stopping += this.AspNetLifetimeAdapter_Stopping;
|
||||
this.aspNetLifetimeAdapter.Stopped += this.AspNetLifetimeAdapter_Stopped;
|
||||
@@ -59,10 +62,13 @@
|
||||
this.ElectronProcess.IsReady() &&
|
||||
this.aspNetLifetimeAdapter.IsReady())
|
||||
{
|
||||
var token = ElectronNetRuntime.ElectronAuthToken;
|
||||
var serverAddressesFeature = this.server.Features.Get<IServerAddressesFeature>();
|
||||
var address = serverAddressesFeature.Addresses.First();
|
||||
var uri = new Uri(address);
|
||||
|
||||
// Only if somebody registered an IElectronAuthenticationService service - otherwise we do not care
|
||||
this.authenticationService?.SetExpectedToken(token);
|
||||
ElectronNetRuntime.AspNetWebPort = uri.Port;
|
||||
|
||||
this.TransitionState(LifetimeState.Ready);
|
||||
|
||||
@@ -8,18 +8,14 @@
|
||||
using ElectronNET.Runtime.Data;
|
||||
using ElectronNET.Runtime.Helpers;
|
||||
using ElectronNET.Runtime.Services.ElectronProcess;
|
||||
using System.Security.Principal;
|
||||
|
||||
internal class RuntimeControllerAspNetDotnetFirst : RuntimeControllerAspNetBase
|
||||
{
|
||||
private ElectronProcessBase electronProcess;
|
||||
private readonly string authorization;
|
||||
|
||||
public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter)
|
||||
public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService)
|
||||
{
|
||||
this.authorization = Guid.NewGuid().ToString("N"); // 32 hex chars, no hyphens
|
||||
|
||||
// Only if somebody registered an IElectronAuthenticationService service - otherwise we do not care
|
||||
authenticationService?.SetExpectedToken(this.authorization);
|
||||
}
|
||||
|
||||
internal override ElectronProcessBase ElectronProcess => this.electronProcess;
|
||||
@@ -28,9 +24,8 @@
|
||||
{
|
||||
var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();
|
||||
var electronBinaryName = ElectronNetRuntime.ElectronExecutable;
|
||||
var authToken = this.authorization;
|
||||
var port = ElectronNetRuntime.ElectronSocketPort ?? 0;
|
||||
var args = $"{Environment.CommandLine} --authtoken={authToken}";
|
||||
var args = Environment.CommandLine;
|
||||
|
||||
this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, port);
|
||||
this.electronProcess.Ready += this.ElectronProcess_Ready;
|
||||
@@ -48,8 +43,9 @@
|
||||
private void ElectronProcess_Ready(object sender, EventArgs e)
|
||||
{
|
||||
var port = ElectronNetRuntime.ElectronSocketPort.Value;
|
||||
var token = ElectronNetRuntime.ElectronAuthToken;
|
||||
this.TransitionState(LifetimeState.Started);
|
||||
this.CreateSocketBridge(port, this.authorization);
|
||||
this.CreateSocketBridge(port, token);
|
||||
}
|
||||
|
||||
private void ElectronProcess_Stopped(object sender, EventArgs e)
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using ElectronNET.AspNet.Services;
|
||||
using ElectronNET.Runtime.Data;
|
||||
using ElectronNET.Runtime.Services.ElectronProcess;
|
||||
|
||||
internal class RuntimeControllerAspNetElectronFirst : RuntimeControllerAspNetBase
|
||||
{
|
||||
private ElectronProcessBase electronProcess;
|
||||
private int? port;
|
||||
|
||||
public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter) : base(server, aspNetLifetimeAdapter)
|
||||
public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,19 +19,15 @@
|
||||
|
||||
protected override Task StartCore()
|
||||
{
|
||||
this.port = ElectronNetRuntime.ElectronSocketPort;
|
||||
|
||||
if (!this.port.HasValue)
|
||||
{
|
||||
throw new Exception("No port has been specified by Electron!");
|
||||
}
|
||||
var port = ElectronNetRuntime.ElectronSocketPort.Value;
|
||||
var token = ElectronNetRuntime.ElectronAuthToken;
|
||||
|
||||
if (!ElectronNetRuntime.ElectronProcessId.HasValue)
|
||||
{
|
||||
throw new Exception("No electronPID has been specified by Electron!");
|
||||
}
|
||||
|
||||
this.CreateSocketBridge(this.port!.Value, "");
|
||||
this.CreateSocketBridge(port, token);
|
||||
|
||||
this.electronProcess = new ElectronProcessPassive(ElectronNetRuntime.ElectronProcessId.Value);
|
||||
this.electronProcess.Stopped += this.ElectronProcess_Stopped;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const { app } = require('electron');
|
||||
const { BrowserWindow } = require('electron');
|
||||
const { createServer } = require('http');
|
||||
const { randomUUID } = require('crypto');
|
||||
const { Server } = require('socket.io');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
@@ -25,6 +26,7 @@ let unpackeddotnet = false;
|
||||
let dotnetpacked = false;
|
||||
let electronforcedport;
|
||||
let electronUrl;
|
||||
let authToken = randomUUID().split('-').join('');
|
||||
|
||||
if (app.commandLine.hasSwitch('manifest')) {
|
||||
manifestJsonFileName = app.commandLine.getSwitchValue('manifest');
|
||||
@@ -44,15 +46,8 @@ if (app.commandLine.hasSwitch('electronforcedport')) {
|
||||
electronforcedport = +app.commandLine.getSwitchValue('electronforcedport');
|
||||
}
|
||||
|
||||
let authToken;
|
||||
|
||||
if (app.commandLine.hasSwitch('authtoken')) {
|
||||
authToken = app.commandLine.getSwitchValue('authtoken');
|
||||
// Store in global for access by browser windows
|
||||
global.authToken = authToken;
|
||||
}
|
||||
|
||||
console.log('Started with token', authToken);
|
||||
// Store in global for access by browser windows
|
||||
global.authToken = authToken;
|
||||
|
||||
if (app.commandLine.hasSwitch('electronurl')) {
|
||||
electronUrl = app.commandLine.getSwitchValue('electronurl');
|
||||
@@ -194,7 +189,7 @@ app.on('quit', async (event, exitCode) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up Socket.IO connection (legacy mode only)
|
||||
// Clean up Socket.IO connection
|
||||
if (typeof io !== 'undefined' && io && typeof io.close === 'function') {
|
||||
try {
|
||||
io.close();
|
||||
@@ -202,15 +197,6 @@ app.on('quit', async (event, exitCode) => {
|
||||
console.error('Error closing Socket.IO connection:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up SignalR connection (SignalR mode only)
|
||||
if (global['electronsignalr'] && typeof global['electronsignalr'].connection !== 'undefined') {
|
||||
try {
|
||||
await global['electronsignalr'].connection.stop();
|
||||
} catch (e) {
|
||||
console.error('Error closing SignalR connection:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function isSplashScreenEnabled() {
|
||||
@@ -278,6 +264,7 @@ function startSocketApiBridge(port) {
|
||||
// otherwise the Windows Firewall will be triggered
|
||||
console.debug('Electron Socket: starting...');
|
||||
server = createServer();
|
||||
const host = !port ? '127.0.0.1' : 'localhost';
|
||||
let hostHook;
|
||||
io = new Server({
|
||||
pingTimeout: 60000, // in ms, default is 5000
|
||||
@@ -285,10 +272,11 @@ function startSocketApiBridge(port) {
|
||||
});
|
||||
io.attach(server);
|
||||
|
||||
server.listen(port, 'localhost');
|
||||
server.listen(port, host);
|
||||
server.on('listening', function () {
|
||||
const addr = server.address();
|
||||
console.info('Electron Socket: listening on port %s at %s', addr.port, addr.address);
|
||||
console.info(`Electron Socket: listening on port ${addr.port} at ${addr.address} using ${authToken}`);
|
||||
|
||||
// Now that socket connection is established, we can guarantee port will not be open for portscanner
|
||||
if (unpackedelectron) {
|
||||
startAspCoreBackendUnpackaged(port);
|
||||
|
||||
Reference in New Issue
Block a user