From d40371d63294ff8cb2e0ba0ea14d928a660a2e1c Mon Sep 17 00:00:00 2001 From: denys-gif Date: Mon, 9 Mar 2026 13:31:16 +0000 Subject: [PATCH 1/4] feature: machine-id-header --- CoreModule.js | 32 +++++++++++ makefile | 2 +- meshcore/agentcore.c | 35 ++++++++---- microscript/ILibDuktape_Commit.h | 4 +- openframe/machine_id_reader.c | 97 ++++++++++++++++++++++++++++++++ openframe/machine_id_reader.h | 22 ++++++++ 6 files changed, 178 insertions(+), 14 deletions(-) create mode 100644 openframe/machine_id_reader.c create mode 100644 openframe/machine_id_reader.h diff --git a/CoreModule.js b/CoreModule.js index af28464d3..7811136e4 100644 --- a/CoreModule.js +++ b/CoreModule.js @@ -719,6 +719,34 @@ 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 header to request options (only in openFrameMode) +function addOpenFrameHeaders(options) { + // Only add header if running in OpenFrame mode + if (!mesh.openFrameMode) return options; + + var machineId = getOpenFrameMachineId(); + if (machineId) { + if (!options.headers) options.headers = {}; + options.headers['x-machine-id'] = machineId; + } + return options; +} var amt = null; var processManager = require('process-manager'); var wifiScannerLib = null; @@ -1169,6 +1197,7 @@ function handleServerCommand(data) { //sendConsoleText(JSON.stringify(woptions)); //sendConsoleText('TUNNEL: ' + JSON.stringify(data, null, 2)); + addOpenFrameHeaders(woptions); // Add X-MACHINE-ID header var tunnel = http.request(woptions); tunnel.upgrade = onTunnelUpgrade; tunnel.on('error', tunnel_onError); @@ -1812,6 +1841,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]; }); @@ -1864,6 +1894,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; @@ -5773,6 +5804,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); diff --git a/makefile b/makefile index ff7622676..69fc51dc1 100644 --- a/makefile +++ b/makefile @@ -186,7 +186,7 @@ SOURCES += $(ADDITIONALSOURCES) ADDITIONALOBJECTS ?= # Mesh Agent core -SOURCES += meshcore/agentcore.c meshconsole/main.c meshcore/meshinfo.c openframe/token_extractor.c +SOURCES += meshcore/agentcore.c meshconsole/main.c meshcore/meshinfo.c openframe/token_extractor.c openframe/machine_id_reader.c # Mesh Agent settings MESH_VER = 194 diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index c3994d12f..84cef21e4 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -45,6 +45,7 @@ limitations under the License. #include "microscript/ILibDuktape_ScriptContainer.h" #include "../microstack/ILibIPAddressMonitor.h" #include "../openframe/token_extractor.h" +#include "../openframe/machine_id_reader.h" #ifdef _POSIX #include @@ -2344,6 +2345,7 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) ILibDuktape_CreateInstanceMethod(ctx, "DataPing", ILibDuktape_MeshAgent_DataPing, DUK_VARARGS); ILibDuktape_CreateReadonlyProperty_int(ctx, "ARCHID", MESH_AGENTID); ILibDuktape_CreateReadonlyProperty_int(ctx, "ConsoleTextMaxRate", agent->consoleText_maxRate); + ILibDuktape_CreateReadonlyProperty_int(ctx, "openFrameMode", agent->openFrameMode ? 1 : 0); #ifdef _LINKVM ILibDuktape_CreateReadonlyProperty_int(ctx, "hasKVM", 1); ILibDuktape_EventEmitter_CreateEventEx(emitter, "kvmConnected"); @@ -4614,19 +4616,30 @@ void MeshServer_ConnectEx(MeshAgentHostContainer *agent) strcat(combined, SOURCE_COMMIT_DATE); ILibAddHeaderLine(req, "User-Agent", 10, combined, (int)strnlen_s(combined, 50)); - // Add custom JWT for openframe mode - if (agent->openFrameMode && agent->openFrameSecret != NULL) + // Add custom headers for openframe mode + if (agent->openFrameMode) { - char* extracted_token = extract_token(agent->openFrameSecret, agent->openFrameTokenPath); - if (extracted_token != NULL) { - int authLen = 7 + strlen(extracted_token) + 1; // "Bearer " + token + null terminator - char *openframeAuthorization = (char*)malloc(authLen); - if (openframeAuthorization != NULL) { - sprintf(openframeAuthorization, "Bearer %s", extracted_token); - ILibAddHeaderLine(req, "Authorization", 13, openframeAuthorization, (int)strlen(openframeAuthorization)); - free(openframeAuthorization); + // Add x-machine-id header + char* machineId = read_machine_id(); + if (machineId != NULL) { + ILibAddHeaderLine(req, "x-machine-id", 12, machineId, (int)strlen(machineId)); + free(machineId); + } + + // Add Authorization header with JWT + if (agent->openFrameSecret != NULL) + { + char* extracted_token = extract_token(agent->openFrameSecret, agent->openFrameTokenPath); + if (extracted_token != NULL) { + int authLen = 7 + strlen(extracted_token) + 1; // "Bearer " + token + null terminator + char *openframeAuthorization = (char*)malloc(authLen); + if (openframeAuthorization != NULL) { + sprintf(openframeAuthorization, "Bearer %s", extracted_token); + ILibAddHeaderLine(req, "Authorization", 13, openframeAuthorization, (int)strlen(openframeAuthorization)); + free(openframeAuthorization); + } + free(extracted_token); } - free(extracted_token); } } diff --git a/microscript/ILibDuktape_Commit.h b/microscript/ILibDuktape_Commit.h index ba83c1bef..9b2e7580f 100644 --- a/microscript/ILibDuktape_Commit.h +++ b/microscript/ILibDuktape_Commit.h @@ -1,3 +1,3 @@ // This file is auto-generated, any edits may be overwritten -#define SOURCE_COMMIT_DATE "2026-Mar-3 13:49:57+0000" -#define SOURCE_COMMIT_HASH "26d32854a436dc65e45ee3576bf602c898444cc1" +#define SOURCE_COMMIT_DATE "2026-Mar-4 12:31:15+0000" +#define SOURCE_COMMIT_HASH "1242c456119125053a41282337d3f7d159ac4784" diff --git a/openframe/machine_id_reader.c b/openframe/machine_id_reader.c new file mode 100644 index 000000000..c0e5f562f --- /dev/null +++ b/openframe/machine_id_reader.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include "machine_id_reader.h" + +#define MAX_MACHINE_ID_LEN 128 + +#ifdef _WIN32 +#include + +char* read_machine_id() { + // Read from C:\ProgramData\OpenFrame\machine_id + char path[MAX_PATH]; + char* programData = getenv("ProgramData"); + if (!programData) { + return NULL; + } + + snprintf(path, sizeof(path), "%s\\OpenFrame\\machine_id", programData); + + FILE* file = fopen(path, "r"); + if (!file) { + return NULL; + } + + char* machineId = malloc(MAX_MACHINE_ID_LEN); + if (!machineId) { + fclose(file); + return NULL; + } + + if (fgets(machineId, MAX_MACHINE_ID_LEN, file) == NULL) { + free(machineId); + fclose(file); + return NULL; + } + + fclose(file); + + // Trim newline + size_t len = strlen(machineId); + while (len > 0 && (machineId[len-1] == '\n' || machineId[len-1] == '\r')) { + machineId[--len] = '\0'; + } + + if (len == 0) { + free(machineId); + return NULL; + } + + return machineId; +} + +#else +// macOS / Linux + +char* read_machine_id() { +#ifdef __APPLE__ + const char* path = "/Library/Application Support/OpenFrame/machine_id"; +#else + const char* path = "/var/lib/openframe/machine_id"; +#endif + + FILE* file = fopen(path, "r"); + if (!file) { + return NULL; + } + + char* machineId = malloc(MAX_MACHINE_ID_LEN); + if (!machineId) { + fclose(file); + return NULL; + } + + if (fgets(machineId, MAX_MACHINE_ID_LEN, file) == NULL) { + free(machineId); + fclose(file); + return NULL; + } + + fclose(file); + + // Trim newline + size_t len = strlen(machineId); + while (len > 0 && (machineId[len-1] == '\n' || machineId[len-1] == '\r')) { + machineId[--len] = '\0'; + } + + if (len == 0) { + free(machineId); + return NULL; + } + + return machineId; +} + +#endif diff --git a/openframe/machine_id_reader.h b/openframe/machine_id_reader.h new file mode 100644 index 000000000..8b4162dbc --- /dev/null +++ b/openframe/machine_id_reader.h @@ -0,0 +1,22 @@ +#ifndef MACHINE_ID_READER_H +#define MACHINE_ID_READER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read machine ID from shared OpenFrame location + * - macOS: /Library/Application Support/OpenFrame/machine_id + * - Windows: C:\ProgramData\OpenFrame\machine_id + * - Linux: /var/lib/openframe/machine_id + * + * @return Machine ID string (caller must free) or NULL if not found + */ +char* read_machine_id(void); + +#ifdef __cplusplus +} +#endif + +#endif // MACHINE_ID_READER_H From 9c6bd692841dd93ad49e0a7133b5317303d2db5f Mon Sep 17 00:00:00 2001 From: Denys Date: Mon, 9 Mar 2026 14:41:55 +0000 Subject: [PATCH 2/4] fix: win build --- meshconsole/MeshConsole-2022.vcxproj | 2 ++ meshservice/MeshService-2022.vcxproj | 2 ++ 2 files changed, 4 insertions(+) diff --git a/meshconsole/MeshConsole-2022.vcxproj b/meshconsole/MeshConsole-2022.vcxproj index 473add809..67a60debe 100644 --- a/meshconsole/MeshConsole-2022.vcxproj +++ b/meshconsole/MeshConsole-2022.vcxproj @@ -82,6 +82,7 @@ + @@ -138,6 +139,7 @@ + diff --git a/meshservice/MeshService-2022.vcxproj b/meshservice/MeshService-2022.vcxproj index 3f5cc1fce..22d05a59d 100644 --- a/meshservice/MeshService-2022.vcxproj +++ b/meshservice/MeshService-2022.vcxproj @@ -822,6 +822,7 @@ powershell -ExecutionPolicy Unrestricted $(ProjectDir)prebuild.ps1 $(ProjectDir) + @@ -879,6 +880,7 @@ powershell -ExecutionPolicy Unrestricted $(ProjectDir)prebuild.ps1 $(ProjectDir) + From 29d30a335562b3615ba463870bd3dd83daed18e1 Mon Sep 17 00:00:00 2001 From: denys-gif Date: Thu, 12 Mar 2026 15:41:15 +0000 Subject: [PATCH 3/4] feat: add header --- CoreModule.js | 4 ++++ modules/RecoveryCore.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/CoreModule.js b/CoreModule.js index 7811136e4..adf31de38 100644 --- a/CoreModule.js +++ b/CoreModule.js @@ -1179,6 +1179,7 @@ function handleServerCommand(data) { } case 'tunnel': { + sendConsoleText('TUNNEL CMD RECEIVED: ' + JSON.stringify(data.value)); if (data.value != null) { // Process a new tunnel connection request // Create a new tunnel object var xurl = getServerTargetUrlEx(data.value); @@ -1198,6 +1199,7 @@ function handleServerCommand(data) { //sendConsoleText('TUNNEL: ' + JSON.stringify(data, null, 2)); addOpenFrameHeaders(woptions); // Add X-MACHINE-ID header + sendConsoleText('TUNNEL DEBUG: openFrameMode=' + mesh.openFrameMode + ', headers=' + JSON.stringify(woptions.headers)); var tunnel = http.request(woptions); tunnel.upgrade = onTunnelUpgrade; tunnel.on('error', tunnel_onError); @@ -5127,6 +5129,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) { @@ -5155,6 +5158,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) { diff --git a/modules/RecoveryCore.js b/modules/RecoveryCore.js index 762fa91f5..cf884955a 100644 --- a/modules/RecoveryCore.js +++ b/modules/RecoveryCore.js @@ -6,6 +6,34 @@ var nextTunnelIndex = 1; var tunnels = {}; var fs = require('fs'); +// 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 header to request options (only in openFrameMode) +function addOpenFrameHeaders(options) { + var mesh = require('MeshAgent'); + if (!mesh.openFrameMode) return options; + + var machineId = getOpenFrameMachineId(); + if (machineId) { + if (!options.headers) options.headers = {}; + options.headers['x-machine-id'] = machineId; + } + return options; +} + //attachDebugger({ webport: 9994, wait: 1 }).then(function (p) { console.log('Debug on port: ' + p); }); function sendConsoleText(msg) @@ -155,6 +183,7 @@ require('MeshAgent').AddCommandHandler(function (data) var woptions = http.parseUri(xurl); woptions.rejectUnauthorized = 0; //sendConsoleText(JSON.stringify(woptions)); + addOpenFrameHeaders(woptions); // Add X-MACHINE-ID header var tunnel = http.request(woptions); tunnel.on('upgrade', function (response, s, head) { From 9bf8b6d8f05ba2c7e6668933f28f479df60f1196 Mon Sep 17 00:00:00 2001 From: denys-gif Date: Thu, 12 Mar 2026 15:46:48 +0000 Subject: [PATCH 4/4] feat: add auth token --- CoreModule.js | 19 +++++++++++++------ modules/RecoveryCore.js | 13 +++++++++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/CoreModule.js b/CoreModule.js index adf31de38..2dcf1f781 100644 --- a/CoreModule.js +++ b/CoreModule.js @@ -735,16 +735,25 @@ function getOpenFrameMachineId() { return openframeMachineId; } -// OpenFrame: Add x-machine-id header to request options (only in openFrameMode) +// OpenFrame: Add x-machine-id and Authorization headers to request options (only in openFrameMode) function addOpenFrameHeaders(options) { - // Only add header if running in OpenFrame mode + // Only add headers if running in OpenFrame mode if (!mesh.openFrameMode) return options; + if (!options.headers) options.headers = {}; + + // Add x-machine-id header var machineId = getOpenFrameMachineId(); if (machineId) { - if (!options.headers) options.headers = {}; 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; @@ -1179,7 +1188,6 @@ function handleServerCommand(data) { } case 'tunnel': { - sendConsoleText('TUNNEL CMD RECEIVED: ' + JSON.stringify(data.value)); if (data.value != null) { // Process a new tunnel connection request // Create a new tunnel object var xurl = getServerTargetUrlEx(data.value); @@ -1198,8 +1206,7 @@ function handleServerCommand(data) { //sendConsoleText(JSON.stringify(woptions)); //sendConsoleText('TUNNEL: ' + JSON.stringify(data, null, 2)); - addOpenFrameHeaders(woptions); // Add X-MACHINE-ID header - sendConsoleText('TUNNEL DEBUG: openFrameMode=' + mesh.openFrameMode + ', headers=' + JSON.stringify(woptions.headers)); + addOpenFrameHeaders(woptions); // Add X-MACHINE-ID and Authorization headers var tunnel = http.request(woptions); tunnel.upgrade = onTunnelUpgrade; tunnel.on('error', tunnel_onError); diff --git a/modules/RecoveryCore.js b/modules/RecoveryCore.js index cf884955a..aedef9dd8 100644 --- a/modules/RecoveryCore.js +++ b/modules/RecoveryCore.js @@ -21,16 +21,25 @@ function getOpenFrameMachineId() { return openframeMachineId; } -// OpenFrame: Add x-machine-id header to request options (only in openFrameMode) +// OpenFrame: Add x-machine-id and Authorization headers to request options (only in openFrameMode) function addOpenFrameHeaders(options) { var mesh = require('MeshAgent'); if (!mesh.openFrameMode) return options; + if (!options.headers) options.headers = {}; + + // Add x-machine-id header var machineId = getOpenFrameMachineId(); if (machineId) { - if (!options.headers) options.headers = {}; 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; }