@mindexec/cli 0.2.93 → 0.2.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/remote-hub.js +87 -7
- package/server.js +8 -1
package/package.json
CHANGED
package/remote-hub.js
CHANGED
|
@@ -77,10 +77,72 @@ function isPrivateIPv4(value) {
|
|
|
77
77
|
|| (parts[0] === 192 && parts[1] === 168);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function
|
|
80
|
+
function isPreferredPhysicalInterfaceName(value) {
|
|
81
|
+
const name = String(value || '').toLowerCase();
|
|
82
|
+
return /(^|[\s_\-()])((wi[\s_\-]?fi)|wifi|wireless|wlan|ethernet|lan|이더넷|en\d+|eth\d+)(?=$|[\s_\-()])/i.test(name);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isVirtualInterfaceName(value) {
|
|
86
|
+
const name = String(value || '').toLowerCase();
|
|
87
|
+
return /virtual|vethernet|hyper-v|hyperv|vmware|virtualbox|vbox|docker|wsl|container|bluetooth|loopback|npcap|isatap|teredo/i.test(name);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getIPv4LastOctet(value) {
|
|
91
|
+
const parts = String(value || '').split('.').map(part => Number(part));
|
|
92
|
+
if (parts.length !== 4 || parts.some(part => !Number.isInteger(part))) {
|
|
93
|
+
return -1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return parts[3];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function scoreReachableIPv4Candidate(candidate) {
|
|
100
|
+
const address = String(candidate?.address || '');
|
|
101
|
+
const name = String(candidate?.name || '');
|
|
102
|
+
let score = 0;
|
|
103
|
+
|
|
104
|
+
if (isPrivateIPv4(address)) {
|
|
105
|
+
score += 1000;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (/^192\.168\./.test(address)) {
|
|
109
|
+
score += 90;
|
|
110
|
+
} else if (/^10\./.test(address)) {
|
|
111
|
+
score += 80;
|
|
112
|
+
} else if (/^172\.(1[6-9]|2\d|3[0-1])\./.test(address)) {
|
|
113
|
+
score += 70;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (isPreferredPhysicalInterfaceName(name)) {
|
|
117
|
+
score += 500;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (isVirtualInterfaceName(name)) {
|
|
121
|
+
score -= 1200;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (/^169\.254\./.test(address)) {
|
|
125
|
+
score -= 2000;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const lastOctet = getIPv4LastOctet(address);
|
|
129
|
+
if (lastOctet === 1) {
|
|
130
|
+
score -= 60;
|
|
131
|
+
} else if (lastOctet === 0 || lastOctet === 255) {
|
|
132
|
+
score -= 100;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (candidate?.mac && candidate.mac === '00:00:00:00:00:00') {
|
|
136
|
+
score -= 50;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return score;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getReachableIPv4CandidateEntries() {
|
|
81
143
|
const candidates = [];
|
|
82
144
|
const interfaces = os.networkInterfaces();
|
|
83
|
-
for (const entries of Object.
|
|
145
|
+
for (const [name, entries] of Object.entries(interfaces)) {
|
|
84
146
|
for (const entry of entries || []) {
|
|
85
147
|
if (entry?.family !== 'IPv4' || entry.internal) {
|
|
86
148
|
continue;
|
|
@@ -91,13 +153,28 @@ function getReachableIPv4Candidates() {
|
|
|
91
153
|
continue;
|
|
92
154
|
}
|
|
93
155
|
|
|
94
|
-
candidates.push(
|
|
156
|
+
candidates.push({
|
|
157
|
+
address,
|
|
158
|
+
name: safeString(name, 128),
|
|
159
|
+
mac: safeString(entry.mac, 32),
|
|
160
|
+
score: 0,
|
|
161
|
+
virtual: isVirtualInterfaceName(name),
|
|
162
|
+
preferred: isPreferredPhysicalInterfaceName(name)
|
|
163
|
+
});
|
|
95
164
|
}
|
|
96
165
|
}
|
|
97
166
|
|
|
98
167
|
return candidates
|
|
99
|
-
.
|
|
100
|
-
|
|
168
|
+
.map(candidate => ({
|
|
169
|
+
...candidate,
|
|
170
|
+
score: scoreReachableIPv4Candidate(candidate)
|
|
171
|
+
}))
|
|
172
|
+
.sort((left, right) => right.score - left.score || left.address.localeCompare(right.address))
|
|
173
|
+
.filter((candidate, index, all) => all.findIndex(item => item.address === candidate.address) === index);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getReachableIPv4Candidates() {
|
|
177
|
+
return getReachableIPv4CandidateEntries().map(candidate => candidate.address);
|
|
101
178
|
}
|
|
102
179
|
|
|
103
180
|
function getReachableIPv4Address() {
|
|
@@ -409,7 +486,8 @@ export function createRemoteHub(options = {}) {
|
|
|
409
486
|
}
|
|
410
487
|
|
|
411
488
|
function getAgentEndpointRouteInfo() {
|
|
412
|
-
const
|
|
489
|
+
const candidateDetails = getReachableIPv4CandidateEntries();
|
|
490
|
+
const candidates = candidateDetails.map(candidate => candidate.address);
|
|
413
491
|
const endpoint = getAgentEndpoint();
|
|
414
492
|
const wildcardWithoutReachableAddress =
|
|
415
493
|
!publicEndpoint
|
|
@@ -424,7 +502,8 @@ export function createRemoteHub(options = {}) {
|
|
|
424
502
|
port: parsed?.port || 0,
|
|
425
503
|
accountRouteReady: reason === 'ok',
|
|
426
504
|
reason,
|
|
427
|
-
candidates
|
|
505
|
+
candidates,
|
|
506
|
+
candidateDetails
|
|
428
507
|
};
|
|
429
508
|
}
|
|
430
509
|
|
|
@@ -574,6 +653,7 @@ export function createRemoteHub(options = {}) {
|
|
|
574
653
|
agentEndpointAccountRouteReady: routeInfo.accountRouteReady,
|
|
575
654
|
agentEndpointRouteReason: routeInfo.reason,
|
|
576
655
|
agentEndpointCandidates: routeInfo.candidates,
|
|
656
|
+
agentEndpointCandidateDetails: routeInfo.candidateDetails,
|
|
577
657
|
pairToken: includeSecrets ? pairToken : undefined,
|
|
578
658
|
pairTokenPreview: maskToken(pairToken),
|
|
579
659
|
deviceCount: devices.size,
|
package/server.js
CHANGED
|
@@ -2954,10 +2954,12 @@ async function startRemoteAgentConnection(options = {}) {
|
|
|
2954
2954
|
const engine = normalizeRemoteAgentEngine(options.engine);
|
|
2955
2955
|
|
|
2956
2956
|
if (!manager) {
|
|
2957
|
+
logWarn('remote', 'managed RemoteAgent connect rejected: invalid manager endpoint');
|
|
2957
2958
|
return { ok: false, error: 'invalid-manager-endpoint', agent: serializeRemoteAgentState() };
|
|
2958
2959
|
}
|
|
2959
2960
|
|
|
2960
2961
|
if (!pairToken) {
|
|
2962
|
+
logWarn('remote', `managed RemoteAgent connect rejected: missing pair token ${formatKeyValue('manager', manager)}`);
|
|
2961
2963
|
return { ok: false, error: 'missing-pair-token', agent: serializeRemoteAgentState() };
|
|
2962
2964
|
}
|
|
2963
2965
|
|
|
@@ -3056,6 +3058,7 @@ async function startRemoteAgentConnection(options = {}) {
|
|
|
3056
3058
|
const exitedEarly = await waitForRemoteAgentEarlyExit(child);
|
|
3057
3059
|
if (exitedEarly) {
|
|
3058
3060
|
const error = formatRemoteAgentFailureSummary();
|
|
3061
|
+
logWarn('remote', `managed RemoteAgent exited during startup ${formatKeyValue('manager', manager)} ${formatKeyValue('error', error)}`);
|
|
3059
3062
|
return { ok: false, error, agent: serializeRemoteAgentState() };
|
|
3060
3063
|
}
|
|
3061
3064
|
|
|
@@ -7615,14 +7618,18 @@ app.get('/api/remote/agent/status', (req, res) => {
|
|
|
7615
7618
|
app.post('/api/remote/agent/connect', async (req, res) => {
|
|
7616
7619
|
res.setHeader('Cache-Control', 'no-store');
|
|
7617
7620
|
try {
|
|
7621
|
+
const requestedManager = normalizeRemoteManagerEndpoint(req.body?.manager || req.body?.managerEndpoint);
|
|
7618
7622
|
const result = await startRemoteAgentConnection({
|
|
7619
|
-
manager:
|
|
7623
|
+
manager: requestedManager,
|
|
7620
7624
|
pairToken: req.body?.pairToken || req.body?.pair,
|
|
7621
7625
|
leaseId: req.body?.leaseId,
|
|
7622
7626
|
nodeId: req.body?.nodeId,
|
|
7623
7627
|
engine: req.body?.engine,
|
|
7624
7628
|
source: req.body?.source || 'registry'
|
|
7625
7629
|
});
|
|
7630
|
+
if (!result.ok) {
|
|
7631
|
+
logWarn('remote', `managed RemoteAgent connect failed ${formatKeyValue('manager', requestedManager || 'invalid')} ${formatKeyValue('error', result.error || 'unknown')}`);
|
|
7632
|
+
}
|
|
7626
7633
|
res.status(result.ok ? 200 : 400).json(result);
|
|
7627
7634
|
} catch (err) {
|
|
7628
7635
|
logError('remote', 'managed RemoteAgent connect failed.', err);
|