From db5415f0dedd62604f59038e59e884f4a75f08e2 Mon Sep 17 00:00:00 2001 From: mikhailm-coder Date: Mon, 10 Aug 2026 16:45:21 +0200 Subject: [PATCH 1/2] Serve OpenFrame gateway URL + JWT from meshcore getServerTargetUrl Ports the one functional patch of the disk-distributed OpenFrame CoreModule into the true core source, so the standard server core-push mechanism delivers it. Guarded on mesh.authToken() returning a token (null outside OpenFrame mode), so the core stays stock for any other agent. Co-Authored-By: Claude Fable 5 --- agents/meshcore.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/agents/meshcore.js b/agents/meshcore.js index 319618b15f..3e2b814634 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -1150,6 +1150,14 @@ function getServerTargetUrl(path) { if (path == null) { path = ''; } x = http.parseUri(x); if (x == null) return null; + // OpenFrame mode: dial through the gateway proxy path with the agent JWT + var token = null; + try { if (typeof mesh.authToken == 'function') { token = mesh.authToken(); } } catch (ex) { } + if (token) { + var url = x.protocol + '//' + x.host + '/ws/tools/agent/meshcentral-server/' + path; + url += ((path.indexOf('?') !== -1) ? '&' : '?') + 'authorization=' + token; + return url; + } return x.protocol + '//' + x.host + ':' + x.port + '/' + path; } From b905ad488c1783a08e8527e43daacd4f8900bba8 Mon Sep 17 00:00:00 2001 From: mikhailm-coder Date: Wed, 19 Aug 2026 14:18:57 +0200 Subject: [PATCH 2/2] Add OpenFrame machine-id/Authorization headers to meshcore requests Ports the CoreModule.js half of meshagent#78 into the server core: getOpenFrameMachineId/addOpenFrameHeaders helpers and their six call sites (tunnel, trusted download, server file fetch, console wget and websocket, self-update), plus encodeURIComponent on the token query param. Guarded by mesh.openFrameMode, which exists only on meshagent 0.0.26+ binaries; older agents get stock behavior. Co-Authored-By: Claude Fable 5 --- agents/meshcore.js | 52 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index 3e2b814634..42ea93bde8 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -857,6 +857,50 @@ var http = require('http'); var net = require('net'); var fs = require('fs'); var rtc = require('ILibWebRTC'); + +// OpenFrame: Read machine ID from shared location +var openframeMachineId = null; +function getOpenFrameMachineId() { + if (openframeMachineId != null) return openframeMachineId; + try { + var machineIdPath = (process.platform == 'win32') + ? (process.env['ProgramData'] + '\\OpenFrame\\machine_id') + : ((process.platform == 'darwin') + ? '/Library/Application Support/OpenFrame/machine_id' + : '/var/lib/openframe/machine_id'); + openframeMachineId = fs.readFileSync(machineIdPath).toString().trim(); + } catch (ex) { openframeMachineId = null; } + return openframeMachineId; +} + +// OpenFrame: Add x-machine-id and Authorization headers to request options (only in openFrameMode) +function addOpenFrameHeaders(options) { + // Only add headers if running in OpenFrame mode + if (!mesh.openFrameMode) return options; + + if (!options.headers) options.headers = {}; + + // Native http adds Host only when no headers object exists; we made one, so set it. + if (options.host && !options.headers['Host']) { + var ofIsTLS = (options.protocol == 'wss:' || options.protocol == 'https:'); + var ofPort = '' + options.port; + options.headers['Host'] = ((ofPort == '443' && ofIsTLS) || (ofPort == '80' && !ofIsTLS)) ? options.host : (options.host + ':' + options.port); + } + + // Add x-machine-id header + var machineId = getOpenFrameMachineId(); + if (machineId) { + options.headers['x-machine-id'] = machineId; + } + + // Add Authorization header with JWT token + var token = mesh.authToken(); + if (token) { + options.headers['Authorization'] = 'Bearer ' + token; + } + + return options; +} var amt = null; var processManager = require('process-manager'); var wifiScannerLib = null; @@ -1155,7 +1199,7 @@ function getServerTargetUrl(path) { try { if (typeof mesh.authToken == 'function') { token = mesh.authToken(); } } catch (ex) { } if (token) { var url = x.protocol + '//' + x.host + '/ws/tools/agent/meshcentral-server/' + path; - url += ((path.indexOf('?') !== -1) ? '&' : '?') + 'authorization=' + token; + url += ((path.indexOf('?') !== -1) ? '&' : '?') + 'authorization=' + encodeURIComponent(token); return url; } return x.protocol + '//' + x.host + ':' + x.port + '/' + path; @@ -1319,6 +1363,7 @@ function handleServerCommand(data) { //sendConsoleText(JSON.stringify(woptions)); //sendConsoleText('TUNNEL: ' + JSON.stringify(data, null, 2)); + addOpenFrameHeaders(woptions); // Add X-MACHINE-ID and Authorization headers var tunnel = http.request(woptions); tunnel.upgrade = onTunnelUpgrade; tunnel.on('error', tunnel_onError); @@ -1978,6 +2023,7 @@ function downloadFile(downloadoptions) { if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') } } //options.checkServerIdentity.servertlshash = downloadoptions.serverhash; + addOpenFrameHeaders(options); // Add X-MACHINE-ID header trustedDownloads[downloadoptions.name] = downloadoptions; trustedDownloads[downloadoptions.name].dl = require('https').get(options); trustedDownloads[downloadoptions.name].dl.on('error', function (e) { downloadoptions.func(downloadoptions, false); delete trustedDownloads[downloadoptions.name]; }); @@ -2030,6 +2076,7 @@ function serverFetchFile() { agentFileHttpOptions.checkServerIdentity.servertlshash = data.servertlshash; if (agentFileHttpOptions == null) return; + addOpenFrameHeaders(agentFileHttpOptions); // Add X-MACHINE-ID header var agentFileHttpRequest = http.request(agentFileHttpOptions, function (response) { response.xparent = this; @@ -5429,6 +5476,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { if (options == null) { response = 'Invalid url.'; } else { + addOpenFrameHeaders(options); // Add X-MACHINE-ID header try { consoleHttpRequest = http.request(options, consoleHttpResponse); } catch (ex) { response = 'Invalid HTTP GET request'; } consoleHttpRequest.sessionid = sessionid; if (consoleHttpRequest != null) { @@ -5457,6 +5505,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { try { var options = http.parseUri(args['_'][0].split('$').join('%24').split('@').join('%40')); // Escape the $ and @ characters in the URL options.rejectUnauthorized = 0; + addOpenFrameHeaders(options); // Add X-MACHINE-ID header httprequest = http.request(options); } catch (ex) { response = 'Invalid HTTP websocket request'; } if (httprequest != null) { @@ -6147,6 +6196,7 @@ function agentUpdate_Start(updateurl, updateoptions) { } } options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null); + addOpenFrameHeaders(options); // Add X-MACHINE-ID header agentUpdate_Start._selfupdate = require('https').get(options); agentUpdate_Start._selfupdate.on('error', function (e) { sendConsoleText('Self Update failed, because there was a problem trying to download the update from ' + updateurl, sessionid);