More MeshCore cleanup.
Ylian Saint-Hilaire committed
Jan 16, 2022 at 19:12 UTC
47a215951f22ae7217ff4a519fcd39a575356c4c
3 files changed
+9
-5028
MeshCentralServer.njsproj
+1
-1
@@ -22,7 +22,7 @@
22
<ItemGroup>
23
<Compile Include="agents\meshcmd.js" />
24
<Compile Include="agents\meshcmd.min.js" />
25
- <Compile Include="agents\meshcore.js" />
25
+ <Compile Include="agents\meshcore-clean.js" />
26
<Compile Include="agents\meshcore.min.js" />
27
<Compile Include="agents\meshinstall-linux.js" />
28
<Compile Include="agents\modules_meshcmd\amt-apfclient.js" />
agents/meshcore-org.js
deleted
-5017
@@ -1,5017 +0,0 @@
1
-/*
2
-Copyright 2018-2022 Intel Corporation
3
-
4
-Licensed under the Apache License, Version 2.0 (the "License");
5
-you may not use this file except in compliance with the License.
6
-You may obtain a copy of the License at
7
-
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
-Unless required by applicable law or agreed to in writing, software
11
-distributed under the License is distributed on an "AS IS" BASIS,
12
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
-See the License for the specific language governing permissions and
14
-limitations under the License.
15
-*/
16
-
17
-process.on('uncaughtException', function (ex) {
18
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException1: " + ex });
19
-});
20
-if (process.platform == 'win32' && require('user-sessions').getDomain == null) {
21
- require('user-sessions').getDomain = function getDomain(uid) {
22
- return (this.getSessionAttribute(uid, this.InfoClass.WTSDomainName));
23
- };
24
-}
25
-
26
-// NOTE: This seems to cause big problems, don't enable the debugger in the server's meshcore.
27
-//attachDebugger({ webport: 9999, wait: 1 }).then(function (prt) { console.log('Point Browser for Debug to port: ' + prt); });
28
-
29
-// Mesh Rights
30
-var MNG_ERROR = 65;
31
-var MESHRIGHT_EDITMESH = 1;
32
-var MESHRIGHT_MANAGEUSERS = 2;
33
-var MESHRIGHT_MANAGECOMPUTERS = 4;
34
-var MESHRIGHT_REMOTECONTROL = 8;
35
-var MESHRIGHT_AGENTCONSOLE = 16;
36
-var MESHRIGHT_SERVERFILES = 32;
37
-var MESHRIGHT_WAKEDEVICE = 64;
38
-var MESHRIGHT_SETNOTES = 128;
39
-var MESHRIGHT_REMOTEVIEW = 256; // Remote View Only
40
-var MESHRIGHT_NOTERMINAL = 512;
41
-var MESHRIGHT_NOFILES = 1024;
42
-var MESHRIGHT_NOAMT = 2048;
43
-var MESHRIGHT_LIMITEDINPUT = 4096;
44
-var MESHRIGHT_LIMITEVENTS = 8192;
45
-var MESHRIGHT_CHATNOTIFY = 16384;
46
-var MESHRIGHT_UNINSTALL = 32768;
47
-var MESHRIGHT_NODESKTOP = 65536;
48
-
49
-try {
50
- Object.defineProperty(Array.prototype, 'findIndex', {
51
- value: function (func) {
52
- var i = 0;
53
- for (i = 0; i < this.length; ++i) {
54
- if (func(this[i], i, this)) {
55
- return (i);
56
- }
57
- }
58
- return (-1);
59
- }
60
- });
61
-}
62
-catch (x) {
63
-}
64
-
65
-if (require('MeshAgent').ARCHID == null) {
66
- var id = null;
67
- switch (process.platform) {
68
- case 'win32':
69
- id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
70
- break;
71
- case 'freebsd':
72
- id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
73
- break;
74
- case 'darwin':
75
- try {
76
- id = require('os').arch() == 'x64' ? 16 : 29;
77
- }
78
- catch (xx) {
79
- id = 16;
80
- }
81
- break;
82
- }
83
- if (id != null) { Object.defineProperty(require('MeshAgent'), 'ARCHID', { value: id }); }
84
-}
85
-
86
-function setDefaultCoreTranslation(obj, field, value) {
87
- if (obj[field] == null || obj[field] == '') { obj[field] = value; }
88
-}
89
-
90
-function getCoreTranslation() {
91
- var ret = {};
92
- if (global.coretranslations != null) {
93
- try {
94
- var lang = require('util-language').current;
95
- if (coretranslations[lang] == null) { lang = lang.split('-')[0]; }
96
- if (coretranslations[lang] == null) { lang = 'en'; }
97
- if (coretranslations[lang] != null) { ret = coretranslations[lang]; }
98
- }
99
- catch (ex) { }
100
- }
101
-
102
- setDefaultCoreTranslation(ret, 'allow', 'Allow');
103
- setDefaultCoreTranslation(ret, 'deny', 'Deny');
104
- setDefaultCoreTranslation(ret, 'autoAllowForFive', 'Auto accept all connections for next 5 minutes');
105
- setDefaultCoreTranslation(ret, 'terminalConsent', '{0} requesting remote terminal access. Grant access?');
106
- setDefaultCoreTranslation(ret, 'desktopConsent', '{0} requesting remote desktop access. Grant access?');
107
- setDefaultCoreTranslation(ret, 'fileConsent', '{0} requesting remote file Access. Grant access?');
108
- setDefaultCoreTranslation(ret, 'terminalNotify', '{0} started a remote terminal session.');
109
- setDefaultCoreTranslation(ret, 'desktopNotify', '{0} started a remote desktop session.');
110
- setDefaultCoreTranslation(ret, 'fileNotify', '{0} started a remote file session.');
111
- setDefaultCoreTranslation(ret, 'privacyBar', 'Sharing desktop with: {0}');
112
-
113
- return (ret);
114
-}
115
-var currentTranslation = getCoreTranslation();
116
-
117
-function lockDesktop(uid) {
118
- switch (process.platform) {
119
- case 'linux':
120
- if (uid != null) {
121
- var name = require('user-sessions').getUsername(uid);
122
- var child = require('child_process').execFile('/bin/sh', ['sh']);
123
- child.stdout.str = ''; child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
124
- child.stderr.str = ''; child.stderr.on('data', function (chunk) { this.str += chunk.toString(); });
125
- child.stdin.write('loginctl show-user -p Sessions ' + name + " | awk '{");
126
- child.stdin.write('gsub(/^Sessions=/,"",$0);');
127
- child.stdin.write('cmd = sprintf("loginctl lock-session %s",$0);');
128
- child.stdin.write('system(cmd);');
129
- child.stdin.write("}'\nexit\n");
130
- child.waitExit();
131
- }
132
- else {
133
- var child = require('child_process').execFile('/bin/sh', ['sh']);
134
- child.stdout.str = ''; child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
135
- child.stderr.str = ''; child.stderr.on('data', function (chunk) { this.str += chunk.toString(); });
136
- child.stdin.write('loginctl lock-sessions\nexit\n');
137
- child.waitExit();
138
- }
139
- break;
140
- case 'win32':
141
- {
142
- var options = { type: 1, uid: uid };
143
- var child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], options);
144
- child.waitExit();
145
- }
146
- break;
147
- default:
148
- break;
149
- }
150
-}
151
-var writable = require('stream').Writable;
152
-function destopLockHelper_pipe(httprequest) {
153
- if (process.platform != 'linux' && process.platform != 'freebsd') { return; }
154
-
155
- if (httprequest.unlockerHelper == null && httprequest.desktop != null && httprequest.desktop.kvm != null) {
156
- httprequest.unlockerHelper = new writable(
157
- {
158
- 'write': function (chunk, flush) {
159
- if (chunk.readUInt16BE(0) == 65) {
160
- delete this.request.autolock;
161
- }
162
- flush();
163
- return (true);
164
- },
165
- 'final': function (flush) {
166
- flush();
167
- }
168
- });
169
- httprequest.unlockerHelper.request = httprequest;
170
- httprequest.desktop.kvm.pipe(httprequest.unlockerHelper);
171
- }
172
-}
173
-
174
-var obj = { serverInfo: {} };
175
-var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests from the server.
176
-var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server.
177
-var debugConsole = (global._MSH && (_MSH().debugConsole == 1));
178
-
179
-if (process.platform == 'win32' && require('user-sessions').isRoot()) {
180
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
181
- try {
182
- var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
183
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
184
- if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
185
- } catch (x) { }
186
-
187
- // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
188
- var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
189
- try {
190
- svcname = require('MeshAgent').serviceName;
191
- }
192
- catch (x) {
193
- }
194
-
195
- try {
196
- var meshCheck = false;
197
- try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (e) { }
198
- if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
199
- } catch (e) { }
200
-}
201
-
202
-if (process.platform != 'win32') {
203
- var ch = require('child_process');
204
- ch._execFile = ch.execFile;
205
- ch.execFile = function execFile(path, args, options) {
206
- if (options && options.type && options.type == ch.SpawnTypes.TERM && options.env) {
207
- options.env['TERM'] = 'xterm-256color';
208
- }
209
- return (this._execFile(path, args, options));
210
- };
211
-}
212
-
213
-
214
-if (process.platform == 'darwin' && !process.versions) {
215
- // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
216
- var child = require('child_process').execFile('/bin/sh', ['sh']);
217
- child.stdout.str = '';
218
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
219
- child.stdin.write("cat /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist | tr '\n' '\.' | awk '{split($0, a, \"<key>KeepAlive</key>\"); split(a[2], b, \"<\"); split(b[2], c, \">\"); ");
220
- child.stdin.write(" if(c[1]==\"dict\"){ split(a[2], d, \"</dict>\"); if(split(d[1], truval, \"<true/>\")>1) { split(truval[1], kn1, \"<key>\"); split(kn1[2], kn2, \"</key>\"); print kn2[1]; } }");
221
- child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
222
- child.waitExit();
223
- if (child.stdout.str.trim() == 'Crashed') {
224
- child = require('child_process').execFile('/bin/sh', ['sh']);
225
- child.stdout.str = '';
226
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
227
- child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
228
- child.waitExit();
229
-
230
- if (parseInt(child.stdout.str.trim()) == process.pid) {
231
- // The currently running MeshAgent is us, so we can continue with the update
232
- var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
233
- var tokens = plist.split('<key>KeepAlive</key>');
234
- if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
235
- var tmp = tokens[1].split('</dict>');
236
- tmp.shift();
237
- tokens[1] = '\n <true/>' + tmp.join('</dict>');
238
- tokens = tokens.join('<key>KeepAlive</key>');
239
-
240
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
241
-
242
- var fix = '';
243
- fix += ("function macosRepair()\n");
244
- fix += ("{\n");
245
- fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
246
- fix += (" child.stdout.str = '';\n");
247
- fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
248
- fix += (" child.stderr.on('data', function (chunk) { });\n");
249
- fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
250
- fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
251
- fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
252
- fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
253
- fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
254
- fix += (" child.waitExit();\n");
255
- fix += ("}\n");
256
- fix += ("macosRepair();\n");
257
- fix += ("process.exit();\n");
258
- require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
259
-
260
- var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
261
- plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
262
- plist += '<plist version="1.0">\n';
263
- plist += ' <dict>\n';
264
- plist += ' <key>Label</key>\n';
265
- plist += (' <string>meshagentRepair</string>\n');
266
- plist += ' <key>ProgramArguments</key>\n';
267
- plist += ' <array>\n';
268
- plist += (' <string>' + process.execPath + '</string>\n');
269
- plist += ' <string>macosRepair.js</string>\n';
270
- plist += ' </array>\n';
271
- plist += ' <key>WorkingDirectory</key>\n';
272
- plist += (' <string>' + process.cwd() + '</string>\n');
273
- plist += ' <key>RunAtLoad</key>\n';
274
- plist += ' <true/>\n';
275
- plist += ' </dict>\n';
276
- plist += '</plist>';
277
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
278
-
279
- child = require('child_process').execFile('/bin/sh', ['sh']);
280
- child.stdout.str = '';
281
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
282
- child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
283
- child.waitExit();
284
- }
285
- }
286
- }
287
-}
288
-
289
-// Add an Intel AMT event to the log
290
-function addAmtEvent(msg) {
291
- if (obj.amtevents == null) { obj.amtevents = []; }
292
- var d = new Date(), e = zeroPad(d.getHours(), 2) + ':' + zeroPad(d.getMinutes(), 2) + ':' + zeroPad(d.getSeconds(), 2) + ', ' + msg;
293
- obj.amtevents.push(e);
294
- if (obj.amtevents.length > 100) { obj.amtevents.splice(0, obj.amtevents.length - 100); }
295
- if (obj.showamtevent) { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: e }); }
296
-}
297
-function zeroPad(num, size) { var s = '000000000' + num; return s.substr(s.length - size); }
298
-
299
-
300
-// Create Secure IPC for Diagnostic Agent Communications
301
-obj.DAIPC = require('net').createServer();
302
-if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
303
-obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
304
-try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
305
-obj.DAIPC._daipc = [];
306
-obj.DAIPC.on('connection', function (c) {
307
- c._send = function (j) {
308
- var data = JSON.stringify(j);
309
- var packet = Buffer.alloc(data.length + 4);
310
- packet.writeUInt32LE(data.length + 4, 0);
311
- Buffer.from(data).copy(packet, 4);
312
- this.write(packet);
313
- };
314
- this._daipc.push(c);
315
- c.parent = this;
316
- c.on('end', function () { removeRegisteredApp(this); });
317
- c.on('data', function (chunk) {
318
- if (chunk.length < 4) { this.unshift(chunk); return; }
319
- var len = chunk.readUInt32LE(0);
320
- if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
321
- if (chunk.length < len) { this.unshift(chunk); return; }
322
-
323
- var data = chunk.slice(4, len);
324
- try { data = JSON.parse(data.toString()); } catch (e) { }
325
- if ((data == null) || (typeof data.cmd != 'string')) return;
326
-
327
- try {
328
- switch (data.cmd) {
329
- case 'requesthelp':
330
- if (this._registered == null) return;
331
- sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
332
- var help = {};
333
- help[this._registered] = data.value;
334
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (e) { }
335
- MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
336
- break;
337
- case 'cancelhelp':
338
- if (this._registered == null) return;
339
- sendConsoleText('Cancel Help (' + this._registered + ')');
340
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
341
- break;
342
- case 'register':
343
- if (typeof data.value == 'string') {
344
- this._registered = data.value;
345
- var apps = {};
346
- apps[data.value] = 1;
347
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
348
- this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
349
- }
350
- break;
351
- case 'query':
352
- switch (data.value) {
353
- case 'connection':
354
- data.result = require('MeshAgent').ConnectedServer;
355
- this._send(data);
356
- break;
357
- case 'descriptors':
358
- require('ChainViewer').getSnapshot().then(function (f) {
359
- this.tag.payload.result = f;
360
- this.tag.ipc._send(this.tag.payload);
361
- }).parentPromise.tag = { ipc: this, payload: data };
362
- break;
363
- case 'timerinfo':
364
- data.result = require('ChainViewer').getTimerInfo();
365
- this._send(data);
366
- break;
367
- }
368
- break;
369
- case 'amtstate':
370
- if (amt == null) return;
371
- var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
372
- func.pipe = this;
373
- amt.getMeiState(11, func);
374
- break;
375
- case 'sessions':
376
- this._send({ cmd: 'sessions', sessions: tunnelUserCount });
377
- break;
378
- case 'meshToolInfo':
379
- try { mesh.SendCommand({ action: 'meshToolInfo', name: data.name, hash: data.hash, cookie: data.cookie ? true : false, pipe: true }); } catch (e) { }
380
- break;
381
- case 'getUserImage':
382
- try { mesh.SendCommand({ action: 'getUserImage', userid: data.userid, pipe: true }); } catch (e) { }
383
- break;
384
- case 'console':
385
- if (debugConsole) {
386
- var args = splitArgs(data.value);
387
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), 0, 'pipe');
388
- }
389
- break;
390
- }
391
- }
392
- catch (e) { removeRegisteredApp(this); this.end(); return; }
393
- });
394
-});
395
-
396
-// Send current sessions to registered apps
397
-function broadcastSessionsToRegisteredApps(x) {
398
- var p = {}, i;
399
- for (i = 0; sendAgentMessage.messages != null && i < sendAgentMessage.messages.length; ++i) {
400
- p[i] = sendAgentMessage.messages[i];
401
- }
402
- tunnelUserCount.msg = p;
403
- broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
404
- tunnelUserCount.msg = {};
405
-}
406
-
407
-// Send this object to all registered local applications
408
-function broadcastToRegisteredApps(x) {
409
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
410
- for (var i in obj.DAIPC._daipc) {
411
- if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); }
412
- }
413
-}
414
-
415
-// Send this object to a specific registered local applications
416
-function sendToRegisteredApp(appid, x) {
417
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
418
- for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered == appid) { obj.DAIPC._daipc[i]._send(x); } }
419
-}
420
-
421
-// Send list of registered apps to the server
422
-function updateRegisteredAppsToServer() {
423
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
424
- var apps = {};
425
- for (var i in obj.DAIPC._daipc) { if (apps[obj.DAIPC._daipc[i]._registered] == null) { apps[obj.DAIPC._daipc[i]._registered] = 1; } else { apps[obj.DAIPC._daipc[i]._registered]++; } }
426
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
427
-}
428
-
429
-// Remove a registered app
430
-function removeRegisteredApp(pipe) {
431
- for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
432
- if (pipe._registered != null) updateRegisteredAppsToServer();
433
-}
434
-
435
-function diagnosticAgent_uninstall() {
436
- require('service-manager').manager.uninstallService('meshagentDiagnostic');
437
- require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
438
-}
439
-function diagnosticAgent_installCheck(install) {
440
- try {
441
- var diag = require('service-manager').manager.getService('meshagentDiagnostic');
442
- return (diag);
443
- }
444
- catch (e) {
445
- }
446
- if (!install) { return (null); }
447
-
448
- var svc = null;
449
- try {
450
- require('service-manager').manager.installService(
451
- {
452
- name: 'meshagentDiagnostic',
453
- displayName: "Mesh Agent Diagnostic Service",
454
- description: "Mesh Agent Diagnostic Service",
455
- servicePath: process.execPath,
456
- parameters: ['-recovery']
457
- //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
458
- });
459
- svc = require('service-manager').manager.getService('meshagentDiagnostic');
460
- }
461
- catch (e) {
462
- return (null);
463
- }
464
- var proxyConfig = require('global-tunnel').proxyConfig;
465
- var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
466
- var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
467
- ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
468
- ddb.Put('disableUpdate', '1');
469
- ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
470
- ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
471
- ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
472
- if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
473
- if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
474
- if (proxyConfig) {
475
- ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
476
- }
477
- else {
478
- ddb.Put('ignoreProxyFile', '1');
479
- }
480
-
481
- require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
482
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
483
-
484
- delete ddb;
485
-
486
- // Set a recurrent task, to run the Diagnostic Agent every 2 days
487
- require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic' });
488
- //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
489
-
490
- return (svc);
491
-}
492
-
493
-// Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
494
-if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
495
- // Setup manual battery monitoring
496
- require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
497
- if (require('MeshAgent')._batteryFileTimer != null) return;
498
- require('MeshAgent')._batteryFileTimer = setTimeout(function () {
499
- try {
500
- require('MeshAgent')._batteryFileTimer = null;
501
- var data = null;
502
- try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
503
- if ((data != null) && (data.length < 10)) {
504
- data = data.split(',');
505
- if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
506
- var level = parseInt(data[1]);
507
- if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
508
- }
509
- }
510
- } catch (e) { }
511
- }, 1000);
512
- });
513
-}
514
-else {
515
- try {
516
- // Setup normal battery monitoring
517
- if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) {
518
- require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
519
- _battLevelChanged.self._currentBatteryLevel = val;
520
- _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
521
- };
522
- require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
523
- require('MeshAgent')._powerChanged = function _powerChanged(val) {
524
- _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
525
- _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
526
- };
527
- require('MeshAgent')._powerChanged.self = require('MeshAgent');
528
- require('MeshAgent').on('Connected', function (status) {
529
- if (status == 0) {
530
- require('power-monitor').removeListener('acdc', this._powerChanged);
531
- require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
532
- } else {
533
- require('power-monitor').on('acdc', this._powerChanged);
534
- require('power-monitor').on('batteryLevel', this._battLevelChanged);
535
- }
536
- });
537
- }
538
- }
539
- catch (e) {
540
- }
541
-}
542
-
543
-
544
-// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
545
-var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? ((process.versions.compileTime ? process.versions.compileTime : '').split(', ')[1].replace(' ', ' ') + ', ' + crc32c(require('MeshAgent').coreHash)) : ('MeshCore v6')), caps: 14, root: require('user-sessions').isRoot() }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
546
-
547
-// Get the operating system description string
548
-try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (e) { }
549
-
550
-
551
-// Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
552
-try {
553
- var userSession = require('user-sessions');
554
- userSession.on('changed', function onUserSessionChanged() {
555
- userSession.enumerateUsers().then(function (users) {
556
- if (process.platform == 'linux') {
557
- if (userSession._startTime == null) {
558
- userSession._startTime = Date.now();
559
- userSession._count = users.length;
560
- }
561
- else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) {
562
- userSession.removeAllListeners('changed');
563
- return;
564
- }
565
- }
566
-
567
- var u = [], a = users.Active;
568
- for (var i = 0; i < a.length; i++) {
569
- var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
570
- if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
571
- }
572
- meshCoreObj.users = u;
573
- meshCoreObjChanged();
574
- });
575
- });
576
- userSession.emit('changed');
577
- //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
578
- //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
579
-} catch (e) { }
580
-
581
-var meshServerConnectionState = 0;
582
-var tunnels = {};
583
-var lastNetworkInfo = null;
584
-var lastPublicLocationInfo = null;
585
-var selfInfoUpdateTimer = null;
586
-var http = require('http');
587
-var net = require('net');
588
-var fs = require('fs');
589
-var rtc = require('ILibWebRTC');
590
-var amt = null;
591
-var processManager = require('process-manager');
592
-var wifiScannerLib = null;
593
-var wifiScanner = null;
594
-var networkMonitor = null;
595
-var nextTunnelIndex = 1;
596
-var apftunnel = null;
597
-var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
598
-
599
-// Add to the server event log
600
-function MeshServerLog(msg, state) {
601
- if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
602
- if (state) {
603
- if (state.userid) { msg.userid = state.userid; }
604
- if (state.username) { msg.username = state.username; }
605
- if (state.sessionid) { msg.sessionid = state.sessionid; }
606
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
607
- if (state.guestname) { msg.guestname = state.guestname; }
608
- }
609
- mesh.SendCommand(msg);
610
-}
611
-
612
-// Add to the server event log, use internationalized events
613
-function MeshServerLogEx(id, args, msg, state) {
614
- var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
615
- if (state) {
616
- if (state.userid) { msg.userid = state.userid; }
617
- if (state.xuserid) { msg.xuserid = state.xuserid; }
618
- if (state.username) { msg.username = state.username; }
619
- if (state.sessionid) { msg.sessionid = state.sessionid; }
620
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
621
- if (state.guestname) { msg.guestname = state.guestname; }
622
- }
623
- mesh.SendCommand(msg);
624
-}
625
-
626
-// Import libraries
627
-db = require('SimpleDataStore').Shared();
628
-sha = require('SHA256Stream');
629
-mesh = require('MeshAgent');
630
-childProcess = require('child_process');
631
-
632
-if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
633
- // Check if this computer supports a desktop
634
- try {
635
- if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) {
636
- meshCoreObj.caps |= 1; meshCoreObjChanged();
637
- } else if (process.platform == 'linux' || process.platform == 'freebsd') {
638
- require('monitor-info').on('kvmSupportDetected', function (value) { meshCoreObj.caps |= 1; meshCoreObjChanged(); });
639
- }
640
- } catch (e) { }
641
-}
642
-mesh.DAIPC = obj.DAIPC;
643
-
644
-/*
645
-// Try to load up the network monitor
646
-try {
647
- networkMonitor = require('NetworkMonitor');
648
- networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
649
- networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
650
- networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
651
-} catch (e) { networkMonitor = null; }
652
-*/
653
-
654
-// Fetch the SMBios Tables
655
-var SMBiosTables = null;
656
-var SMBiosTablesRaw = null;
657
-try {
658
- var SMBiosModule = null;
659
- try { SMBiosModule = require('smbios'); } catch (e) { }
660
- if (SMBiosModule != null) {
661
- SMBiosModule.get(function (data) {
662
- if (data != null) {
663
- SMBiosTablesRaw = data;
664
- SMBiosTables = require('smbios').parse(data)
665
- if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
666
-
667
- // If SMBios tables say that Intel AMT is present, try to connect MEI
668
- if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true)) {
669
- var amtmodule = require('amt-manage');
670
- amt = new amtmodule(mesh, db, false);
671
- amt.on('portBinding_LMS', function (map) { mesh.SendCommand({ action: 'lmsinfo', value: { ports: map.keys() } }); });
672
- amt.on('stateChange_LMS', function (v) { if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; } meshCoreObj.intelamt.microlms = v; meshCoreObjChanged(); }); // 0 = Disabled, 1 = Connecting, 2 = Connected
673
- amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } } // MEI State
674
- amt.reset();
675
- }
676
- }
677
- });
678
- }
679
-} catch (e) { sendConsoleText("ex1: " + e); }
680
-
681
-// Try to load up the WIFI scanner
682
-try {
683
- var wifiScannerLib = require('wifi-scanner');
684
- wifiScanner = new wifiScannerLib();
685
- wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
686
-} catch (e) { wifiScannerLib = null; wifiScanner = null; }
687
-
688
-// Get our location (lat/long) using our public IP address
689
-var getIpLocationDataExInProgress = false;
690
-var getIpLocationDataExCounts = [0, 0];
691
-function getIpLocationDataEx(func) {
692
- if (getIpLocationDataExInProgress == true) { return false; }
693
- try {
694
- getIpLocationDataExInProgress = true;
695
- getIpLocationDataExCounts[0]++;
696
- var options = http.parseUri("http://ipinfo.io/json");
697
- options.method = 'GET';
698
- http.request(options, function (resp) {
699
- if (resp.statusCode == 200) {
700
- var geoData = '';
701
- resp.data = function (geoipdata) { geoData += geoipdata; };
702
- resp.end = function () {
703
- var location = null;
704
- try {
705
- if (typeof geoData == 'string') {
706
- var result = JSON.parse(geoData);
707
- if (result.ip && result.loc) { location = result; }
708
- }
709
- } catch (e) { }
710
- if (func) { getIpLocationDataExCounts[1]++; func(location); }
711
- }
712
- } else
713
- { func(null); }
714
- getIpLocationDataExInProgress = false;
715
- }).end();
716
- return true;
717
- }
718
- catch (e) { return false; }
719
-}
720
-
721
-// Setup script task. Allows running scripts at scheduled intervals
722
-var scriptTask = null;
723
-try { scriptTask = require('scripttask'); } catch (ex) { }
724
-
725
-// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
726
-function clearGatewayMac(str) {
727
- if (typeof str != 'string') return null;
728
- var x = JSON.parse(str);
729
- for (var i in x.netif) { try { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } } catch (ex) { } }
730
- return JSON.stringify(x);
731
-}
732
-
733
-function getIpLocationData(func) {
734
- // Get the location information for the cache if possible
735
- var publicLocationInfo = db.Get('publicLocationInfo');
736
- if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
737
- if (publicLocationInfo == null) {
738
- // Nothing in the cache, fetch the data
739
- getIpLocationDataEx(function (locationData) {
740
- if (locationData != null) {
741
- publicLocationInfo = {};
742
- publicLocationInfo.netInfoStr = lastNetworkInfo;
743
- publicLocationInfo.locationData = locationData;
744
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
745
- if (func) func(locationData); // Report the new location
746
- }
747
- else {
748
- if (func) func(null); // Report no location
749
- }
750
- });
751
- }
752
- else {
753
- // Check the cache
754
- if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
755
- // Cache match
756
- if (func) func(publicLocationInfo.locationData);
757
- }
758
- else {
759
- // Cache mismatch
760
- getIpLocationDataEx(function (locationData) {
761
- if (locationData != null) {
762
- publicLocationInfo = {};
763
- publicLocationInfo.netInfoStr = lastNetworkInfo;
764
- publicLocationInfo.locationData = locationData;
765
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
766
- if (func) func(locationData); // Report the new location
767
- }
768
- else {
769
- if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
770
- }
771
- });
772
- }
773
- }
774
-}
775
-
776
-// Polyfill String.endsWith
777
-if (!String.prototype.endsWith) {
778
- String.prototype.endsWith = function (searchString, position) {
779
- var subjectString = this.toString();
780
- if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
781
- position -= searchString.length;
782
- var lastIndex = subjectString.lastIndexOf(searchString, position);
783
- return lastIndex !== -1 && lastIndex === position;
784
- };
785
-}
786
-
787
-// Polyfill path.join
788
-obj.path =
789
- {
790
- join: function () {
791
- var x = [];
792
- for (var i in arguments) {
793
- var w = arguments[i];
794
- if (w != null) {
795
- while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
796
- if (i != 0) {
797
- while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
798
- }
799
- x.push(w);
800
- }
801
- }
802
- if (x.length == 0) return '/';
803
- return x.join('/');
804
- }
805
- };
806
-
807
-// Replace a string with a number if the string is an exact number
808
-function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
809
-
810
-// Convert decimal to hex
811
-function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
812
-
813
-// Convert a raw string to a hex string
814
-function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
815
-
816
-// Convert a buffer into a string
817
-function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
818
-
819
-// Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
820
-function hex2rstr(d) {
821
- if (typeof d != "string" || d.length == 0) return '';
822
- var r = '', m = ('' + d).match(/../g), t;
823
- while (t = m.shift()) r += String.fromCharCode('0x' + t);
824
- return r
825
-}
826
-
827
-// Convert an object to string with all functions
828
-function objToString(x, p, pad, ret) {
829
- if (ret == undefined) ret = '';
830
- if (p == undefined) p = 0;
831
- if (x == null) { return '[null]'; }
832
- if (p > 8) { return '[...]'; }
833
- if (x == undefined) { return '[undefined]'; }
834
- if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; }
835
- if (typeof x == 'buffer') { return '[buffer]'; }
836
- if (typeof x != 'object') { return x; }
837
- var r = '{' + (ret ? '\r\n' : ' ');
838
- for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
839
- return r + addPad(p, pad) + '}';
840
-}
841
-
842
-// Return p number of spaces
843
-function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
844
-
845
-// Split a string taking into account the quoats. Used for command line parsing
846
-function splitArgs(str) {
847
- var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
848
- do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
849
- return myArray;
850
-}
851
-
852
-// Parse arguments string array into an object
853
-function parseArgs(argv) {
854
- var results = { '_': [] }, current = null;
855
- for (var i = 1, len = argv.length; i < len; i++) {
856
- var x = argv[i];
857
- if (x.length > 2 && x[0] == '-' && x[1] == '-') {
858
- if (current != null) { results[current] = true; }
859
- current = x.substring(2);
860
- } else {
861
- if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
862
- }
863
- }
864
- if (current != null) { results[current] = true; }
865
- return results;
866
-}
867
-
868
-// Get server target url with a custom path
869
-function getServerTargetUrl(path) {
870
- var x = mesh.ServerUrl;
871
- //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
872
- if (x == null) { return null; }
873
- if (path == null) { path = ''; }
874
- x = http.parseUri(x);
875
- if (x == null) return null;
876
- return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
877
-}
878
-
879
-// Get server url. If the url starts with "*/..." change it, it not use the url as is.
880
-function getServerTargetUrlEx(url) {
881
- if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
882
- return url;
883
-}
884
-
885
-function sendWakeOnLanEx_interval() {
886
- var t = require('MeshAgent').wakesockets;
887
- if (t.list.length == 0) {
888
- clearInterval(t);
889
- delete require('MeshAgent').wakesockets;
890
- return;
891
- }
892
-
893
- var mac = t.list.shift().split(':').join('')
894
- var magic = 'FFFFFFFFFFFF';
895
- for (var x = 1; x <= 16; ++x) { magic += mac; }
896
- var magicbin = Buffer.from(magic, 'hex');
897
-
898
- for (var i in t.sockets) {
899
- t.sockets[i].send(magicbin, 7, '255.255.255.255');
900
- //sendConsoleText('Sending wake packet on ' + JSON.stringify(t.sockets[i].address()));
901
- }
902
-}
903
-function sendWakeOnLanEx(hexMacList) {
904
- var ret = 0;
905
-
906
- if (require('MeshAgent').wakesockets == null) {
907
- // Create a new interval timer
908
- require('MeshAgent').wakesockets = setInterval(sendWakeOnLanEx_interval, 10);
909
- require('MeshAgent').wakesockets.sockets = [];
910
- require('MeshAgent').wakesockets.list = hexMacList;
911
-
912
- var interfaces = require('os').networkInterfaces();
913
- for (var adapter in interfaces) {
914
- if (interfaces.hasOwnProperty(adapter)) {
915
- for (var i = 0; i < interfaces[adapter].length; ++i) {
916
- var addr = interfaces[adapter][i];
917
- if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
918
- try {
919
- var socket = require('dgram').createSocket({ type: 'udp4' });
920
- socket.bind({ address: addr.address });
921
- socket.setBroadcast(true);
922
- socket.setMulticastInterface(addr.address);
923
- socket.setMulticastTTL(1);
924
- socket.descriptorMetadata = 'WoL (' + addr.address + ')';
925
- require('MeshAgent').wakesockets.sockets.push(socket);
926
- ++ret;
927
- }
928
- catch (e) { }
929
- }
930
- }
931
- }
932
- }
933
- }
934
- else {
935
- // Append to an existing interval timer
936
- for (var i in hexMacList) {
937
- require('MeshAgent').wakesockets.list.push(hexMacList[i]);
938
- }
939
- ret = require('MeshAgent').wakesockets.sockets.length;
940
- }
941
-
942
- return (ret);
943
-}
944
-
945
-function server_promise_default(res, rej) {
946
- this.resolve = res;
947
- this.reject = rej;
948
-}
949
-function server_getUserImage(userid) {
950
- var promise = require('promise');
951
- var ret = new promise(server_promise_default);
952
-
953
- if (require('MeshAgent')._promises == null) { require('MeshAgent')._promises = {}; }
954
- require('MeshAgent')._promises[ret._hashCode()] = ret;
955
- require('MeshAgent').SendCommand({ action: 'getUserImage', userid: userid, promise: ret._hashCode(), default: true });
956
- return (ret);
957
-}
958
-require('MeshAgent')._consentTimers = {};
959
-function server_set_consentTimer(id) {
960
- require('MeshAgent')._consentTimers[id] = new Date();
961
-}
962
-function server_check_consentTimer(id) {
963
- if (require('MeshAgent')._consentTimers[id] != null) {
964
- if ((new Date()) - require('MeshAgent')._consentTimers[id] < (60000 * 5)) {
965
- return (true);
966
- }
967
- else {
968
- require('MeshAgent')._consentTimers[id] = null;
969
- }
970
- }
971
- return (false);
972
-}
973
-
974
-// Handle a mesh agent command
975
-function handleServerCommand(data) {
976
- if (typeof data == 'object') {
977
- // If this is a console command, parse it and call the console handler
978
- switch (data.action) {
979
- case 'agentupdate':
980
- agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
981
- break;
982
- case 'msg': {
983
- switch (data.type) {
984
- case 'console': { // Process a console command
985
- if ((typeof data.rights != 'number') || ((data.rights & 8) == 0) || ((data.rights & 16) == 0)) break; // Check console rights (Remote Control and Console)
986
- if (data.value && data.sessionid) {
987
- MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
988
- var args = splitArgs(data.value);
989
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
990
- }
991
- break;
992
- }
993
- case 'tunnel': {
994
- if (data.value != null) { // Process a new tunnel connection request
995
- // Create a new tunnel object
996
- var xurl = getServerTargetUrlEx(data.value);
997
- if (xurl != null) {
998
- xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
999
- var woptions = http.parseUri(xurl);
1000
- woptions.perMessageDeflate = false;
1001
- if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
1002
-
1003
- // Perform manual server TLS certificate checking based on the certificate hash given by the server.
1004
- woptions.rejectUnauthorized = 0;
1005
- woptions.checkServerIdentity = function checkServerIdentity(certs) {
1006
- /*
1007
- try { sendConsoleText("certs[0].digest: " + certs[0].digest); } catch (ex) { sendConsoleText(ex); }
1008
- try { sendConsoleText("certs[0].fingerprint: " + certs[0].fingerprint); } catch (ex) { sendConsoleText(ex); }
1009
- try { sendConsoleText("control-digest: " + require('MeshAgent').ServerInfo.ControlChannelCertificate.digest); } catch (ex) { sendConsoleText(ex); }
1010
- try { sendConsoleText("control-fingerprint: " + require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint); } catch (ex) { sendConsoleText(ex); }
1011
- */
1012
-
1013
- // Check if this is an old agent, no certificate checks are possible in this situation. Display a warning.
1014
- if ((require('MeshAgent').ServerInfo == null) || (require('MeshAgent').ServerInfo.ControlChannelCertificate == null) || (certs[0].digest == null)) { sendAgentMessage("This agent is using insecure tunnels, consider updating.", 3, 119, true); return; }
1015
-
1016
- // If the tunnel certificate matches the control channel certificate, accept the connection
1017
- if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; // Control channel certificate matches using full cert hash
1018
- if ((certs[0].fingerprint != null) && (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint)) return; // Control channel certificate matches using public key hash
1019
-
1020
- // Check that the certificate is the one expected by the server, fail if not.
1021
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1022
- }
1023
- woptions.checkServerIdentity.servertlshash = data.servertlshash;
1024
-
1025
- //sendConsoleText(JSON.stringify(woptions));
1026
- //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
1027
- var tunnel = http.request(woptions);
1028
- tunnel.upgrade = onTunnelUpgrade;
1029
- tunnel.on('error', function (e) { sendConsoleText("ERROR: Unable to connect relay tunnel to: " + this.url + ", " + JSON.stringify(e)); });
1030
- tunnel.sessionid = data.sessionid;
1031
- tunnel.rights = data.rights;
1032
- tunnel.consent = data.consent;
1033
- if (global._MSH && _MSH().LocalConsent != null) { tunnel.consent |= parseInt(_MSH().LocalConsent); }
1034
- tunnel.privacybartext = data.privacybartext ? data.privacybartext : currentTranslation['privacyBar'];
1035
- tunnel.username = data.username + (data.guestname ? (' - ' + data.guestname) : '');
1036
- tunnel.realname = (data.realname ? data.realname : data.username) + (data.guestname ? (' - ' + data.guestname) : '');
1037
- tunnel.guestname = data.guestname;
1038
- tunnel.userid = data.userid;
1039
-
1040
- if (server_check_consentTimer(tunnel.userid)) {
1041
- sendConsoleText('Deleting Consent Requirement');
1042
- tunnel.consent = (tunnel.consent & -57);
1043
- }
1044
-
1045
- tunnel.desktopviewonly = data.desktopviewonly;
1046
- tunnel.remoteaddr = data.remoteaddr;
1047
- tunnel.state = 0;
1048
- tunnel.url = xurl;
1049
- tunnel.protocol = 0;
1050
- tunnel.soptions = data.soptions;
1051
- tunnel.tcpaddr = data.tcpaddr;
1052
- tunnel.tcpport = data.tcpport;
1053
- tunnel.udpaddr = data.udpaddr;
1054
- tunnel.udpport = data.udpport;
1055
- tunnel.end();
1056
- // Put the tunnel in the tunnels list
1057
- var index = nextTunnelIndex++;
1058
- tunnel.index = index;
1059
- tunnels[index] = tunnel;
1060
-
1061
- //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
1062
- }
1063
- }
1064
- break;
1065
- }
1066
- case 'endtunnel': {
1067
- // Terminate one or more tunnels
1068
- if ((data.rights != 4294967295) && (data.xuserid != data.userid)) return; // This command requires full admin rights on the device or user self-closes it's own sessions
1069
- for (var i in tunnels) {
1070
- if ((tunnels[i].userid == data.xuserid) && (tunnels[i].guestname == data.guestname)) {
1071
- var disconnect = false, msgid = 0;
1072
- if ((data.protocol == 'kvm') && (tunnels[i].protocol == 2)) { msgid = 134; disconnect = true; }
1073
- else if ((data.protocol == 'terminal') && (tunnels[i].protocol == 1)) { msgid = 135; disconnect = true; }
1074
- else if ((data.protocol == 'files') && (tunnels[i].protocol == 5)) { msgid = 136; disconnect = true; }
1075
- else if ((data.protocol == 'tcp') && (tunnels[i].tcpport != null)) { msgid = 137; disconnect = true; }
1076
- else if ((data.protocol == 'udp') && (tunnels[i].udpport != null)) { msgid = 137; disconnect = true; }
1077
- if (disconnect) {
1078
- if (tunnels[i].s != null) { tunnels[i].s.end(); } else { tunnels[i].end(); }
1079
-
1080
- // Log tunnel disconnection
1081
- var xusername = data.xuserid.split('/')[2];
1082
- if (data.guestname != null) { xusername += '/' + guestname; }
1083
- MeshServerLogEx(msgid, [xusername], "Forcibly disconnected session of user: " + xusername, data);
1084
- }
1085
- }
1086
- }
1087
- break;
1088
- }
1089
- case 'messagebox': {
1090
- // Display a message box
1091
- if (data.title && data.msg) {
1092
- MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
1093
- try { require('message-box').create(data.title, data.msg, 120).then(function () { }).catch(function () { }); } catch (e) { }
1094
- }
1095
- break;
1096
- }
1097
- case 'ps': {
1098
- // Return the list of running processes
1099
- if (data.sessionid) {
1100
- processManager.getProcesses(function (plist) {
1101
- mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
1102
- });
1103
- }
1104
- break;
1105
- }
1106
- case 'psinfo': {
1107
- // Requestion details information about a process
1108
- if (data.pid) {
1109
- var info = {}; // TODO: Replace with real data. Feel free not to give all values if not available.
1110
- /*
1111
- info.processUser = "User"; // String
1112
- info.processDomain = "Domain"; // String
1113
- info.cmd = "abc"; // String
1114
- info.processName = "dummydata";
1115
- info.privateMemorySize = 123; // Bytes
1116
- info.virtualMemorySize = 123; // Bytes
1117
- info.workingSet = 123; // Bytes
1118
- info.totalProcessorTime = 123; // Seconds
1119
- info.userProcessorTime = 123; // Seconds
1120
- info.startTime = "2012-12-30T23:59:59.000Z"; // Time in UTC ISO format
1121
- info.sessionId = 123; // Number
1122
- info.privilegedProcessorTime = 123; // Seconds
1123
- info.PriorityBoostEnabled = true; // Boolean
1124
- info.peakWorkingSet = 123; // Bytes
1125
- info.peakVirtualMemorySize = 123; // Bytes
1126
- info.peakPagedMemorySize = 123; // Bytes
1127
- info.pagedSystemMemorySize = 123; // Bytes
1128
- info.pagedMemorySize = 123; // Bytes
1129
- info.nonpagedSystemMemorySize = 123; // Bytes
1130
- info.mainWindowTitle = "dummydata"; // String
1131
- info.machineName = "dummydata"; // Only set this if machine name is not "."
1132
- info.handleCount = 123; // Number
1133
- */
1134
- mesh.SendCommand({ action: 'msg', type: 'psinfo', pid: data.pid, sessionid: data.sessionid, value: info });
1135
- }
1136
- break;
1137
- }
1138
- case 'pskill': {
1139
- // Kill a process
1140
- if (data.value) {
1141
- MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
1142
- try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
1143
- }
1144
- break;
1145
- }
1146
- case 'services': {
1147
- // Return the list of installed services
1148
- var services = null;
1149
- try { services = require('service-manager').manager.enumerateService(); } catch (e) { }
1150
- if (services != null) { mesh.SendCommand({ action: 'msg', type: 'services', value: JSON.stringify(services), sessionid: data.sessionid }); }
1151
- break;
1152
- }
1153
- case 'serviceStop': {
1154
- // Stop a service
1155
- try {
1156
- var service = require('service-manager').manager.getService(data.serviceName);
1157
- if (service != null) { service.stop(); }
1158
- } catch (e) { }
1159
- break;
1160
- }
1161
- case 'serviceStart': {
1162
- // Start a service
1163
- try {
1164
- var service = require('service-manager').manager.getService(data.serviceName);
1165
- if (service != null) { service.start(); }
1166
- } catch (e) { }
1167
- break;
1168
- }
1169
- case 'serviceRestart': {
1170
- // Restart a service
1171
- try {
1172
- var service = require('service-manager').manager.getService(data.serviceName);
1173
- if (service != null) { service.restart(); }
1174
- } catch (e) { }
1175
- break;
1176
- }
1177
- case 'deskBackground':
1178
- {
1179
- // Toggle desktop background
1180
- try {
1181
- if (process.platform == 'win32') {
1182
- var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
1183
- var sid = undefined;
1184
- if (stype == 1) {
1185
- if (require('MeshAgent')._tsid != null) {
1186
- stype = 5;
1187
- sid = require('MeshAgent')._tsid;
1188
- }
1189
- }
1190
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
1191
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: stype, uid: sid });
1192
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
1193
- child.stderr.on('data', function () { });
1194
- child.waitExit();
1195
- var current = child.stdout.str.trim();
1196
- if (current != '') { require('MeshAgent')._wallpaper = current; }
1197
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: stype, uid: sid });
1198
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
1199
- child.stderr.on('data', function () { });
1200
- child.waitExit();
1201
- } else {
1202
- var id = require('user-sessions').consoleUid();
1203
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
1204
- if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
1205
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
1206
- }
1207
- } catch (e) {
1208
- sendConsoleText(e);
1209
- }
1210
- break;
1211
- }
1212
- case 'openUrl': {
1213
- // Open a local web browser and return success/fail
1214
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1215
- sendConsoleText("OpenURL: " + data.url);
1216
- if (data.url) { mesh.SendCommand({ action: 'msg', type: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1217
- break;
1218
- }
1219
- case 'getclip': {
1220
- // Send the load clipboard back to the user
1221
- //sendConsoleText('getClip: ' + JSON.stringify(data));
1222
- if (require('MeshAgent').isService) {
1223
- require('clipboard').dispatchRead().then(function (str) {
1224
- if (str) {
1225
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
1226
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
1227
- }
1228
- });
1229
- } else {
1230
- require("clipboard").read().then(function (str) {
1231
- if (str) {
1232
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
1233
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
1234
- }
1235
- });
1236
- }
1237
- break;
1238
- }
1239
- case 'setclip': {
1240
- // Set the load clipboard to a user value
1241
- if (typeof data.data == 'string') {
1242
- MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
1243
- if (require('MeshAgent').isService) {
1244
- if (process.platform != 'win32') {
1245
- require('clipboard').dispatchWrite(data.data);
1246
- }
1247
- else {
1248
- var clipargs = data.data;
1249
- var uid = require('user-sessions').consoleUid();
1250
- var user = require('user-sessions').getUsername(uid);
1251
- var domain = require('user-sessions').getDomain(uid);
1252
- user = (domain + '\\' + user);
1253
-
1254
- this._dispatcher = require('win-dispatcher').dispatch({ user: user, modules: [{ name: 'clip-dispatch', script: "module.exports = { dispatch: function dispatch(val) { require('clipboard')(val); process.exit(); } };" }], launch: { module: 'clip-dispatch', method: 'dispatch', args: [clipargs] } });
1255
- this._dispatcher.parent = this;
1256
- //require('events').setFinalizerMetadata.call(this._dispatcher, 'clip-dispatch');
1257
- this._dispatcher.on('connection', function (c) {
1258
- this._c = c;
1259
- this._c.root = this.parent;
1260
- this._c.on('end', function () {
1261
- this.root._dispatcher = null;
1262
- this.root = null;
1263
- });
1264
- });
1265
- }
1266
- }
1267
- else {
1268
- require("clipboard")(data.data);
1269
- } // Set the clipboard
1270
- mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
1271
- }
1272
- break;
1273
- }
1274
- case 'userSessions': {
1275
- // Send back current user sessions list, this is Windows only.
1276
- //sendConsoleText('userSessions: ' + JSON.stringify(data));
1277
- if (process.platform != 'win32') break;
1278
- var p = require('user-sessions').enumerateUsers();
1279
- p.sessionid = data.sessionid;
1280
- p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u, tag: data.tag }); });
1281
- break;
1282
- }
1283
- case 'cpuinfo':
1284
- // CPU & memory utilization
1285
- var cpuuse = require('sysinfo').cpuUtilization();
1286
- cpuuse.sessionid = data.sessionid;
1287
- cpuuse.tag = data.tag;
1288
- cpuuse.then(function (data) {
1289
- mesh.SendCommand(JSON.stringify(
1290
- {
1291
- action: 'msg',
1292
- type: 'cpuinfo',
1293
- cpu: data,
1294
- memory: require('sysinfo').memUtilization(),
1295
- thermals: require('sysinfo').thermals == null ? [] : require('sysinfo').thermals(),
1296
- sessionid: this.sessionid,
1297
- tag: this.tag
1298
- }));
1299
- }, function (ex) { });
1300
- break;
1301
- case 'localapp':
1302
- // Send a message to a local application
1303
- sendConsoleText('localappMsg: ' + data.appid + ', ' + JSON.stringify(data.value));
1304
- if (data.appid != null) { sendToRegisteredApp(data.appid, data.value); } else { broadcastToRegisteredApps(data.value); }
1305
- break;
1306
- default:
1307
- // Unknown action, ignore it.
1308
- break;
1309
- }
1310
- break;
1311
- }
1312
- case 'acmactivate': {
1313
- if (amt != null) {
1314
- MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
1315
- amt.setAcmResponse(data);
1316
- }
1317
- break;
1318
- }
1319
- case 'wakeonlan': {
1320
- // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
1321
- //sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
1322
- sendWakeOnLanEx(data.macs);
1323
- sendWakeOnLanEx(data.macs);
1324
- sendWakeOnLanEx(data.macs);
1325
- break;
1326
- }
1327
- case 'runcommands': {
1328
- if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; }
1329
- sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds);
1330
-
1331
- // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
1332
- var options = {};
1333
- if (data.runAsUser > 0) {
1334
- try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
1335
- options.type = require('child_process').SpawnTypes.TERM;
1336
- }
1337
- if (data.runAsUser == 2) {
1338
- if (options.uid == null) break;
1339
- if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1340
- }
1341
-
1342
- if (process.platform == 'win32') {
1343
- if (data.type == 1) {
1344
- // Windows command shell
1345
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1346
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1347
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1348
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1349
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1350
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1351
- } else if (data.type == 2) {
1352
- // Windows Powershell
1353
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1354
- mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
1355
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1356
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1357
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1358
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1359
- }
1360
- } else if (data.type == 3) {
1361
- // Linux shell
1362
- mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1363
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1364
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1365
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1366
- mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
1367
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1368
- }
1369
- break;
1370
- }
1371
- case 'uninstallagent':
1372
- // Uninstall this agent
1373
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1374
- try {
1375
- agentName = require('MeshAgent').serviceName;
1376
- }
1377
- catch (x) {
1378
- }
1379
-
1380
- if (require('service-manager').manager.getService(agentName).isMe()) {
1381
- try { diagnosticAgent_uninstall(); } catch (e) { }
1382
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1383
- this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
1384
- }
1385
- break;
1386
- case 'poweraction': {
1387
- // Server telling us to execute a power action
1388
- if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
1389
- var forced = 0;
1390
- if (data.forced == 1) { forced = 1; }
1391
- data.actiontype = parseInt(data.actiontype);
1392
- MeshServerLogEx(25, [data.actiontype, forced], "Performing power action=" + data.actiontype + ", forced=" + forced, data);
1393
- sendConsoleText("Performing power action=" + data.actiontype + ", forced=" + forced + '.');
1394
- var r = mesh.ExecPowerState(data.actiontype, forced);
1395
- sendConsoleText("ExecPowerState returned code: " + r);
1396
- }
1397
- break;
1398
- }
1399
- case 'iplocation': {
1400
- // Update the IP location information of this node. Only do this when requested by the server since we have a limited amount of time we can call this per day
1401
- getIpLocationData(function (location) { mesh.SendCommand({ action: 'iplocation', type: 'publicip', value: location }); });
1402
- break;
1403
- }
1404
- case 'toast': {
1405
- // Display a toast message
1406
- if (data.title && data.msg) {
1407
- MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1408
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1409
- try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
1410
- }
1411
- break;
1412
- }
1413
- case 'openUrl': {
1414
- // Open a local web browser and return success/fail
1415
- //sendConsoleText('OpenURL: ' + data.url);
1416
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1417
- if (data.url) { mesh.SendCommand({ action: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1418
- break;
1419
- }
1420
- case 'amtconfig': {
1421
- // Perform Intel AMT activation and/or configuration
1422
- if ((apftunnel != null) || (amt == null) || (typeof data.user != 'string') || (typeof data.pass != 'string')) break;
1423
- amt.getMeiState(15, function (state) {
1424
- if ((apftunnel != null) || (amt == null)) return;
1425
- if ((state == null) || (state.ProvisioningState == null)) return;
1426
- if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
1427
- getAmtOsDnsSuffix(state, function () {
1428
- var apfarg = {
1429
- mpsurl: mesh.ServerUrl.replace('/agent.ashx', '/apf.ashx'),
1430
- mpsuser: data.user, // Agent user name
1431
- mpspass: data.pass, // Encrypted login cookie
1432
- mpskeepalive: 60000,
1433
- clientname: state.OsHostname,
1434
- clientaddress: '127.0.0.1',
1435
- clientuuid: state.UUID,
1436
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
1437
- meiState: state // MEI state will be passed to MPS server
1438
- };
1439
- addAmtEvent('LMS tunnel start.');
1440
- apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
1441
- apftunnel.onJsonControl = handleApfJsonControl;
1442
- apftunnel.onChannelClosed = function () { addAmtEvent('LMS tunnel closed.'); apftunnel = null; }
1443
- try { apftunnel.connect(); } catch (ex) { }
1444
- });
1445
- });
1446
- break;
1447
- }
1448
- case 'getScript': {
1449
- // Received a configuration script from the server
1450
- sendConsoleText('getScript: ' + JSON.stringify(data));
1451
- break;
1452
- }
1453
- case 'sysinfo': {
1454
- // Fetch system information
1455
- getSystemInformation(function (results) {
1456
- if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1457
- });
1458
- break;
1459
- }
1460
- case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
1461
- case 'pong': { break; }
1462
- case 'plugin': {
1463
- try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; }
1464
- break;
1465
- }
1466
- case 'coredump':
1467
- // Set the current agent coredump situation.s
1468
- if (data.value === true) {
1469
- if (process.platform == 'win32') {
1470
- // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1471
- process.coreDumpLocation = process.execPath.replace('.exe', '.dmp');
1472
- } else {
1473
- process.coreDumpLocation = (process.cwd() != '//') ? (process.cwd() + 'core') : null;
1474
- }
1475
- } else if (data.value === false) {
1476
- process.coreDumpLocation = null;
1477
- }
1478
- break;
1479
- case 'getcoredump':
1480
- // Ask the agent if a core dump is currently available, if yes, also return the hash of the agent.
1481
- var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1482
- var coreDumpPath = null;
1483
- if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1484
- if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath))) {
1485
- try {
1486
- var coredate = fs.statSync(coreDumpPath).mtime;
1487
- var coretime = new Date(coredate).getTime();
1488
- var agenttime = new Date(fs.statSync(process.execPath).mtime).getTime();
1489
- if (coretime > agenttime) { r.exists = (db.Get('CoreDumpTime') != coredate); }
1490
- } catch (ex) { }
1491
- }
1492
- if (r.exists == true) {
1493
- r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); // Hash of current agent
1494
- r.corehashhex = getSHA384FileHash(coreDumpPath).toString('hex'); // Hash of core dump file
1495
- }
1496
- mesh.SendCommand(JSON.stringify(r));
1497
- break;
1498
- case 'meshToolInfo':
1499
- if (data.pipe == true) { delete data.pipe; delete data.action; data.cmd = 'meshToolInfo'; broadcastToRegisteredApps(data); }
1500
- if (data.tag == 'info') { sendConsoleText(JSON.stringify(data, null, 2)); }
1501
- if (data.tag == 'install') {
1502
- data.func = function (options, success) {
1503
- sendConsoleText('Download of MeshCentral Assistant ' + (success ? 'succeed' : 'failed'));
1504
- if (success) {
1505
- // TODO: Install & Run
1506
- }
1507
- }
1508
- data.filename = 'MeshAssistant.exe';
1509
- downloadFile(data);
1510
- }
1511
- break;
1512
- case 'getUserImage':
1513
- if (data.pipe == true) { delete data.pipe; delete data.action; data.cmd = 'getUserImage'; broadcastToRegisteredApps(data); }
1514
- if (data.tag == 'info') { sendConsoleText(JSON.stringify(data, null, 2)); }
1515
- if (data.promise != null && require('MeshAgent')._promises[data.promise] != null) {
1516
- var p = require('MeshAgent')._promises[data.promise];
1517
- delete require('MeshAgent')._promises[data.promise];
1518
- p.resolve(data.image);
1519
- }
1520
- break;
1521
- case 'wget': // Server uses this command to tell the agent to download a file using HTTPS/GET and place it in a given path. This is used for one-to-many file uploads.
1522
- agentFileHttpPendingRequests.push(data);
1523
- serverFetchFile();
1524
- break;
1525
- case 'serverInfo': // Server information
1526
- obj.serverInfo = data;
1527
- delete obj.serverInfo.action;
1528
- break;
1529
- case 'errorlog': // Return agent error log
1530
- try { mesh.SendCommand(JSON.stringify({ action: 'errorlog', log: require('util-agentlog').read(data.startTime) })); } catch (ex) { }
1531
- break;
1532
- default:
1533
- // Unknown action, ignore it.
1534
- break;
1535
- }
1536
- }
1537
-}
1538
-
1539
-// On non-Windows platforms, we need to query the DHCP server for the DNS suffix
1540
-function getAmtOsDnsSuffix(mestate, func) {
1541
- if ((process.platform == 'win32') || (mestate.net0 == null) || (mestate.net0.mac == null)) { func(mestate); return; }
1542
- try { require('linux-dhcp') } catch (ex) { func(mestate); return; }
1543
- require('linux-dhcp').client.info(mestate.net0.mac).then(function (d) {
1544
- if ((typeof d.options == 'object') && (typeof d.options.domainname == 'string')) { mestate.OsDnsSuffix = d.options.domainname; }
1545
- func(mestate);
1546
- }, function (e) {
1547
- console.log('DHCP error', e);
1548
- func(mestate);
1549
- });
1550
-}
1551
-
1552
-// Download a file from the server and check the hash.
1553
-// This download is similar to the one used for meshcore self-update.
1554
-var trustedDownloads = {};
1555
-function downloadFile(downloadoptions) {
1556
- var options = require('http').parseUri(downloadoptions.url);
1557
- options.rejectUnauthorized = false;
1558
- options.checkServerIdentity = function checkServerIdentity(certs) {
1559
- // If the tunnel certificate matches the control channel certificate, accept the connection
1560
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1561
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
1562
- // Check that the certificate is the one expected by the server, fail if not.
1563
- if (checkServerIdentity.servertlshash == null) { if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) return; throw new Error('BadCert'); }
1564
- if (certs[0].digest == null) return;
1565
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1566
- }
1567
- //options.checkServerIdentity.servertlshash = downloadoptions.serverhash;
1568
- trustedDownloads[downloadoptions.name] = downloadoptions;
1569
- trustedDownloads[downloadoptions.name].dl = require('https').get(options);
1570
- trustedDownloads[downloadoptions.name].dl.on('error', function (e) { downloadoptions.func(downloadoptions, false); delete trustedDownloads[downloadoptions.name]; });
1571
- trustedDownloads[downloadoptions.name].dl.on('response', function (img) {
1572
- this._file = require('fs').createWriteStream(trustedDownloads[downloadoptions.name].filename, { flags: 'wb' });
1573
- this._filehash = require('SHA384Stream').create();
1574
- this._filehash.on('hash', function (h) { if ((downloadoptions.hash != null) && (downloadoptions.hash.toLowerCase() != h.toString('hex').toLowerCase())) { downloadoptions.func(downloadoptions, false); delete trustedDownloads[downloadoptions.name]; return; } downloadoptions.func(downloadoptions, true); });
1575
- img.pipe(this._file);
1576
- img.pipe(this._filehash);
1577
- });
1578
-}
1579
-
1580
-// Handle APF JSON control commands
1581
-function handleApfJsonControl(data) {
1582
- if (data.action == 'console') { addAmtEvent(data.msg); } // Add console message to AMT event log
1583
- if (data.action == 'mestate') { amt.getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
1584
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
1585
- if (amt.amtMei != null) {
1586
- if (data.action == 'deactivate') { // Request CCM deactivation
1587
- amt.amtMei.unprovision(1, function (status) { if (apftunnel) apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
1588
- }
1589
- if (data.action == 'startTlsHostConfig') { // Request start of host based TLS ACM activation
1590
- amt.amtMei.startConfigurationHBased(Buffer.from(data.hash, 'hex'), data.hostVpn, data.dnsSuffixList, function (response) { apftunnel.sendStartTlsHostConfigResponse(response); });
1591
- }
1592
- if (data.action == 'stopConfiguration') { // Request Intel AMT stop configuration.
1593
- amt.amtMei.stopConfiguration(function (status) { apftunnel.sendStopConfigurationResponse(status); });
1594
- }
1595
- }
1596
-}
1597
-
1598
-// Agent just get a file from the server and save it locally.
1599
-function serverFetchFile() {
1600
- if ((Object.keys(agentFileHttpRequests).length > 4) || (agentFileHttpPendingRequests.length == 0)) return; // No more than 4 active HTTPS requests to the server.
1601
- var data = agentFileHttpPendingRequests.shift();
1602
- if ((data.overwrite !== true) && fs.existsSync(data.path)) return; // Don't overwrite an existing file.
1603
- if (data.createFolder) { try { fs.mkdirSync(data.folder); } catch (ex) { } } // If requested, create the local folder.
1604
- data.url = 'http' + getServerTargetUrlEx('*/').substring(2);
1605
- var agentFileHttpOptions = http.parseUri(data.url);
1606
- agentFileHttpOptions.path = data.urlpath;
1607
-
1608
- // Perform manual server TLS certificate checking based on the certificate hash given by the server.
1609
- agentFileHttpOptions.rejectUnauthorized = 0;
1610
- agentFileHttpOptions.checkServerIdentity = function checkServerIdentity(certs) {
1611
- // If the tunnel certificate matches the control channel certificate, accept the connection
1612
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1613
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
1614
- // Check that the certificate is the one expected by the server, fail if not.
1615
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1616
- }
1617
- agentFileHttpOptions.checkServerIdentity.servertlshash = data.servertlshash;
1618
-
1619
- if (agentFileHttpOptions == null) return;
1620
- var agentFileHttpRequest = http.request(agentFileHttpOptions,
1621
- function (response) {
1622
- response.xparent = this;
1623
- try {
1624
- response.xfile = fs.createWriteStream(this.xpath, { flags: 'wbN' })
1625
- response.pipe(response.xfile);
1626
- response.end = function () { delete agentFileHttpRequests[this.xparent.xurlpath]; delete this.xparent; serverFetchFile(); }
1627
- } catch (ex) { delete agentFileHttpRequests[this.xurlpath]; delete response.xparent; serverFetchFile(); return; }
1628
- }
1629
- );
1630
- agentFileHttpRequest.on('error', function (ex) { sendConsoleText(ex); delete agentFileHttpRequests[this.xurlpath]; serverFetchFile(); });
1631
- agentFileHttpRequest.end();
1632
- agentFileHttpRequest.xurlpath = data.urlpath;
1633
- agentFileHttpRequest.xpath = data.path;
1634
- agentFileHttpRequests[data.urlpath] = agentFileHttpRequest;
1635
-}
1636
-
1637
-// Called when a file changed in the file system
1638
-/*
1639
-function onFileWatcher(a, b) {
1640
- console.log('onFileWatcher', a, b, this.path);
1641
- var response = getDirectoryInfo(this.path);
1642
- if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
1643
-}
1644
-*/
1645
-
1646
-function getSystemInformation(func) {
1647
- try {
1648
- var results = { hardware: require('identifiers').get() }; // Hardware info
1649
-
1650
- if (results.hardware && results.hardware.windows) {
1651
- // Remove extra entries and things that change quickly
1652
- var x = results.hardware.windows.osinfo;
1653
- try { delete x.FreePhysicalMemory; } catch (e) { }
1654
- try { delete x.FreeSpaceInPagingFiles; } catch (e) { }
1655
- try { delete x.FreeVirtualMemory; } catch (e) { }
1656
- try { delete x.LocalDateTime; } catch (e) { }
1657
- try { delete x.MaxProcessMemorySize; } catch (e) { }
1658
- try { delete x.TotalVirtualMemorySize; } catch (e) { }
1659
- try { delete x.TotalVisibleMemorySize; } catch (e) { }
1660
- try {
1661
- if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1662
- if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1663
- if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1664
- } catch (e) { }
1665
- }
1666
- results.hardware.agentvers = process.versions;
1667
- var hasher = require('SHA384Stream').create();
1668
- results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1669
- func(results);
1670
-
1671
- /*
1672
- // On Windows platforms, get volume information - Needs more testing.
1673
- if (process.platform == 'win32')
1674
- {
1675
- results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot
1676
-
1677
- if (require('identifiers').volumes_promise != null)
1678
- {
1679
- var p = require('identifiers').volumes_promise();
1680
- p.then(function (res)
1681
- {
1682
- results.volumes = res;
1683
- results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1684
- func(results);
1685
- });
1686
- }
1687
- else if (require('identifiers').volumes != null)
1688
- {
1689
- results.volumes = require('identifiers').volumes();
1690
- results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1691
- func(results);
1692
- }
1693
- else
1694
- {
1695
- results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1696
- func(results);
1697
- }
1698
- }
1699
- else
1700
- {
1701
- results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1702
- func(results);
1703
- }
1704
- */
1705
- } catch (e) { func(null, e); }
1706
-}
1707
-
1708
-// Get a formated response for a given directory path
1709
-function getDirectoryInfo(reqpath) {
1710
- var response = { path: reqpath, dir: [] };
1711
- if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
1712
- // List all the drives in the root, or the root itself
1713
- var results = null;
1714
- try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1715
- if (results != null) {
1716
- for (var i = 0; i < results.length; ++i) {
1717
- var drive = { n: results[i].name, t: 1 };
1718
- if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1719
- response.dir.push(drive);
1720
- }
1721
- }
1722
- } else {
1723
- // List all the files and folders in this path
1724
- if (reqpath == '') { reqpath = '/'; }
1725
- var results = null, xpath = obj.path.join(reqpath, '*');
1726
- //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1727
- try { results = fs.readdirSync(xpath); } catch (e) { }
1728
- try { if ((results != null) && (results.length == 0) && (fs.existsSync(reqpath) == false)) { results = null; } } catch (e) { }
1729
- if (results != null) {
1730
- for (var i = 0; i < results.length; ++i) {
1731
- if ((results[i] != '.') && (results[i] != '..')) {
1732
- var stat = null, p = obj.path.join(reqpath, results[i]);
1733
- //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1734
- try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1735
- if ((stat != null) && (stat != undefined)) {
1736
- if (stat.isDirectory() == true) {
1737
- response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1738
- } else {
1739
- response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1740
- }
1741
- }
1742
- }
1743
- }
1744
- } else {
1745
- response.dir = null;
1746
- }
1747
- }
1748
- return response;
1749
-}
1750
-
1751
-// Tunnel callback operations
1752
-function onTunnelUpgrade(response, s, head) {
1753
- this.s = s;
1754
- s.httprequest = this;
1755
- s.end = onTunnelClosed;
1756
- s.tunnel = this;
1757
- s.descriptorMetadata = "MeshAgent_relayTunnel";
1758
-
1759
- if (require('MeshAgent').idleTimeout != null) {
1760
- s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1761
- s.on('timeout', function () {
1762
- this.ping();
1763
- this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1764
- });
1765
- }
1766
-
1767
- //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1768
-
1769
- if (this.tcpport != null) {
1770
- // This is a TCP relay connection, pause now and try to connect to the target.
1771
- s.pause();
1772
- s.data = onTcpRelayServerTunnelData;
1773
- var connectionOptions = { port: parseInt(this.tcpport) };
1774
- if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
1775
- s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
1776
- s.tcprelay.peerindex = this.index;
1777
-
1778
- // Add the TCP session to the count and update the server
1779
- if (s.httprequest.userid != null) {
1780
- var userid = getUserIdAndGuestNameFromHttpRequest(s.httprequest);
1781
- if (tunnelUserCount.tcp[userid] == null) { tunnelUserCount.tcp[userid] = 1; } else { tunnelUserCount.tcp[userid]++; }
1782
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1783
- broadcastSessionsToRegisteredApps();
1784
- }
1785
- } if (this.udpport != null) {
1786
- // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1787
- s.data = onUdpRelayServerTunnelData;
1788
- s.udprelay = require('dgram').createSocket({ type: 'udp4' });
1789
- s.udprelay.bind({ port: 0 });
1790
- s.udprelay.peerindex = this.index;
1791
- s.udprelay.on('message', onUdpRelayTargetTunnelConnect);
1792
- s.udprelay.udpport = this.udpport;
1793
- s.udprelay.udpaddr = this.udpaddr;
1794
- s.udprelay.first = true;
1795
-
1796
- // Add the UDP session to the count and update the server
1797
- if (s.httprequest.userid != null) {
1798
- var userid = getUserIdAndGuestNameFromHttpRequest(s.httprequest);
1799
- if (tunnelUserCount.udp[userid] == null) { tunnelUserCount.udp[userid] = 1; } else { tunnelUserCount.udp[userid]++; }
1800
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1801
- broadcastSessionsToRegisteredApps();
1802
- }
1803
- } else {
1804
- // This is a normal connect for KVM/Terminal/Files
1805
- s.data = onTunnelData;
1806
- }
1807
-}
1808
-
1809
-// If the HTTP Request has a guest name, we need to form a userid that includes the guest name in hex.
1810
-// This is so we can tell the server that a session is for a given userid/guest sharing pair.
1811
-function getUserIdAndGuestNameFromHttpRequest(request) {
1812
- if (request.guestname == null) return request.userid; else return request.userid + '/guest:' + Buffer.from(request.guestname).toString('base64');
1813
-}
1814
-
1815
-// Called when UDP relay data is received // TODO****
1816
-function onUdpRelayTargetTunnelConnect(data) {
1817
- var peerTunnel = tunnels[this.peerindex];
1818
- peerTunnel.s.write(data);
1819
-}
1820
-
1821
-// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1822
-function onUdpRelayServerTunnelData(data) {
1823
- if (this.udprelay.first === true) {
1824
- delete this.udprelay.first; // Skip the first 'c' that is received.
1825
- } else {
1826
- this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1827
- }
1828
-}
1829
-
1830
-// Called when the TCP relay target is connected
1831
-function onTcpRelayTargetTunnelConnect() {
1832
- var peerTunnel = tunnels[this.peerindex];
1833
- this.pipe(peerTunnel.s); // Pipe Target --> Server
1834
- peerTunnel.s.first = true;
1835
- peerTunnel.s.resume();
1836
-}
1837
-
1838
-// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1839
-function onTcpRelayServerTunnelData(data) {
1840
- if (this.first == true) {
1841
- this.first = false;
1842
- this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1843
- }
1844
-}
1845
-
1846
-function onTunnelClosed() {
1847
- var tunnel = tunnels[this.httprequest.index];
1848
- if (tunnel == null) return; // Stop duplicate calls.
1849
-
1850
- // Perform display locking on disconnect
1851
- if ((this.httprequest.protocol == 2) && (this.httprequest.autolock === true)) {
1852
- // Look for a TSID
1853
- var tsid = null;
1854
- if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
1855
-
1856
- // Lock the current user out of the desktop
1857
- MeshServerLogEx(53, null, "Locking remote user out of desktop", this.httprequest);
1858
- lockDesktop(tsid);
1859
- }
1860
-
1861
- // If this is a routing session, clean up and send the new session counts.
1862
- if (this.httprequest.userid != null) {
1863
- if (this.httprequest.tcpport != null) {
1864
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
1865
- if (tunnelUserCount.tcp[userid] != null) { tunnelUserCount.tcp[userid]--; if (tunnelUserCount.tcp[userid] <= 0) { delete tunnelUserCount.tcp[userid]; } }
1866
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1867
- broadcastSessionsToRegisteredApps();
1868
- } else if (this.httprequest.udpport != null) {
1869
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
1870
- if (tunnelUserCount.udp[userid] != null) { tunnelUserCount.udp[userid]--; if (tunnelUserCount.udp[userid] <= 0) { delete tunnelUserCount.udp[userid]; } }
1871
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1872
- broadcastSessionsToRegisteredApps();
1873
- }
1874
- }
1875
-
1876
- try {
1877
- // Sent tunnel statistics to the server, only send this if compression was used.
1878
- if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString())) {
1879
- mesh.SendCommand({
1880
- action: 'tunnelCloseStats',
1881
- url: tunnel.url,
1882
- userid: tunnel.userid,
1883
- protocol: tunnel.protocol,
1884
- sessionid: tunnel.sessionid,
1885
- sent: this.bytesSent_uncompressed.toString(),
1886
- sentActual: this.bytesSent_actual.toString(),
1887
- sentRatio: this.bytesSent_ratio,
1888
- received: this.bytesReceived_uncompressed.toString(),
1889
- receivedActual: this.bytesReceived_actual.toString(),
1890
- receivedRatio: this.bytesReceived_ratio
1891
- });
1892
- }
1893
- }
1894
- catch (z) {
1895
- }
1896
-
1897
- //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1898
- if (this.httprequest.index) { delete tunnels[this.httprequest.index]; }
1899
-
1900
- /*
1901
- // Close the watcher if required
1902
- if (this.httprequest.watcher != undefined) {
1903
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
1904
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
1905
- delete this.httprequest.watcher;
1906
- }
1907
- */
1908
-
1909
- // If there is a upload or download active on this connection, close the file
1910
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; delete this.httprequest.uploadFileSize; }
1911
- if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1912
-
1913
- // Clean up WebRTC
1914
- if (this.webrtc != null) {
1915
- if (this.webrtc.rtcchannel) { try { this.webrtc.rtcchannel.close(); } catch (e) { } this.webrtc.rtcchannel.removeAllListeners('data'); this.webrtc.rtcchannel.removeAllListeners('end'); delete this.webrtc.rtcchannel; }
1916
- if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1917
- try { this.webrtc.close(); } catch (e) { }
1918
- this.webrtc.removeAllListeners('connected');
1919
- this.webrtc.removeAllListeners('disconnected');
1920
- this.webrtc.removeAllListeners('dataChannel');
1921
- delete this.webrtc;
1922
- }
1923
-
1924
- // Clean up WebSocket
1925
- this.removeAllListeners('data');
1926
-}
1927
-
1928
-function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1929
-function onTunnelData(data) {
1930
- //console.log("OnTunnelData");
1931
- //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1932
-
1933
- // If this is upload data, save it to file
1934
- if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
1935
- // Save the data to file being uploaded.
1936
- if (data[0] == 0) {
1937
- // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1938
- this.httprequest.uploadFileSize += (data.length - 1);
1939
- try { fs.writeSync(this.httprequest.uploadFile, data, 1, data.length - 1); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
1940
- } else {
1941
- // If data does not start with zero, save as-is.
1942
- this.httprequest.uploadFileSize += data.length;
1943
- try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
1944
- }
1945
- this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
1946
- return;
1947
- }
1948
-
1949
- if (this.httprequest.state == 0) {
1950
- // Check if this is a relay connection
1951
- if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1952
- } else {
1953
- // Handle tunnel data
1954
- if (this.httprequest.protocol == 0) { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
1955
- // Take a look at the protocol
1956
- if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1957
- this.httprequest.protocol = parseInt(data);
1958
- if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1959
-
1960
- // See if this protocol request is allowed.
1961
- if ((this.httprequest.soptions != null) && (this.httprequest.soptions.usages != null) && (this.httprequest.soptions.usages.indexOf(this.httprequest.protocol) == -1)) { this.httprequest.protocol = 0; }
1962
-
1963
- if (this.httprequest.protocol == 10) {
1964
- //
1965
- // Basic file transfer
1966
- //
1967
- var stats = null;
1968
- if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1969
- try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1970
- try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1971
- if (this.httprequest.downloadFile) {
1972
- MeshServerLogEx(106, [this.httprequest.xoptions.file, stats.size], 'Download: \"' + this.httprequest.xoptions.file + '\", Size: ' + stats.size, this.httprequest);
1973
- //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1974
- this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1975
- this.httprequest.downloadFile.pipe(this);
1976
- this.httprequest.downloadFile.end = function () { }
1977
- } else {
1978
- //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1979
- this.write(JSON.stringify({ op: 'cancel' }));
1980
- }
1981
- }
1982
- else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) {
1983
- //
1984
- // Remote Terminal
1985
- //
1986
-
1987
- // Check user access rights for terminal
1988
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1989
- // Disengage this tunnel, user does not have the rights to do this!!
1990
- this.httprequest.protocol = 999999;
1991
- this.httprequest.s.end();
1992
- sendConsoleText("Error: No Terminal Control Rights.");
1993
- return;
1994
- }
1995
-
1996
- this.descriptorMetadata = "Remote Terminal";
1997
-
1998
- if (process.platform == 'win32') {
1999
- if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) {
2000
- this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
2001
- this.httprequest.s.end();
2002
- return;
2003
- }
2004
- }
2005
-
2006
- var prom = require('promise');
2007
- this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
2008
- this.httprequest.tpromise.that = this;
2009
- this.httprequest.tpromise.httprequest = this.httprequest;
2010
-
2011
- this.end = function () {
2012
- if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
2013
- if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
2014
-
2015
- // Remove the terminal session to the count to update the server
2016
- if (this.httprequest.userid != null) {
2017
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
2018
- if (tunnelUserCount.terminal[userid] != null) { tunnelUserCount.terminal[userid]--; if (tunnelUserCount.terminal[userid] <= 0) { delete tunnelUserCount.terminal[userid]; } }
2019
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
2020
- broadcastSessionsToRegisteredApps();
2021
- }
2022
-
2023
- if (process.platform == 'win32') {
2024
- // Unpipe the web socket
2025
- this.unpipe(this.httprequest._term);
2026
- if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
2027
-
2028
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
2029
- if (this.rtcchannel) {
2030
- this.rtcchannel.unpipe(this.httprequest._term);
2031
- if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
2032
- }
2033
-
2034
- // Clean up
2035
- if (this.httprequest._term) { this.httprequest._term.end(); }
2036
- this.httprequest._term = null;
2037
- }
2038
- };
2039
-
2040
- // Perform User-Consent if needed.
2041
- if (this.httprequest.consent && (this.httprequest.consent & 16)) {
2042
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2043
- var consentMessage = currentTranslation['terminalConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
2044
- var consentTitle = 'MeshCentral';
2045
-
2046
- if (this.httprequest.soptions != null) {
2047
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2048
- if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2049
- }
2050
- if (process.platform == 'win32') {
2051
- var enhanced = false;
2052
- try {
2053
- require('win-userconsent');
2054
- enhanced = true;
2055
- }
2056
- catch (z) {
2057
- }
2058
- if (enhanced) {
2059
- var ipr = server_getUserImage(this.httprequest.userid);
2060
- ipr.consentTitle = consentTitle;
2061
- ipr.consentMessage = consentMessage;
2062
- ipr.username = this.httprequest.realname;
2063
- ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2064
- this.httprequest.tpromise._consent = ipr.then(function (img) {
2065
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: 30000, translations: this.translations });
2066
- this.__childPromise.close = this.consent.close.bind(this.consent);
2067
- return (this.consent);
2068
- });
2069
- }
2070
- else {
2071
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
2072
- }
2073
- }
2074
- else {
2075
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
2076
- }
2077
- this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
2078
- this.httprequest.tpromise._consent.then(
2079
- function (always) {
2080
- if (always) { server_set_consentTimer(this.retPromise.httprequest.userid); }
2081
-
2082
- // Success
2083
- MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2084
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2085
- this.retPromise._consent = null;
2086
- this.retPromise._res();
2087
- },
2088
- function (e) {
2089
- // Denied
2090
- MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2091
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2092
- this.retPromise._rej(e.toString());
2093
- });
2094
- }
2095
- else {
2096
- // User-Consent is not required, so just resolve this promise
2097
- this.httprequest.tpromise._res();
2098
- }
2099
-
2100
-
2101
- this.httprequest.tpromise.then(
2102
- function () {
2103
- this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
2104
- this.httprequest.connectionPromise.ws = this.that;
2105
-
2106
- // Start Terminal
2107
- if (process.platform == 'win32') {
2108
- try {
2109
- var cols = 80, rows = 25;
2110
- if (this.httprequest.xoptions) {
2111
- if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
2112
- if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
2113
- }
2114
-
2115
- if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6)) {
2116
- // Admin Terminal
2117
- if (require('win-virtual-terminal').supported) {
2118
- // ConPTY PseudoTerminal
2119
- // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
2120
-
2121
- // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
2122
- this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
2123
- this.httprequest._dispatcher.httprequest = this.httprequest;
2124
- this.httprequest._dispatcher.on('connection', function (c) { if (this.httprequest.connectionPromise.completed) { c.end(); } else { this.httprequest.connectionPromise._res(c); } });
2125
- }
2126
- else {
2127
- // Legacy Terminal
2128
- this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
2129
- }
2130
- }
2131
- else {
2132
- // Logged in user
2133
- var userPromise = require('user-sessions').enumerateUsers();
2134
- userPromise.that = this;
2135
- userPromise.then(function (u) {
2136
- var that = this.that;
2137
- if (u.Active.length > 0) {
2138
- var username = '"' + u.Active[0].Domain + '\\' + u.Active[0].Username + '"';
2139
- //sendConsoleText('Terminal: ' + username);
2140
- if (require('win-virtual-terminal').supported) {
2141
- // ConPTY PseudoTerminal
2142
- that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
2143
- }
2144
- else {
2145
- // Legacy Terminal
2146
- that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
2147
- }
2148
- that.httprequest._dispatcher.ws = that;
2149
- that.httprequest._dispatcher.on('connection', function (c) { if (this.ws.httprequest.connectionPromise.completed) { c.end(); } else { this.ws.httprequest.connectionPromise._res(c); } });
2150
- }
2151
- });
2152
- }
2153
- }
2154
- catch (e) {
2155
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
2156
- }
2157
- }
2158
- else {
2159
- try {
2160
- var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
2161
- var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
2162
- var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
2163
-
2164
- var env = { HISTCONTROL: 'ignoreboth' };
2165
- if (process.env['LANG']) { env['LANG'] = process.env['LANG']; }
2166
- if (process.env['PATH']) { env['PATH'] = process.env['PATH']; }
2167
- if (this.httprequest.xoptions) {
2168
- if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
2169
- if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
2170
- }
2171
- var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
2172
- if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin) {
2173
- if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
2174
- this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
2175
- }
2176
- else if (bash) {
2177
- var p = childProcess.execFile(bash, ['bash'], options); // Start bash
2178
- // Spaces at the beginning of lines are needed to hide commands from the command history
2179
- if ((obj.serverInfo.termlaunchcommand != null) && (typeof obj.serverInfo.termlaunchcommand[process.platform] == 'string')) {
2180
- if (obj.serverInfo.termlaunchcommand[process.platform] != '') { p.stdin.write(obj.serverInfo.termlaunchcommand[process.platform]); }
2181
- } else if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
2182
- this.httprequest.connectionPromise._res(p);
2183
- }
2184
- else if (sh) {
2185
- var p = childProcess.execFile(sh, ['sh'], options); // Start sh
2186
- // Spaces at the beginning of lines are needed to hide commands from the command history
2187
- if ((obj.serverInfo.termlaunchcommand != null) && (typeof obj.serverInfo.termlaunchcommand[process.platform] == 'string')) {
2188
- if (obj.serverInfo.termlaunchcommand[process.platform] != '') { p.stdin.write(obj.serverInfo.termlaunchcommand[process.platform]); }
2189
- } else if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
2190
- this.httprequest.connectionPromise._res(p);
2191
- }
2192
- else {
2193
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
2194
- }
2195
- }
2196
- catch (e) {
2197
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
2198
- }
2199
- }
2200
-
2201
- this.httprequest.connectionPromise.then(
2202
- function (term) {
2203
- // SUCCESS
2204
- var stdoutstream;
2205
- var stdinstream;
2206
- if (process.platform == 'win32') {
2207
- this.ws.httprequest._term = term;
2208
- this.ws.httprequest._term.tunnel = this.ws;
2209
- stdoutstream = stdinstream = term;
2210
- }
2211
- else {
2212
- term.descriptorMetadata = 'Remote Terminal';
2213
- this.ws.httprequest.process = term;
2214
- this.ws.httprequest.process.tunnel = this.ws;
2215
- term.stderr.stdout = term.stdout;
2216
- term.stderr.on('data', function (c) { this.stdout.write(c); });
2217
- stdoutstream = term.stdout;
2218
- stdinstream = term.stdin;
2219
- this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
2220
- term.prependListener('exit', function () { this.tunnel.end(); });
2221
- }
2222
-
2223
- this.ws.removeAllListeners('data');
2224
- this.ws.on('data', onTunnelControlData);
2225
-
2226
- stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2227
- this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2228
-
2229
- // Add the terminal session to the count to update the server
2230
- if (this.ws.httprequest.userid != null) {
2231
- var userid = getUserIdAndGuestNameFromHttpRequest(this.ws.httprequest);
2232
- if (tunnelUserCount.terminal[userid] == null) { tunnelUserCount.terminal[userid] = 1; } else { tunnelUserCount.terminal[userid]++; }
2233
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
2234
- broadcastSessionsToRegisteredApps();
2235
- }
2236
-
2237
- // Toast Notification, if required
2238
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
2239
- // User Notifications is required
2240
- var notifyMessage = currentTranslation['terminalNotify'].replace('{0}', this.ws.httprequest.username);
2241
- var notifyTitle = "MeshCentral";
2242
- if (this.ws.httprequest.soptions != null) {
2243
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2244
- if (this.ws.httprequest.soptions.notifyMsgTerminal != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgTerminal.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
2245
- }
2246
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2247
- }
2248
- },
2249
- function (e) {
2250
- // FAILED to connect terminal
2251
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2252
- this.ws.end();
2253
- });
2254
- },
2255
- function (e) {
2256
- // DO NOT start terminal
2257
- this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2258
- this.that.end();
2259
- });
2260
- }
2261
- else if (this.httprequest.protocol == 2) {
2262
- //
2263
- // Remote Desktop
2264
- //
2265
-
2266
- // Check user access rights for desktop
2267
- if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
2268
- // Disengage this tunnel, user does not have the rights to do this!!
2269
- this.httprequest.protocol = 999999;
2270
- this.httprequest.s.end();
2271
- sendConsoleText("Error: No Desktop Control Rights.");
2272
- return;
2273
- }
2274
-
2275
- this.descriptorMetadata = "Remote KVM";
2276
-
2277
- // Look for a TSID
2278
- var tsid = null;
2279
- if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
2280
- require('MeshAgent')._tsid = tsid;
2281
-
2282
- // Remote desktop using native pipes
2283
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this };
2284
- this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
2285
- this.desktop = this.httprequest.desktop;
2286
-
2287
- // Add ourself to the list of remote desktop sessions
2288
- if (this.httprequest.desktop.kvm.tunnels == null) { this.httprequest.desktop.kvm.tunnels = []; }
2289
- this.httprequest.desktop.kvm.tunnels.push(this);
2290
-
2291
- // Send a metadata update to all desktop sessions
2292
- var users = {};
2293
- if (this.httprequest.desktop.kvm.tunnels != null) {
2294
- for (var i in this.httprequest.desktop.kvm.tunnels) {
2295
- try {
2296
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest.desktop.kvm.tunnels[i].httprequest);
2297
- if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; }
2298
- } catch (ex) { sendConsoleText(ex); }
2299
- }
2300
- for (var i in this.httprequest.desktop.kvm.tunnels) {
2301
- try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { }
2302
- }
2303
- tunnelUserCount.desktop = users;
2304
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
2305
- broadcastSessionsToRegisteredApps();
2306
- }
2307
-
2308
- this.end = function () {
2309
- --this.desktop.kvm.connectionCount;
2310
-
2311
- // Remove ourself from the list of remote desktop session
2312
- var i = this.desktop.kvm.tunnels.indexOf(this);
2313
- if (i >= 0) { this.desktop.kvm.tunnels.splice(i, 1); }
2314
-
2315
- // Send a metadata update to all desktop sessions
2316
- var users = {};
2317
- if (this.httprequest.desktop.kvm.tunnels != null) {
2318
- for (var i in this.httprequest.desktop.kvm.tunnels) {
2319
- try {
2320
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest.desktop.kvm.tunnels[i].httprequest);
2321
- if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; }
2322
- } catch (ex) { sendConsoleText(ex); }
2323
- }
2324
- for (var i in this.httprequest.desktop.kvm.tunnels) {
2325
- try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { }
2326
- }
2327
- tunnelUserCount.desktop = users;
2328
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
2329
- broadcastSessionsToRegisteredApps();
2330
- }
2331
-
2332
- // Unpipe the web socket
2333
- try {
2334
- this.unpipe(this.httprequest.desktop.kvm);
2335
- this.httprequest.desktop.kvm.unpipe(this);
2336
- }
2337
- catch (e) { }
2338
-
2339
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
2340
- if (this.rtcchannel) {
2341
- try {
2342
- this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
2343
- this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
2344
- }
2345
- catch (e) { }
2346
- }
2347
-
2348
- // Place wallpaper back if needed
2349
- // TODO
2350
-
2351
- if (this.desktop.kvm.connectionCount == 0) {
2352
- // Display a toast message. This may not be supported on all platforms.
2353
- // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
2354
-
2355
- this.httprequest.desktop.kvm.end();
2356
- if (this.httprequest.desktop.kvm.connectionBar) {
2357
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2358
- this.httprequest.desktop.kvm.connectionBar.close();
2359
- this.httprequest.desktop.kvm.connectionBar = null;
2360
- }
2361
- } else {
2362
- for (var i in this.httprequest.desktop.kvm.users) {
2363
- if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar) {
2364
- for (var j in this.httprequest.desktop.kvm.rusers) { if (this.httprequest.desktop.kvm.rusers[j] == this.httprequest.realname) { this.httprequest.desktop.kvm.rusers.splice(j, 1); break; } }
2365
- this.httprequest.desktop.kvm.users.splice(i, 1);
2366
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2367
- this.httprequest.desktop.kvm.connectionBar.close();
2368
- this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2369
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2370
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
2371
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2372
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2373
- this.httprequest.desktop.kvm._pipedStreams[i].end();
2374
- }
2375
- this.httprequest.desktop.kvm.end();
2376
- });
2377
- break;
2378
- }
2379
- }
2380
- }
2381
- };
2382
- if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
2383
- this.httprequest.desktop.kvm.connectionCount++;
2384
- this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
2385
- this.httprequest.desktop.kvm.users.push(this.httprequest.username);
2386
- this.httprequest.desktop.kvm.rusers.sort();
2387
- this.httprequest.desktop.kvm.users.sort();
2388
- } else {
2389
- this.httprequest.desktop.kvm.connectionCount = 1;
2390
- this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
2391
- this.httprequest.desktop.kvm.users = [this.httprequest.username];
2392
- }
2393
-
2394
- if ((this.httprequest.desktopviewonly != true) && ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)))) {
2395
- // If we have remote control rights, pipe the KVM input
2396
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
2397
- } else {
2398
- // We need to only pipe non-mouse & non-keyboard inputs.
2399
- // sendConsoleText('Warning: No Remote Desktop Input Rights.');
2400
- // TODO!!!
2401
- }
2402
-
2403
- // Perform notification if needed. Toast messages may not be supported on all platforms.
2404
- if (this.httprequest.consent && (this.httprequest.consent & 8)) {
2405
- // User Consent Prompt is required
2406
- // Send a console message back using the console channel, "\n" is supported.
2407
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2408
- var consentMessage = currentTranslation['desktopConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
2409
- var consentTitle = 'MeshCentral';
2410
- if (this.httprequest.soptions != null) {
2411
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2412
- if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2413
- }
2414
- var pr;
2415
- if (process.platform == 'win32') {
2416
- var enhanced = false;
2417
- try {
2418
- require('win-userconsent');
2419
- enhanced = true;
2420
- }
2421
- catch (z) {
2422
- }
2423
- if (enhanced) {
2424
- var ipr = server_getUserImage(this.httprequest.userid);
2425
- ipr.consentTitle = consentTitle;
2426
- ipr.consentMessage = consentMessage;
2427
- ipr.tsid = tsid;
2428
- ipr.username = this.httprequest.realname;
2429
- ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2430
- pr = ipr.then(function (img) {
2431
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: 30000, translations: this.translation });
2432
- this.__childPromise.close = this.consent.close.bind(this.consent);
2433
- return (this.consent);
2434
- });
2435
- }
2436
- else {
2437
- pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
2438
- }
2439
- }
2440
- else {
2441
- pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
2442
- }
2443
- pr.ws = this;
2444
- this.pause();
2445
- this._consentpromise = pr;
2446
- this.prependOnceListener('end', function () {
2447
- if (this._consentpromise && this._consentpromise.close) {
2448
- this._consentpromise.close();
2449
- }
2450
- });
2451
- pr.then(
2452
- function (always) {
2453
- if (always) { server_set_consentTimer(this.ws.httprequest.userid); }
2454
-
2455
- // Success
2456
- this.ws._consentpromise = null;
2457
- MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2458
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2459
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
2460
- // User Notifications is required
2461
- var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', this.ws.httprequest.realname);
2462
- var notifyTitle = "MeshCentral";
2463
- if (this.ws.httprequest.soptions != null) {
2464
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2465
- if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
2466
- }
2467
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2468
- }
2469
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40)) {
2470
- // Connection Bar is required
2471
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
2472
- this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2473
- this.ws.httprequest.desktop.kvm.connectionBar.close();
2474
- }
2475
- try {
2476
- this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2477
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2478
- }
2479
- catch (e) {
2480
- if (process.platform != 'darwin') {
2481
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2482
- }
2483
- }
2484
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
2485
- this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
2486
- this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
2487
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2488
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2489
- this.httprequest.desktop.kvm._pipedStreams[i].end();
2490
- }
2491
- this.httprequest.desktop.kvm.end();
2492
- });
2493
- }
2494
- }
2495
- this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
2496
- if (this.ws.httprequest.autolock) {
2497
- destopLockHelper_pipe(this.ws.httprequest);
2498
- }
2499
- this.ws.resume();
2500
- },
2501
- function (e) {
2502
- // User Consent Denied/Failed
2503
- this.ws._consentpromise = null;
2504
- MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2505
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2506
- });
2507
- } else {
2508
- // User Consent Prompt is not required
2509
- if (this.httprequest.consent && (this.httprequest.consent & 1)) {
2510
- // User Notifications is required
2511
- MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2512
- var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', this.ws.httprequest.realname);
2513
- var notifyTitle = "MeshCentral";
2514
- if (this.httprequest.soptions != null) {
2515
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2516
- if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2517
- }
2518
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2519
- } else {
2520
- MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2521
- }
2522
- if (this.httprequest.consent && (this.httprequest.consent & 0x40)) {
2523
- // Connection Bar is required
2524
- if (this.httprequest.desktop.kvm.connectionBar) {
2525
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2526
- this.httprequest.desktop.kvm.connectionBar.close();
2527
- }
2528
- try {
2529
- this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2530
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
2531
- }
2532
- catch (e) {
2533
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
2534
- }
2535
- if (this.httprequest.desktop.kvm.connectionBar) {
2536
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2537
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
2538
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2539
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2540
- this.httprequest.desktop.kvm._pipedStreams[i].end();
2541
- }
2542
- this.httprequest.desktop.kvm.end();
2543
- });
2544
- }
2545
- }
2546
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
2547
- if (this.httprequest.autolock) {
2548
- destopLockHelper_pipe(this.httprequest);
2549
- }
2550
- }
2551
-
2552
- this.removeAllListeners('data');
2553
- this.on('data', onTunnelControlData);
2554
- //this.write('MeshCore KVM Hello!1');
2555
-
2556
- } else if (this.httprequest.protocol == 5) {
2557
- //
2558
- // Remote Files
2559
- //
2560
-
2561
- // Check user access rights for files
2562
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
2563
- // Disengage this tunnel, user does not have the rights to do this!!
2564
- this.httprequest.protocol = 999999;
2565
- this.httprequest.s.end();
2566
- sendConsoleText("Error: No files control rights.");
2567
- return;
2568
- }
2569
-
2570
- this.descriptorMetadata = "Remote Files";
2571
-
2572
- // Add the files session to the count to update the server
2573
- if (this.httprequest.userid != null) {
2574
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
2575
- if (tunnelUserCount.files[userid] == null) { tunnelUserCount.files[userid] = 1; } else { tunnelUserCount.files[userid]++; }
2576
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2577
- broadcastSessionsToRegisteredApps();
2578
- }
2579
-
2580
- this.end = function () {
2581
- // Remove the files session from the count to update the server
2582
- if (this.httprequest.userid != null) {
2583
- var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
2584
- if (tunnelUserCount.files[userid] != null) { tunnelUserCount.files[userid]--; if (tunnelUserCount.files[userid] <= 0) { delete tunnelUserCount.files[userid]; } }
2585
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2586
- broadcastSessionsToRegisteredApps();
2587
- }
2588
- };
2589
-
2590
- // Perform notification if needed. Toast messages may not be supported on all platforms.
2591
- if (this.httprequest.consent && (this.httprequest.consent & 32)) {
2592
- // User Consent Prompt is required
2593
- // Send a console message back using the console channel, "\n" is supported.
2594
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2595
- var consentMessage = currentTranslation['fileConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
2596
- var consentTitle = 'MeshCentral';
2597
-
2598
- if (this.httprequest.soptions != null) {
2599
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2600
- if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2601
- }
2602
- var pr;
2603
- if (process.platform == 'win32') {
2604
- var enhanced = false;
2605
- try {
2606
- require('win-userconsent');
2607
- enhanced = true;
2608
- }
2609
- catch (z) {
2610
- }
2611
- if (enhanced) {
2612
- var ipr = server_getUserImage(this.httprequest.userid);
2613
- ipr.consentTitle = consentTitle;
2614
- ipr.consentMessage = consentMessage;
2615
- ipr.username = this.httprequest.realname;
2616
- ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2617
- pr = ipr.then(function (img) {
2618
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: 30000, translations: this.translations });
2619
- this.__childPromise.close = this.consent.close.bind(this.consent);
2620
- return (this.consent);
2621
- });
2622
- }
2623
- else {
2624
- pr = require('message-box').create(consentTitle, consentMessage, 30, null);
2625
- }
2626
- }
2627
- else {
2628
- pr = require('message-box').create(consentTitle, consentMessage, 30, null);
2629
- }
2630
- pr.ws = this;
2631
- this.pause();
2632
- this._consentpromise = pr;
2633
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2634
- pr.then(
2635
- function (always) {
2636
- if (always) { server_set_consentTimer(this.ws.httprequest.userid); }
2637
-
2638
- // Success
2639
- this.ws._consentpromise = null;
2640
- MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2641
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2642
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
2643
- // User Notifications is required
2644
- var notifyMessage = currentTranslation['fileNotify'].replace('{0}', this.ws.httprequest.realname);
2645
- var notifyTitle = "MeshCentral";
2646
- if (this.ws.httprequest.soptions != null) {
2647
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2648
- if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
2649
- }
2650
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2651
- }
2652
- this.ws.resume();
2653
- },
2654
- function (e) {
2655
- // User Consent Denied/Failed
2656
- this.ws._consentpromise = null;
2657
- MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2658
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2659
- });
2660
- }
2661
- else {
2662
- // User Consent Prompt is not required
2663
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
2664
- // User Notifications is required
2665
- MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2666
- var notifyMessage = currentTranslation['fileNotify'].replace('{0}', this.ws.httprequest.realname);
2667
- var notifyTitle = "MeshCentral";
2668
- if (this.httprequest.soptions != null) {
2669
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2670
- if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2671
- }
2672
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2673
- } else {
2674
- MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2675
- }
2676
- this.resume();
2677
- }
2678
-
2679
- // Setup files
2680
- // NOP
2681
- }
2682
- } else if (this.httprequest.protocol == 1) {
2683
- // Send data into terminal stdin
2684
- //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2685
- } else if (this.httprequest.protocol == 2) {
2686
- // Send data into remote desktop
2687
- if (this.httprequest.desktop.state == 0) {
2688
- this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2689
- this.httprequest.desktop.state = 1;
2690
- } else {
2691
- this.httprequest.desktop.write(data);
2692
- }
2693
- } else if (this.httprequest.protocol == 5) {
2694
- // Process files commands
2695
- var cmd = null;
2696
- try { cmd = JSON.parse(data); } catch (e) { };
2697
- if (cmd == null) { return; }
2698
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2699
- if (cmd.action == undefined) { return; }
2700
- //sendConsoleText('CMD: ' + JSON.stringify(cmd));
2701
-
2702
- if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2703
- //console.log(objToString(cmd, 0, ' '));
2704
- switch (cmd.action) {
2705
- case 'ls': {
2706
- /*
2707
- // Close the watcher if required
2708
- var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
2709
- if ((this.httprequest.watcher != undefined) && (samepath == false)) {
2710
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
2711
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
2712
- delete this.httprequest.watcher;
2713
- }
2714
- */
2715
-
2716
- // Send the folder content to the browser
2717
- var response = getDirectoryInfo(cmd.path);
2718
- response.reqid = cmd.reqid;
2719
- this.write(Buffer.from(JSON.stringify(response)));
2720
-
2721
- /*
2722
- // Start the directory watcher
2723
- if ((cmd.path != '') && (samepath == false)) {
2724
- var watcher = fs.watch(cmd.path, onFileWatcher);
2725
- watcher.tunnel = this.httprequest;
2726
- watcher.path = cmd.path;
2727
- this.httprequest.watcher = watcher;
2728
- //console.log('Starting watcher: ' + this.httprequest.watcher.path);
2729
- }
2730
- */
2731
- break;
2732
- }
2733
- case 'mkdir': {
2734
- // Create a new empty folder
2735
- fs.mkdirSync(cmd.path);
2736
- MeshServerLogEx(44, [cmd.path], "Create folder: \"" + cmd.path + "\"", this.httprequest);
2737
- break;
2738
- }
2739
- case 'rm': {
2740
- // Delete, possibly recursive delete
2741
- for (var i in cmd.delfiles) {
2742
- var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2743
- try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2744
- if ((delcount == 1) && !cmd.rec) {
2745
- MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2746
- } else {
2747
- if (cmd.rec) {
2748
- MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2749
- } else {
2750
- MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2751
- }
2752
- }
2753
- }
2754
- break;
2755
- }
2756
- case 'markcoredump': {
2757
- // If we are asking for the coredump file, set the right path.
2758
- var coreDumpPath = null;
2759
- if (process.platform == 'win32') {
2760
- if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2761
- } else {
2762
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2763
- }
2764
- if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
2765
- break;
2766
- }
2767
- case 'rename':
2768
- {
2769
- // Rename a file or folder
2770
- var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
2771
- var newfullpath = obj.path.join(cmd.path, cmd.newname);
2772
- MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
2773
- try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
2774
- break;
2775
- }
2776
- case 'findfile':
2777
- {
2778
- // Search for files
2779
- var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
2780
- if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
2781
- this._search = r;
2782
- r.socket = this;
2783
- r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
2784
- r.socket.path = cmd.path; // Search path
2785
- r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
2786
- r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
2787
- break;
2788
- }
2789
- case 'cancelfindfile':
2790
- {
2791
- if (this._search) { this._search.cancel(); this._search = null; }
2792
- break;
2793
- }
2794
- case 'download':
2795
- {
2796
- // Download a file
2797
- var sendNextBlock = 0;
2798
- if (cmd.sub == 'start') { // Setup the download
2799
- if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
2800
- if (process.platform == 'win32') {
2801
- if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2802
- } else {
2803
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2804
- }
2805
- }
2806
- MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
2807
- if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2808
- this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2809
- try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2810
- if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2811
- } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
2812
- if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
2813
- }
2814
- // Send the next download block(s)
2815
- while (sendNextBlock > 0) {
2816
- sendNextBlock--;
2817
- var buf = Buffer.alloc(16384);
2818
- var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
2819
- this.filedownload.ptr += len;
2820
- if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
2821
- this.write(buf.slice(0, len + 4)); // Write as binary
2822
- }
2823
- break;
2824
- }
2825
- case 'upload':
2826
- {
2827
- // Upload a file, browser to agent
2828
- if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
2829
- if (cmd.path == undefined) break;
2830
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2831
- this.httprequest.uploadFilePath = filepath;
2832
- this.httprequest.uploadFileSize = 0;
2833
- try { this.httprequest.uploadFile = fs.openSync(filepath, cmd.append ? 'abN' : 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
2834
- this.httprequest.uploadFileid = cmd.reqid;
2835
- if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
2836
- break;
2837
- }
2838
- case 'uploaddone':
2839
- {
2840
- // Indicates that an upload is done
2841
- if (this.httprequest.uploadFile) {
2842
- MeshServerLogEx(105, [this.httprequest.uploadFilePath, this.httprequest.uploadFileSize], 'Upload: \"' + this.httprequest.uploadFilePath + '\", Size: ' + this.httprequest.uploadFileSize, this.httprequest);
2843
- fs.closeSync(this.httprequest.uploadFile);
2844
- this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2845
- delete this.httprequest.uploadFile;
2846
- delete this.httprequest.uploadFileid;
2847
- delete this.httprequest.uploadFilePath;
2848
- delete this.httprequest.uploadFileSize;
2849
- }
2850
- break;
2851
- }
2852
- case 'uploadcancel':
2853
- {
2854
- // Indicates that an upload is canceled
2855
- if (this.httprequest.uploadFile) {
2856
- fs.closeSync(this.httprequest.uploadFile);
2857
- fs.unlinkSync(this.httprequest.uploadFilePath);
2858
- this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2859
- delete this.httprequest.uploadFile;
2860
- delete this.httprequest.uploadFileid;
2861
- delete this.httprequest.uploadFilePath;
2862
- delete this.httprequest.uploadFileSize;
2863
- }
2864
- break;
2865
- }
2866
- case 'uploadhash':
2867
- {
2868
- // Hash a file
2869
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2870
- var h = null;
2871
- try { h = getSHA384FileHash(filepath); } catch (ex) { sendConsoleText(ex); }
2872
- this.write(Buffer.from(JSON.stringify({ action: 'uploadhash', reqid: cmd.reqid, path: cmd.path, name: cmd.name, tag: cmd.tag, hash: (h ? h.toString('hex') : null) })));
2873
- break
2874
- }
2875
- case 'copy':
2876
- {
2877
- // Copy a bunch of files from scpath to dspath
2878
- for (var i in cmd.names) {
2879
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2880
- MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2881
- if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
2882
- }
2883
- break;
2884
- }
2885
- case 'move':
2886
- {
2887
- // Move a bunch of files from scpath to dspath
2888
- for (var i in cmd.names) {
2889
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2890
- MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2891
- if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
2892
- }
2893
- break;
2894
- }
2895
- case 'zip':
2896
- // Zip a bunch of files
2897
- if (this.zip != null) return; // Zip operating is currently running, exit now.
2898
-
2899
- // Check that the specified files exist & build full paths
2900
- var fp, stat, p = [];
2901
- for (var i in cmd.files) { fp = cmd.path + '/' + cmd.files[i]; stat = null; try { stat = fs.statSync(fp); } catch (e) { } if (stat != null) { p.push(fp); } }
2902
- if (p.length == 0) return; // No files, quit now.
2903
-
2904
- // Setup file compression
2905
- var ofile = cmd.path + '/' + cmd.output;
2906
- this.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zipping' })));
2907
- this.zipfile = ofile;
2908
- delete this.zipcancel;
2909
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2910
- out.xws = this;
2911
- out.on('close', function () {
2912
- this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2913
- this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2914
- if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
2915
- delete this.xws.zipcancel;
2916
- delete this.xws.zipfile;
2917
- delete this.xws.zip;
2918
- });
2919
- this.zip = require('zip-writer').write({ files: p, basePath: cmd.path });
2920
- this.zip.xws = this;
2921
- this.zip.on('progress', require('events').moderated(function (name, p) { this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zippingFile', file: ((process.platform == 'win32') ? (name.split('/').join('\\')) : name), progress: p }))); }, 1000));
2922
- this.zip.pipe(out);
2923
- break;
2924
- case 'cancel':
2925
- // Cancel zip operation if present
2926
- try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (e) { }
2927
- this.zip = null;
2928
- break;
2929
- default:
2930
- // Unknown action, ignore it.
2931
- break;
2932
- }
2933
- } else if (this.httprequest.protocol == 7) { // Plugin data exchange
2934
- var cmd = null;
2935
- try { cmd = JSON.parse(data); } catch (e) { };
2936
- if (cmd == null) { return; }
2937
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2938
- if (cmd.action == undefined) return;
2939
-
2940
- switch (cmd.action) {
2941
- case 'plugin': {
2942
- try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2943
- break;
2944
- }
2945
- default: {
2946
- // probably shouldn't happen, but just in case this feature is expanded
2947
- }
2948
- }
2949
-
2950
- }
2951
- //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
2952
- }
2953
-}
2954
-
2955
-// Delete a directory with a files and directories within it
2956
-function deleteFolderRecursive(path, rec) {
2957
- var count = 0;
2958
- if (fs.existsSync(path)) {
2959
- if (rec == true) {
2960
- fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
2961
- var curPath = obj.path.join(path, file);
2962
- if (fs.statSync(curPath).isDirectory()) { // recurse
2963
- count += deleteFolderRecursive(curPath, true);
2964
- } else { // delete file
2965
- fs.unlinkSync(curPath);
2966
- count++;
2967
- }
2968
- });
2969
- }
2970
- fs.unlinkSync(path);
2971
- count++;
2972
- }
2973
- return count;
2974
-}
2975
-
2976
-// Called when receiving control data on WebRTC
2977
-function onTunnelWebRTCControlData(data) {
2978
- if (typeof data != 'string') return;
2979
- var obj;
2980
- try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2981
- if (obj.type == 'close') {
2982
- //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2983
- try { this.close(); } catch (e) { }
2984
- try { this.xrtc.close(); } catch (e) { }
2985
- }
2986
-}
2987
-
2988
-// Called when receiving control data on websocket
2989
-function onTunnelControlData(data, ws) {
2990
- var obj;
2991
- if (ws == null) { ws = this; }
2992
- if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
2993
- else if (typeof data == 'object') { obj = data; } else { return; }
2994
- //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2995
- //console.log('onTunnelControlData: ' + JSON.stringify(data));
2996
-
2997
- switch (obj.type) {
2998
- case 'lock': {
2999
- // Look for a TSID
3000
- var tsid = null;
3001
- if ((ws.httprequest.xoptions != null) && (typeof ws.httprequest.xoptions.tsid == 'number')) { tsid = ws.httprequest.xoptions.tsid; }
3002
-
3003
- // Lock the current user out of the desktop
3004
- MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
3005
- lockDesktop(tsid);
3006
- break;
3007
- }
3008
- case 'autolock': {
3009
- // Set the session to auto lock on disconnect
3010
- if (obj.value === true) {
3011
- ws.httprequest.autolock = true;
3012
- if (ws.httprequest.unlockerHelper == null) {
3013
- destopLockHelper_pipe(ws.httprequest);
3014
- }
3015
- }
3016
- else {
3017
- delete ws.httprequest.autolock;
3018
- }
3019
- break;
3020
- }
3021
- case 'options': {
3022
- // These are additional connection options passed in the control channel.
3023
- //sendConsoleText('options: ' + JSON.stringify(obj));
3024
- delete obj.type;
3025
- ws.httprequest.xoptions = obj;
3026
-
3027
- // Set additional user consent options if present
3028
- if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
3029
-
3030
- // Set autolock
3031
- if ((obj != null) && (obj.autolock === true)) {
3032
- ws.httprequest.autolock = true;
3033
- if (ws.httprequest.unlockerHelper == null) {
3034
- destopLockHelper_pipe(ws.httprequest);
3035
- }
3036
- }
3037
-
3038
- break;
3039
- }
3040
- case 'close': {
3041
- // We received the close on the websocket
3042
- //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
3043
- try { ws.close(); } catch (e) { }
3044
- break;
3045
- }
3046
- case 'termsize': {
3047
- // Indicates a change in terminal size
3048
- if (process.platform == 'win32') {
3049
- if (ws.httprequest._dispatcher == null) return;
3050
- //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
3051
- if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
3052
- } else {
3053
- if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
3054
- //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
3055
-
3056
- if (ws.httprequest.process.tcsetsize) { ws.httprequest.process.tcsetsize(obj.rows, obj.cols); }
3057
- }
3058
- break;
3059
- }
3060
- case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
3061
- if (ws.httprequest.protocol == 1) { // Terminal
3062
- // This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
3063
- if (process.platform == 'win32') {
3064
- ws.httprequest._term.unpipe(ws);
3065
- } else {
3066
- ws.httprequest.process.stdout.unpipe(ws);
3067
- ws.httprequest.process.stderr.unpipe(ws);
3068
- }
3069
- } else if (ws.httprequest.protocol == 2) { // Desktop
3070
- // This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
3071
- ws.httprequest.desktop.kvm.unpipe(ws);
3072
- } else {
3073
- // Switch things around so all WebRTC data goes to onTunnelData().
3074
- ws.rtcchannel.httprequest = ws.httprequest;
3075
- ws.rtcchannel.removeAllListeners('data');
3076
- ws.rtcchannel.on('data', onTunnelData);
3077
- }
3078
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // End of data marker
3079
- break;
3080
- }
3081
- case 'webrtc1': {
3082
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
3083
- // Switch the user input from websocket to webrtc at this point.
3084
- if (process.platform == 'win32') {
3085
- ws.unpipe(ws.httprequest._term);
3086
- ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
3087
- } else {
3088
- ws.unpipe(ws.httprequest.process.stdin);
3089
- ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
3090
- }
3091
- ws.resume(); // Resume the websocket to keep receiving control data
3092
- } else if (ws.httprequest.protocol == 2) { // Desktop
3093
- // Switch the user input from websocket to webrtc at this point.
3094
- ws.unpipe(ws.httprequest.desktop.kvm);
3095
- try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
3096
- ws.resume(); // Resume the websocket to keep receiving control data
3097
- }
3098
- ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
3099
- break;
3100
- }
3101
- case 'webrtc2': {
3102
- // Other side received websocket end of data marker, start sending data on WebRTC channel
3103
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
3104
- if (process.platform == 'win32') {
3105
- ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
3106
- } else {
3107
- ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
3108
- ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
3109
- }
3110
- } else if (ws.httprequest.protocol == 2) { // Desktop
3111
- ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
3112
- }
3113
- break;
3114
- }
3115
- case 'offer': {
3116
- // This is a WebRTC offer.
3117
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) return; // TODO: Terminal is currently broken with WebRTC. Reject WebRTC upgrade for now.
3118
- ws.webrtc = rtc.createConnection();
3119
- ws.webrtc.websocket = ws;
3120
- ws.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
3121
- ws.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
3122
- ws.webrtc.on('dataChannel', function (rtcchannel) {
3123
- //sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
3124
- //rtcchannel.maxFragmentSize = 32768;
3125
- rtcchannel.xrtc = this;
3126
- rtcchannel.websocket = this.websocket;
3127
- this.rtcchannel = rtcchannel;
3128
- this.websocket.rtcchannel = rtcchannel;
3129
- this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
3130
- this.websocket.rtcchannel.on('end', function () {
3131
- // The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes.
3132
- //sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');
3133
- if (this.websocket.desktop && this.websocket.desktop.kvm) {
3134
- try {
3135
- this.unpipe(this.websocket.desktop.kvm);
3136
- this.websocket.httprequest.desktop.kvm.unpipe(this);
3137
- }
3138
- catch (e) { }
3139
- }
3140
- });
3141
- this.websocket.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc0\"}'); // Indicate we are ready for WebRTC switch-over.
3142
- });
3143
- var sdp = null;
3144
- try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (e) { }
3145
- if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
3146
- break;
3147
- }
3148
- case 'ping': {
3149
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"pong\"}"); // Send pong response
3150
- break;
3151
- }
3152
- case 'pong': { // NOP
3153
- break;
3154
- }
3155
- case 'rtt': {
3156
- ws.write({ type: 'rtt', ctrlChannel: '102938', time: obj.time });
3157
- break;
3158
- }
3159
- }
3160
-}
3161
-
3162
-// Console state
3163
-var consoleWebSockets = {};
3164
-var consoleHttpRequest = null;
3165
-
3166
-// Console HTTP response
3167
-function consoleHttpResponse(response) {
3168
- response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
3169
- response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; }
3170
-}
3171
-
3172
-// Open a web browser to a specified URL on current user's desktop
3173
-function openUserDesktopUrl(url) {
3174
- if ((url.toLowerCase().startsWith('http://') == false) && (url.toLowerCase().startsWith('https://') == false)) { return null; }
3175
- var child = null;
3176
- try {
3177
- switch (process.platform) {
3178
- case 'win32':
3179
- var uid = require('user-sessions').consoleUid();
3180
- var user = require('user-sessions').getUsername(uid);
3181
- var domain = require('user-sessions').getDomain(uid);
3182
- var taskoptions = { env: { _target: process.env['windir'] + '\\system32\\cmd.exe', _args: '/C START ' + url.split('&').join('^&'), _user: '"' + domain + '\\' + user + '"' } };
3183
- for (var c1e in process.env) {
3184
- taskoptions.env[c1e] = process.env[c1e];
3185
- }
3186
- var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], taskoptions);
3187
- child.stderr.on('data', function (c) { });
3188
- child.stdout.on('data', function (c) { });
3189
- child.stdin.write('SCHTASKS /CREATE /F /TN MeshChatTask /SC ONCE /ST 00:00 ');
3190
- if (user) { child.stdin.write('/RU $env:_user '); }
3191
- child.stdin.write('/TR "$env:_target $env:_args"\r\n');
3192
- child.stdin.write('$ts = New-Object -ComObject Schedule.service\r\n');
3193
- child.stdin.write('$ts.connect()\r\n');
3194
- child.stdin.write('$tsfolder = $ts.getfolder("\\")\r\n');
3195
- child.stdin.write('$task = $tsfolder.GetTask("MeshChatTask")\r\n');
3196
- child.stdin.write('$taskdef = $task.Definition\r\n');
3197
- child.stdin.write('$taskdef.Settings.StopIfGoingOnBatteries = $false\r\n');
3198
- child.stdin.write('$taskdef.Settings.DisallowStartIfOnBatteries = $false\r\n');
3199
- child.stdin.write('$taskdef.Actions.Item(1).Path = $env:_target\r\n');
3200
- child.stdin.write('$taskdef.Actions.Item(1).Arguments = $env:_args\r\n');
3201
- child.stdin.write('$tsfolder.RegisterTaskDefinition($task.Name, $taskdef, 4, $null, $null, $null)\r\n');
3202
-
3203
- child.stdin.write('SCHTASKS /RUN /TN MeshChatTask\r\n');
3204
- child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\nexit\r\n');
3205
- child.waitExit();
3206
- break;
3207
- case 'linux':
3208
- child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { uid: require('user-sessions').consoleUid() });
3209
- break;
3210
- case 'darwin':
3211
- child = require('child_process').execFile('/usr/bin/open', ['open', url], { uid: require('user-sessions').consoleUid() });
3212
- break;
3213
- default:
3214
- // Unknown platform, ignore this command.
3215
- break;
3216
- }
3217
- } catch (e) { }
3218
- return child;
3219
-}
3220
-
3221
-// Process a mesh agent console command
3222
-function processConsoleCommand(cmd, args, rights, sessionid) {
3223
- try {
3224
- var response = null;
3225
- switch (cmd) {
3226
- case 'help': { // Displays available commands
3227
- var fin = '', f = '', availcommands = 'translations,agentupdate,errorlog,msh,timerinfo,coreinfo,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,wslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg,task';
3228
- if (require('os').dns != null) { availcommands += ',dnsinfo'; }
3229
- try { require('linux-dhcp'); availcommands += ',dhcp'; } catch (e) { }
3230
- if (process.platform == 'win32') { availcommands += ',cs,safemode,wpfhwacceleration,uac'; }
3231
- if (amt != null) { availcommands += ',amt,amtconfig,amtevents'; }
3232
- if (process.platform != 'freebsd') { availcommands += ',vm'; }
3233
- if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
3234
- try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { }
3235
-
3236
- availcommands = availcommands.split(',').sort();
3237
- while (availcommands.length > 0) {
3238
- if (f.length > 90) { fin += (f + ',\r\n'); f = ''; }
3239
- f += (((f != '') ? ', ' : ' ') + availcommands.shift());
3240
- }
3241
- if (f != '') { fin += f; }
3242
- response = "Available commands: \r\n" + fin + ".";
3243
- break;
3244
- }
3245
- case 'translations': {
3246
- response = JSON.stringify(coretranslations, null, 2);
3247
- break;
3248
- }
3249
- case 'dhcp': // This command is only supported on Linux, this is because Linux does not give us the DNS suffix for each network adapter independently so we have to ask the DHCP server.
3250
- {
3251
- try { require('linux-dhcp'); } catch (e) { response = 'Unknown command "dhcp", type "help" for list of avaialble commands.'; break; }
3252
- if (args['_'].length == 0) {
3253
- var j = require('os').networkInterfaces();
3254
- var ifcs = [];
3255
- for (var i in j) {
3256
- for (var z in j[i]) {
3257
- if (j[i][z].status == 'up' && j[i][z].type != 'loopback' && j[i][z].address != null) {
3258
- ifcs.push('"' + i + '"');
3259
- break;
3260
- }
3261
- }
3262
- }
3263
- response = 'Proper usage: dhcp [' + ifcs.join(' | ') + ']';
3264
- }
3265
- else {
3266
- require('linux-dhcp').client.info(args['_'][0]).
3267
- then(function (d) {
3268
- sendConsoleText(JSON.stringify(d, null, 1), sessionid);
3269
- },
3270
- function (e) {
3271
- sendConsoleText(e, sessionid);
3272
- });
3273
- }
3274
- break;
3275
- }
3276
- case 'cs':
3277
- if (process.platform != 'win32') {
3278
- response = 'Unknown command "cs", type "help" for list of avaialble commands.';
3279
- break;
3280
- }
3281
- switch (args['_'].length) {
3282
- case 0:
3283
- try {
3284
- var cs = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Power', 'CsEnabled');
3285
- response = "Connected Standby: " + (cs == 1 ? "ENABLED" : "DISABLED");
3286
- }
3287
- catch (e) {
3288
- response = "This machine does not support Connected Standby";
3289
- }
3290
- break;
3291
- case 1:
3292
- if ((args['_'][0].toUpperCase() != 'ENABLE' && args['_'][0].toUpperCase() != 'DISABLE')) {
3293
- response = "Proper usage:\r\n cs [ENABLE|DISABLE]";
3294
- }
3295
- else {
3296
- try {
3297
- var cs = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Power', 'CsEnabled');
3298
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Power', 'CsEnabled', args['_'][0].toUpperCase() == 'ENABLE' ? 1 : 0);
3299
-
3300
- cs = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Power', 'CsEnabled');
3301
- response = "Connected Standby: " + (cs == 1 ? "ENABLED" : "DISABLED");
3302
- }
3303
- catch (e) {
3304
- response = "This machine does not support Connected Standby";
3305
- }
3306
- }
3307
- break;
3308
- default:
3309
- response = "Proper usage:\r\n cs [ENABLE|DISABLE]";
3310
- break;
3311
- }
3312
- break;
3313
- case 'assistant':
3314
- if (process.platform == 'win32') {
3315
- // Install MeshCentral Assistant on this device
3316
- response = "Usage: Assistant [info|install|uninstall]";
3317
- if (args['_'].length == 1) {
3318
- if ((args['_'][0] == 'install') || (args['_'][0] == 'info')) { response = ''; require('MeshAgent').SendCommand({ action: 'meshToolInfo', sessionid: sessionid, name: 'MeshCentralAssistant', cookie: true, tag: args['_'][0] }); }
3319
- // TODO: Uninstall
3320
- }
3321
- } else {
3322
- response = "MeshCentral Assistant is not supported on this platform.";
3323
- }
3324
- break;
3325
- case 'userimage':
3326
- require('MeshAgent').SendCommand({ action: 'getUserImage', sessionid: sessionid, userid: args['_'][0], tag: 'info' });
3327
- response = 'ok';
3328
- break;
3329
- case 'agentupdate':
3330
- require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid });
3331
- break;
3332
- case 'agentupdateex':
3333
- // Perform an direct agent update without requesting any information from the server, this should not typically be used.
3334
- if (args['_'].length == 1) {
3335
- if (args['_'][0].startsWith('https://')) { agentUpdate_Start(args['_'][0], { sessionid: sessionid }); } else { response = "Usage: agentupdateex https://server/path"; }
3336
- } else {
3337
- agentUpdate_Start(null, { sessionid: sessionid });
3338
- }
3339
- break;
3340
- case 'errorlog':
3341
- switch (args['_'].length) {
3342
- case 0:
3343
- // All Error Logs
3344
- response = JSON.stringify(require('util-agentlog').read(), null, 1);
3345
- break;
3346
- case 1:
3347
- // Error Logs, by either count or timestamp
3348
- response = JSON.stringify(require('util-agentlog').read(parseInt(args['_'][0])), null, 1);
3349
- break;
3350
- default:
3351
- response = "Proper usage:\r\n errorlog [lastCount|linuxEpoch]";
3352
- break;
3353
- }
3354
- break;
3355
- case 'msh':
3356
- response = JSON.stringify(_MSH(), null, 2);
3357
- break;
3358
- case 'dnsinfo':
3359
- if (require('os').dns == null) {
3360
- response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands.";
3361
- }
3362
- else {
3363
- response = 'DNS Servers: ';
3364
- var dns = require('os').dns();
3365
- for (var i = 0; i < dns.length; ++i) {
3366
- if (i > 0) { response += ', '; }
3367
- response += dns[i];
3368
- }
3369
- }
3370
- break;
3371
- case 'timerinfo':
3372
- response = require('ChainViewer').getTimerInfo();
3373
- break;
3374
- case 'find':
3375
- if (args['_'].length <= 1) {
3376
- response = "Proper usage:\r\n find root criteria [criteria2] [criteria n...]";
3377
- }
3378
- else {
3379
- var root = args['_'][0];
3380
- var p = args['_'].slice(1);
3381
- var r = require('file-search').find(root, p);
3382
- r.sid = sessionid;
3383
- r.on('result', function (str) { sendConsoleText(str, this.sid); });
3384
- r.then(function () { sendConsoleText('*** End Results ***', this.sid); });
3385
- response = "Find: [" + root + "] " + JSON.stringify(p);
3386
- }
3387
- break;
3388
- case 'coreinfo': {
3389
- response = JSON.stringify(meshCoreObj, null, 2);
3390
- break;
3391
- }
3392
- case 'coreinfoupdate': {
3393
- sendPeriodicServerUpdate();
3394
- break;
3395
- }
3396
- case 'agentmsg': {
3397
- if (args['_'].length == 0) {
3398
- response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage
3399
- } else {
3400
- if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
3401
- var msgID, iconIndex = 0;
3402
- if (args['_'].length >= 3) { try { iconIndex = parseInt(args['_'][2]); } catch (e) { } }
3403
- if (typeof iconIndex != 'number') { iconIndex = 0; }
3404
- msgID = sendAgentMessage(args['_'][1], iconIndex);
3405
- response = 'Agent message: ' + msgID + ' added.';
3406
- } else if ((args['_'][0] == 'remove') && (args['_'].length > 1)) {
3407
- var r = removeAgentMessage(args['_'][1]);
3408
- response = 'Message ' + (r ? 'removed' : 'NOT FOUND');
3409
- } else if (args['_'][0] == 'list') {
3410
- response = JSON.stringify(sendAgentMessage(), null, 2);
3411
- }
3412
- broadcastSessionsToRegisteredApps();
3413
- }
3414
- break;
3415
- }
3416
- case 'clearagentmsg': {
3417
- removeAgentMessage();
3418
- broadcastSessionsToRegisteredApps();
3419
- break;
3420
- }
3421
- case 'coredump':
3422
- if (args['_'].length != 1) {
3423
- response = "Proper usage: coredump on|off|status|clear"; // Display usage
3424
- } else {
3425
- switch (args['_'][0].toLowerCase()) {
3426
- case 'on':
3427
- process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
3428
- response = 'coredump is now on';
3429
- break;
3430
- case 'off':
3431
- process.coreDumpLocation = null;
3432
- response = 'coredump is now off';
3433
- break;
3434
- case 'status':
3435
- response = 'coredump is: ' + ((process.coreDumpLocation == null) ? 'off' : 'on');
3436
- if (process.coreDumpLocation != null) {
3437
- if (process.platform == 'win32') {
3438
- if (fs.existsSync(process.coreDumpLocation)) {
3439
- response += '\r\n CoreDump present at: ' + process.coreDumpLocation;
3440
- response += '\r\n CoreDump Time: ' + new Date(fs.statSync(process.coreDumpLocation).mtime).getTime();
3441
- response += '\r\n Agent Time : ' + new Date(fs.statSync(process.execPath).mtime).getTime();
3442
- }
3443
- } else {
3444
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) {
3445
- response += '\r\n CoreDump present at: ' + process.cwd() + 'core';
3446
- response += '\r\n CoreDump Time: ' + new Date(fs.statSync(process.cwd() + 'core').mtime).getTime();
3447
- response += '\r\n Agent Time : ' + new Date(fs.statSync(process.execPath).mtime).getTime();
3448
- }
3449
- }
3450
- }
3451
- break;
3452
- case 'clear':
3453
- db.Put('CoreDumpTime', null);
3454
- response = 'coredump db cleared';
3455
- break;
3456
- default:
3457
- response = "Proper usage: coredump on|off|status"; // Display usage
3458
- break;
3459
- }
3460
- }
3461
- break;
3462
- case 'service':
3463
- if (args['_'].length != 1) {
3464
- response = "Proper usage: service status|restart"; // Display usage
3465
- }
3466
- else {
3467
- var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3468
- try {
3469
- svcname = require('MeshAgent').serviceName;
3470
- }
3471
- catch (x) {
3472
- }
3473
- var s = require('service-manager').manager.getService(svcname);
3474
- switch (args['_'][0].toLowerCase()) {
3475
- case 'status':
3476
- response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]'));
3477
- break;
3478
- case 'restart':
3479
- if (s.isMe()) {
3480
- s.restart();
3481
- }
3482
- else {
3483
- response = 'Restarting another agent instance is not allowed';
3484
- }
3485
- break;
3486
- default:
3487
- response = "Proper usage: service status|restart"; // Display usage
3488
- break;
3489
- }
3490
- if (process.platform == 'win32') { s.close(); }
3491
- }
3492
- break;
3493
- case 'zip':
3494
- if (args['_'].length == 0) {
3495
- response = "Proper usage: zip (output file name), input1 [, input n]"; // Display usage
3496
- } else {
3497
- var p = args['_'].join(' ').split(',');
3498
- var ofile = p.shift();
3499
- sendConsoleText('Writing ' + ofile + '...');
3500
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
3501
- out.fname = ofile;
3502
- out.sessionid = sessionid;
3503
- out.on('close', function () { sendConsoleText('DONE writing ' + this.fname, this.sessionid); });
3504
- var zip = require('zip-writer').write({ files: p });
3505
- zip.pipe(out);
3506
- }
3507
- break;
3508
- case 'unzip':
3509
- if (args['_'].length == 0) {
3510
- response = "Proper usage: unzip input, destination"; // Display usage
3511
- } else {
3512
- var p = args['_'].join(' ').split(',');
3513
- if (p.length != 2) { response = "Proper usage: unzip input, destination"; break; } // Display usage
3514
- var prom = require('zip-reader').read(p[0]);
3515
- prom._dest = p[1];
3516
- prom.self = this;
3517
- prom.sessionid = sessionid;
3518
- prom.then(function (zipped) {
3519
- sendConsoleText('Extracting to ' + this._dest + '...', this.sessionid);
3520
- zipped.extractAll(this._dest).then(function () { sendConsoleText('finished unzipping', this.sessionid); }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); }).parentPromise.sessionid = this.sessionid;
3521
- }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); });
3522
- }
3523
- break;
3524
- case 'setbattery':
3525
- // require('MeshAgent').SendCommand({ action: 'battery', state: 'dc', level: 55 });
3526
- if ((args['_'].length > 0) && ((args['_'][0] == 'ac') || (args['_'][0] == 'dc'))) {
3527
- var b = { action: 'battery', state: args['_'][0] };
3528
- if (args['_'].length == 2) { b.level = parseInt(args['_'][1]); }
3529
- require('MeshAgent').SendCommand(b);
3530
- } else {
3531
- require('MeshAgent').SendCommand({ action: 'battery' });
3532
- }
3533
- break;
3534
- case 'fdsnapshot':
3535
- require('ChainViewer').getSnapshot().then(function (c) { sendConsoleText(c, this.sessionid); }).parentPromise.sessionid = sessionid;
3536
- break;
3537
- case 'fdcount':
3538
- require('DescriptorEvents').getDescriptorCount().then(
3539
- function (c) {
3540
- sendConsoleText('Descriptor Count: ' + c, this.sessionid);
3541
- }, function (e) {
3542
- sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid);
3543
- }).parentPromise.sessionid = sessionid;
3544
- break;
3545
- case 'uac':
3546
- if (process.platform != 'win32') {
3547
- response = 'Unknown command "uac", type "help" for list of avaialble commands.';
3548
- break;
3549
- }
3550
- if (args['_'].length != 1) {
3551
- response = 'Proper usage: uac [get|interactive|secure]';
3552
- }
3553
- else {
3554
- switch (args['_'][0].toUpperCase()) {
3555
- case 'GET':
3556
- var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop');
3557
- response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop");
3558
- break;
3559
- case 'INTERACTIVE':
3560
- try {
3561
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0);
3562
- response = 'UAC mode changed to: Interactive Desktop';
3563
- }
3564
- catch (e) {
3565
- response = "Unable to change UAC Mode";
3566
- }
3567
- break;
3568
- case 'SECURE':
3569
- try {
3570
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1);
3571
- response = 'UAC mode changed to: Secure Desktop';
3572
- }
3573
- catch (e) {
3574
- response = "Unable to change UAC Mode";
3575
- }
3576
- break;
3577
- default:
3578
- response = 'Proper usage: uac [get|interactive|secure]';
3579
- break;
3580
- }
3581
- }
3582
- break;
3583
- case 'vm':
3584
- response = 'Virtual Machine = ' + require('identifiers').isVM();
3585
- break;
3586
- case 'startupoptions':
3587
- response = JSON.stringify(require('MeshAgent').getStartupOptions());
3588
- break;
3589
- case 'kvmmode':
3590
- if (require('MeshAgent').maxKvmTileSize == null) {
3591
- response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands.";
3592
- }
3593
- else {
3594
- if (require('MeshAgent').maxKvmTileSize == 0) {
3595
- response = 'KVM Mode: Full JUMBO';
3596
- }
3597
- else {
3598
- response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO');
3599
- response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize / 1024) + ' Kbytes')));
3600
- }
3601
- }
3602
- break;
3603
- case 'alert':
3604
- if (args['_'].length == 0) {
3605
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
3606
- }
3607
- else {
3608
- var p = args['_'].join(' ').split(',');
3609
- if (p.length < 2) {
3610
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
3611
- }
3612
- else {
3613
- this._alert = require('message-box').create(p[0], p[1], p.length == 3 ? parseInt(p[2]) : 9999, 1);
3614
- }
3615
- }
3616
- break;
3617
- case 'agentsize':
3618
- var actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
3619
- if (process.platform == 'win32') {
3620
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
3621
- var writtenSize = 0;
3622
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { response = e; }
3623
- if (writtenSize != actualSize) {
3624
- response = "Size updated from: " + writtenSize + " to: " + actualSize;
3625
- try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { response = e; }
3626
- } else
3627
- { response = "Agent Size: " + actualSize + " kb"; }
3628
- } else
3629
- { response = "Agent Size: " + actualSize + " kb"; }
3630
- break;
3631
- case 'versions':
3632
- response = JSON.stringify(process.versions, null, ' ');
3633
- break;
3634
- case 'wpfhwacceleration':
3635
- if (process.platform != 'win32') { throw ("wpfhwacceleration setting is only supported on Windows"); }
3636
- if (args['_'].length != 1) {
3637
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS)"; // Display usage
3638
- }
3639
- else {
3640
- var reg = require('win-registry');
3641
- var uname = require('user-sessions').getUsername(require('user-sessions').consoleUid());
3642
- var key = reg.usernameToUserKey(uname);
3643
-
3644
- switch (args['_'][0].toUpperCase()) {
3645
- default:
3646
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS|DEFAULT)"; // Display usage
3647
- break;
3648
- case 'ON':
3649
- try {
3650
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 0);
3651
- response = "OK";
3652
- } catch (e) { response = "FAILED"; }
3653
- break;
3654
- case 'OFF':
3655
- try {
3656
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 1);
3657
- response = 'OK';
3658
- } catch (e) { response = 'FAILED'; }
3659
- break;
3660
- case 'STATUS':
3661
- var s;
3662
- try { s = reg.QueryKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration') == 1 ? 'DISABLED' : 'ENABLED'; } catch (e) { s = 'DEFAULT'; }
3663
- response = "WPF Hardware Acceleration: " + s;
3664
- break;
3665
- case 'DEFAULT':
3666
- try { reg.DeleteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration'); } catch (e) { }
3667
- response = 'OK';
3668
- break;
3669
- }
3670
- }
3671
- break;
3672
- case 'tsid':
3673
- if (process.platform == 'win32') {
3674
- if (args['_'].length != 1) {
3675
- response = "TSID: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
3676
- } else {
3677
- var i = parseInt(args['_'][0]);
3678
- require('MeshAgent')._tsid = (isNaN(i) ? null : i);
3679
- response = "TSID set to: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
3680
- }
3681
- } else
3682
- { response = "TSID command only supported on Windows"; }
3683
- break;
3684
- case 'activeusers':
3685
- if (process.platform == 'win32') {
3686
- var p = require('user-sessions').enumerateUsers();
3687
- p.sessionid = sessionid;
3688
- p.then(function (u) {
3689
- var v = [];
3690
- for (var i in u) {
3691
- if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3692
- }
3693
- sendConsoleText(JSON.stringify(v, null, 1), this.sessionid);
3694
- });
3695
- } else
3696
- { response = "activeusers command only supported on Windows"; }
3697
- break;
3698
- case 'wallpaper':
3699
- if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available)) {
3700
- response = "wallpaper command not supported on this platform";
3701
- }
3702
- else {
3703
- if (args['_'].length != 1) {
3704
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
3705
- }
3706
- else {
3707
- switch (args['_'][0].toUpperCase()) {
3708
- default:
3709
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
3710
- break;
3711
- case 'GET':
3712
- case 'TOGGLE':
3713
- if (process.platform == 'win32') {
3714
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
3715
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: id });
3716
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3717
- child.stderr.on('data', function () { });
3718
- child.waitExit();
3719
- var current = child.stdout.str.trim();
3720
- if (args['_'][0].toUpperCase() == 'GET') {
3721
- response = current;
3722
- break;
3723
- }
3724
- if (current != '') {
3725
- require('MeshAgent')._wallpaper = current;
3726
- response = 'Wallpaper cleared';
3727
- } else {
3728
- response = 'Wallpaper restored';
3729
- }
3730
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: id });
3731
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3732
- child.stderr.on('data', function () { });
3733
- child.waitExit();
3734
- }
3735
- else {
3736
- var id = require('user-sessions').consoleUid();
3737
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
3738
- if (args['_'][0].toUpperCase() == 'GET') {
3739
- response = current;
3740
- break;
3741
- }
3742
- if (current != '/dev/null') {
3743
- require('MeshAgent')._wallpaper = current;
3744
- response = 'Wallpaper cleared';
3745
- } else {
3746
- response = 'Wallpaper restored';
3747
- }
3748
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
3749
- }
3750
- break;
3751
- }
3752
- }
3753
- }
3754
- break;
3755
- case 'safemode':
3756
- if (process.platform != 'win32') {
3757
- response = 'safemode only supported on Windows Platforms'
3758
- }
3759
- else {
3760
- if (args['_'].length != 1) {
3761
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
3762
- }
3763
- else {
3764
- var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3765
- try {
3766
- svcname = require('MeshAgent').serviceName;
3767
- }
3768
- catch (x) {
3769
- }
3770
-
3771
- switch (args['_'][0].toUpperCase()) {
3772
- default:
3773
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
3774
- break;
3775
- case 'ON':
3776
- require('win-bcd').setKey('safeboot', 'Network');
3777
- require('win-bcd').enableSafeModeService(svcname);
3778
- break;
3779
- case 'OFF':
3780
- require('win-bcd').deleteKey('safeboot');
3781
- break;
3782
- case 'STATUS':
3783
- var nextboot = require('win-bcd').getKey('safeboot');
3784
- if (nextboot) {
3785
- switch (nextboot) {
3786
- case 'Network':
3787
- case 'network':
3788
- nextboot = 'SAFE_MODE_NETWORK';
3789
- break;
3790
- default:
3791
- nextboot = 'SAFE_MODE';
3792
- break;
3793
- }
3794
- }
3795
- response = 'Current: ' + require('win-bcd').bootMode + ', NextBoot: ' + (nextboot ? nextboot : 'NORMAL');
3796
- break;
3797
- }
3798
- }
3799
- }
3800
- break;
3801
- /*
3802
- case 'border':
3803
- {
3804
- if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
3805
- if (meshCoreObj.users.length > 0) {
3806
- obj.borderManager.Start(meshCoreObj.users[0]);
3807
- response = 'Border blinking is on.';
3808
- } else {
3809
- response = 'Cannot turn on border blinking, no logged in users.';
3810
- }
3811
- } else if ((args['_'].length == 1) && (args['_'][0] == 'off')) {
3812
- obj.borderManager.Stop();
3813
- response = 'Border blinking is off.';
3814
- } else {
3815
- response = 'Proper usage: border "on|off"'; // Display correct command usage
3816
- }
3817
- }
3818
- break;
3819
- */
3820
- case 'av':
3821
- if (process.platform == 'win32') {
3822
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3823
- response = JSON.stringify(require('win-info').av(), null, 1);
3824
- } else {
3825
- response = 'Not supported on the platform';
3826
- }
3827
- break;
3828
- case 'log':
3829
- if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
3830
- break;
3831
- case 'getclip':
3832
- if (require('MeshAgent').isService) {
3833
- require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });
3834
- } else {
3835
- require("clipboard").read().then(function (str) { sendConsoleText(str, sessionid); });
3836
- }
3837
- break;
3838
- case 'setclip': {
3839
- if (args['_'].length != 1) {
3840
- response = 'Proper usage: setclip "sample text"';
3841
- } else {
3842
- if (require('MeshAgent').isService) {
3843
- if (process.platform != 'win32') {
3844
- require('clipboard').dispatchWrite(args['_'][0]);
3845
- }
3846
- else {
3847
- var clipargs = args['_'][0];
3848
- var uid = require('user-sessions').consoleUid();
3849
- var user = require('user-sessions').getUsername(uid);
3850
- var domain = require('user-sessions').getDomain(uid);
3851
- user = (domain + '\\' + user);
3852
-
3853
- this._dispatcher = require('win-dispatcher').dispatch({ user: user, modules: [{ name: 'clip-dispatch', script: "module.exports = { dispatch: function dispatch(val) { require('clipboard')(val); process.exit(); } };" }], launch: { module: 'clip-dispatch', method: 'dispatch', args: [clipargs] } });
3854
- this._dispatcher.parent = this;
3855
- //require('events').setFinalizerMetadata.call(this._dispatcher, 'clip-dispatch');
3856
- this._dispatcher.on('connection', function (c) {
3857
- this._c = c;
3858
- this._c.root = this.parent;
3859
- this._c.on('end', function () {
3860
- this.root._dispatcher = null;
3861
- this.root = null;
3862
- });
3863
- });
3864
- }
3865
- response = 'Setting clipboard to: "' + args['_'][0] + '"';
3866
- }
3867
- else {
3868
- require("clipboard")(args['_'][0]); response = 'Setting clipboard to: "' + args['_'][0] + '"';
3869
- }
3870
- }
3871
- break;
3872
- }
3873
- case 'openurl': {
3874
- if (args['_'].length != 1) { response = 'Proper usage: openurl (url)'; } // Display usage
3875
- else { if (openUserDesktopUrl(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } }
3876
- break;
3877
- }
3878
- case 'users': {
3879
- if (meshCoreObj.users == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + meshCoreObj.users.join(', ') + '.'; }
3880
- require('user-sessions').enumerateUsers().then(function (u) { for (var i in u) { sendConsoleText(u[i]); } });
3881
- break;
3882
- }
3883
- case 'toast': {
3884
- if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
3885
- if (require('MeshAgent')._tsid == null) {
3886
- require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
3887
- }
3888
- else {
3889
- require('toaster').Toast('MeshCentral', args['_'][0], require('MeshAgent')._tsid).then(sendConsoleText, sendConsoleText);
3890
- }
3891
- }
3892
- break;
3893
- }
3894
- case 'setdebug': {
3895
- if (args['_'].length < 1) { response = 'Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile'; } // Display usage
3896
- else { if (args['_'][0] == '*') { console.setDestination(2); } else { console.setDestination(parseInt(args['_'][0]), sessionid); } }
3897
- break;
3898
- }
3899
- case 'ps': {
3900
- processManager.getProcesses(function (plist) {
3901
- var x = '';
3902
- for (var i in plist) { x += i + ((plist[i].user) ? (', ' + plist[i].user) : '') + ', ' + plist[i].cmd + '\r\n'; }
3903
- sendConsoleText(x, sessionid);
3904
- });
3905
- break;
3906
- }
3907
- case 'kill': {
3908
- if ((args['_'].length < 1)) {
3909
- response = 'Proper usage: kill [pid]'; // Display correct command usage
3910
- } else {
3911
- process.kill(parseInt(args['_'][0]));
3912
- response = 'Killed process ' + args['_'][0] + '.';
3913
- }
3914
- break;
3915
- }
3916
- case 'smbios': {
3917
- if (SMBiosTables == null) { response = 'SMBios tables not available.'; } else { response = objToString(SMBiosTables, 0, ' ', true); }
3918
- break;
3919
- }
3920
- case 'rawsmbios': {
3921
- if (SMBiosTablesRaw == null) { response = 'SMBios tables not available.'; } else {
3922
- response = '';
3923
- for (var i in SMBiosTablesRaw) {
3924
- var header = false;
3925
- for (var j in SMBiosTablesRaw[i]) {
3926
- if (SMBiosTablesRaw[i][j].length > 0) {
3927
- if (header == false) { response += ('Table type #' + i + ((require('smbios').smTableTypes[i] == null) ? '' : (', ' + require('smbios').smTableTypes[i]))) + '\r\n'; header = true; }
3928
- response += (' ' + SMBiosTablesRaw[i][j].toString('hex')) + '\r\n';
3929
- }
3930
- }
3931
- }
3932
- }
3933
- break;
3934
- }
3935
- case 'eval': { // Eval JavaScript
3936
- if (args['_'].length < 1) {
3937
- response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
3938
- } else {
3939
- response = JSON.stringify(mesh.eval(args['_'][0])); // This can only be run by trusted administrator.
3940
- }
3941
- break;
3942
- }
3943
- case 'uninstallagent': // Uninstall this agent
3944
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3945
- try {
3946
- agentName = require('MeshAgent').serviceName;
3947
- }
3948
- catch (x) {
3949
- }
3950
-
3951
- if (!require('service-manager').manager.getService(agentName).isMe()) {
3952
- response = 'Uininstall failed, this instance is not the service instance';
3953
- } else {
3954
- try { diagnosticAgent_uninstall(); } catch (e) { }
3955
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
3956
- this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
3957
- }
3958
- break;
3959
- case 'notify': { // Send a notification message to the mesh
3960
- if (args['_'].length != 1) {
3961
- response = 'Proper usage: notify "message" [--session]'; // Display correct command usage
3962
- } else {
3963
- var notification = { action: 'msg', type: 'notify', value: args['_'][0], tag: 'console' };
3964
- if (args.session) { notification.sessionid = sessionid; } // If "--session" is specified, notify only this session, if not, the server will notify the mesh
3965
- mesh.SendCommand(notification); // no sessionid or userid specified, notification will go to the entire mesh
3966
- response = "ok";
3967
- }
3968
- break;
3969
- }
3970
- case 'cpuinfo': { // Return system information
3971
- // CPU & memory utilization
3972
- pr = require('sysinfo').cpuUtilization();
3973
- pr.sessionid = sessionid;
3974
- pr.then(function (data) {
3975
- sendConsoleText(JSON.stringify(
3976
- {
3977
- cpu: data,
3978
- memory: require('sysinfo').memUtilization(),
3979
- thermals: require('sysinfo').thermals == null ? [] : require('sysinfo').thermals()
3980
- }, null, 1), this.sessionid);
3981
- }, function (e) {
3982
- sendConsoleText(e);
3983
- });
3984
- break;
3985
- }
3986
- case 'sysinfo': { // Return system information
3987
- getSystemInformation(function (results, err) {
3988
- if (results == null) { sendConsoleText(err, this.sessionid); } else {
3989
- sendConsoleText(JSON.stringify(results, null, 1), this.sessionid);
3990
- }
3991
- });
3992
- break;
3993
- }
3994
- case 'info': { // Return information about the agent and agent core module
3995
- response = 'Current Core: ' + meshCoreObj.value + '\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform: ' + process.platform + '.\r\nCapabilities: ' + meshCoreObj.caps + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
3996
- if (amt != null) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amt.lmsstate] + '.'; }
3997
- if (meshCoreObj.osdesc) { response += '\r\nOS: ' + meshCoreObj.osdesc + '.'; }
3998
- response += '\r\nModules: ' + addedModules.join(', ') + '.';
3999
- response += '\r\nServer Connection: ' + mesh.isControlChannelConnected + ', State: ' + meshServerConnectionState + '.';
4000
- var oldNodeId = db.Get('OldNodeId');
4001
- if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
4002
- if (process.platform == 'linux' || process.platform == 'freebsd') { response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.'; }
4003
- //response += '\r\Debug Console: ' + debugConsole + '.';
4004
- break;
4005
- }
4006
- case 'osinfo': { // Return the operating system information
4007
- var i = 1;
4008
- if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; }
4009
- for (var j = 0; j < i; j++) {
4010
- var pr = require('os').name();
4011
- pr.sessionid = sessionid;
4012
- pr.then(function (v) {
4013
- sendConsoleText("OS: " + v + (process.platform == 'win32' ? (require('win-virtual-terminal').supported ? ' [ConPTY: YES]' : ' [ConPTY: NO]') : ''), this.sessionid);
4014
- });
4015
- }
4016
- break;
4017
- }
4018
- case 'args': { // Displays parsed command arguments
4019
- response = 'args ' + objToString(args, 0, ' ', true);
4020
- break;
4021
- }
4022
- case 'print': { // Print a message on the mesh agent console, does nothing when running in the background
4023
- var r = [];
4024
- for (var i in args['_']) { r.push(args['_'][i]); }
4025
- console.log(r.join(' '));
4026
- response = 'Message printed on agent console.';
4027
- break;
4028
- }
4029
- case 'type': { // Returns the content of a file
4030
- if (args['_'].length == 0) {
4031
- response = 'Proper usage: type (filepath) [maxlength]'; // Display correct command usage
4032
- } else {
4033
- var max = 4096;
4034
- if ((args['_'].length > 1) && (typeof args['_'][1] == 'number')) { max = args['_'][1]; }
4035
- if (max > 4096) max = 4096;
4036
- var buf = Buffer.alloc(max), fd = fs.openSync(args['_'][0], "r"), r = fs.readSync(fd, buf, 0, max); // Read the file content
4037
- response = buf.toString();
4038
- var i = response.indexOf('\n');
4039
- if ((i > 0) && (response[i - 1] != '\r')) { response = response.split('\n').join('\r\n'); }
4040
- if (r == max) response += '...';
4041
- fs.closeSync(fd);
4042
- }
4043
- break;
4044
- }
4045
- case 'dbkeys': { // Return all data store keys
4046
- response = JSON.stringify(db.Keys);
4047
- break;
4048
- }
4049
- case 'dbget': { // Return the data store value for a given key
4050
- if (db == null) { response = 'Database not accessible.'; break; }
4051
- if (args['_'].length != 1) {
4052
- response = 'Proper usage: dbget (key)'; // Display the value for a given database key
4053
- } else {
4054
- response = db.Get(args['_'][0]);
4055
- }
4056
- break;
4057
- }
4058
- case 'dbset': { // Set a data store key and value pair
4059
- if (db == null) { response = 'Database not accessible.'; break; }
4060
- if (args['_'].length != 2) {
4061
- response = 'Proper usage: dbset (key) (value)'; // Set a database key
4062
- } else {
4063
- var r = db.Put(args['_'][0], args['_'][1]);
4064
- response = 'Key set: ' + r;
4065
- }
4066
- break;
4067
- }
4068
- case 'dbcompact': { // Compact the data store
4069
- if (db == null) { response = 'Database not accessible.'; break; }
4070
- var r = db.Compact();
4071
- response = 'Database compacted: ' + r;
4072
- break;
4073
- }
4074
- case 'httpget': {
4075
- if (consoleHttpRequest != null) {
4076
- response = 'HTTP operation already in progress.';
4077
- } else {
4078
- if (args['_'].length != 1) {
4079
- response = 'Proper usage: httpget (url)';
4080
- } else {
4081
- var options = http.parseUri(args['_'][0]);
4082
- options.method = 'GET';
4083
- if (options == null) {
4084
- response = 'Invalid url.';
4085
- } else {
4086
- try { consoleHttpRequest = http.request(options, consoleHttpResponse); } catch (e) { response = 'Invalid HTTP GET request'; }
4087
- consoleHttpRequest.sessionid = sessionid;
4088
- if (consoleHttpRequest != null) {
4089
- consoleHttpRequest.end();
4090
- response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
4091
- }
4092
- }
4093
- }
4094
- }
4095
- break;
4096
- }
4097
- case 'wslist': { // List all web sockets
4098
- response = '';
4099
- for (var i in consoleWebSockets) {
4100
- var httprequest = consoleWebSockets[i];
4101
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
4102
- }
4103
- if (response == '') { response = 'no websocket sessions.'; }
4104
- break;
4105
- }
4106
- case 'wsconnect': { // Setup a web socket
4107
- if (args['_'].length == 0) {
4108
- response = 'Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc'; // Display correct command usage
4109
- } else {
4110
- var httprequest = null;
4111
- try {
4112
- var options = http.parseUri(args['_'][0].split('$').join('%24').split('@').join('%40')); // Escape the $ and @ characters in the URL
4113
- options.rejectUnauthorized = 0;
4114
- httprequest = http.request(options);
4115
- } catch (e) { response = 'Invalid HTTP websocket request'; }
4116
- if (httprequest != null) {
4117
- httprequest.upgrade = onWebSocketUpgrade;
4118
- httprequest.on('error', function (e) { sendConsoleText("ERROR: Unable to connect to: " + this.url + ", " + JSON.stringify(e)); });
4119
-
4120
- var index = 1;
4121
- while (consoleWebSockets[index]) { index++; }
4122
- httprequest.sessionid = sessionid;
4123
- httprequest.index = index;
4124
- httprequest.url = args['_'][0];
4125
- consoleWebSockets[index] = httprequest;
4126
- response = 'New websocket session #' + index;
4127
- }
4128
- }
4129
- break;
4130
- }
4131
- case 'wssend': { // Send data on a web socket
4132
- if (args['_'].length == 0) {
4133
- response = 'Proper usage: wssend (socketnumber)\r\n'; // Display correct command usage
4134
- for (var i in consoleWebSockets) {
4135
- var httprequest = consoleWebSockets[i];
4136
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
4137
- }
4138
- } else {
4139
- var i = parseInt(args['_'][0]);
4140
- var httprequest = consoleWebSockets[i];
4141
- if (httprequest != undefined) {
4142
- httprequest.s.write(args['_'][1]);
4143
- response = 'ok';
4144
- } else {
4145
- response = 'Invalid web socket number';
4146
- }
4147
- }
4148
- break;
4149
- }
4150
- case 'wsclose': { // Close a websocket
4151
- if (args['_'].length == 0) {
4152
- response = 'Proper usage: wsclose (socketnumber)'; // Display correct command usage
4153
- } else {
4154
- var i = parseInt(args['_'][0]);
4155
- var httprequest = consoleWebSockets[i];
4156
- if (httprequest != undefined) {
4157
- if (httprequest.s != null) { httprequest.s.end(); } else { httprequest.end(); }
4158
- response = 'ok';
4159
- } else {
4160
- response = 'Invalid web socket number';
4161
- }
4162
- }
4163
- break;
4164
- }
4165
- case 'tunnels': { // Show the list of current tunnels
4166
- response = '';
4167
- for (var i in tunnels) {
4168
- response += 'Tunnel #' + i + ', ' + tunnels[i].protocol; //tunnels[i].url
4169
- if (tunnels[i].userid) { response += ', ' + tunnels[i].userid; }
4170
- if (tunnels[i].guestname) { response += '/' + tunnels[i].guestname; }
4171
- response += '\r\n'
4172
- }
4173
- if (response == '') { response = 'No websocket sessions.'; }
4174
- break;
4175
- }
4176
- case 'ls': { // Show list of files and folders
4177
- response = '';
4178
- var xpath = '*';
4179
- if (args['_'].length > 0) { xpath = obj.path.join(args['_'][0], '*'); }
4180
- response = 'List of ' + xpath + '\r\n';
4181
- var results = fs.readdirSync(xpath);
4182
- for (var i = 0; i < results.length; ++i) {
4183
- var stat = null, p = obj.path.join(args['_'][0], results[i]);
4184
- try { stat = fs.statSync(p); } catch (e) { }
4185
- if ((stat == null) || (stat == undefined)) {
4186
- response += (results[i] + "\r\n");
4187
- } else {
4188
- response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
4189
- }
4190
- }
4191
- break;
4192
- }
4193
- case 'lsx': { // Show list of files and folders
4194
- response = objToString(getDirectoryInfo(args['_'][0]), 0, ' ', true);
4195
- break;
4196
- }
4197
- case 'lock': { // Lock the current user out of the desktop
4198
- lockDesktop();
4199
- break;
4200
- }
4201
- case 'amt': { // Show Intel AMT status
4202
- if (amt != null) {
4203
- amt.getMeiState(9, function (state) {
4204
- var resp = "Intel AMT not detected.";
4205
- if (state != null) { resp = objToString(state, 0, ' ', true); }
4206
- sendConsoleText(resp, sessionid);
4207
- });
4208
- } else {
4209
- response = "Intel AMT not detected.";
4210
- }
4211
- break;
4212
- }
4213
- case 'netinfo': { // Show network interface information
4214
- var interfaces = require('os').networkInterfaces();
4215
- response = objToString(interfaces, 0, ' ', true);
4216
- break;
4217
- }
4218
- case 'wakeonlan': { // Send wake-on-lan
4219
- if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
4220
- response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
4221
- } else {
4222
- var count = sendWakeOnLanEx([args['_'][0]]);
4223
- sendWakeOnLanEx([args['_'][0]]);
4224
- sendWakeOnLanEx([args['_'][0]]);
4225
- response = 'Sending wake-on-lan on ' + count + ' interface(s).';
4226
- }
4227
- break;
4228
- }
4229
- case 'sendall': { // Send a message to all consoles on this mesh
4230
- sendConsoleText(args['_'].join(' '));
4231
- break;
4232
- }
4233
- case 'power': { // Execute a power action on this computer
4234
- if (mesh.ExecPowerState == undefined) {
4235
- response = 'Power command not supported on this agent.';
4236
- } else {
4237
- if ((args['_'].length == 0) || isNaN(Number(args['_'][0]))) {
4238
- response = 'Proper usage: power (actionNumber), where actionNumber is:\r\n LOGOFF = 1\r\n SHUTDOWN = 2\r\n REBOOT = 3\r\n SLEEP = 4\r\n HIBERNATE = 5\r\n DISPLAYON = 6\r\n KEEPAWAKE = 7\r\n BEEP = 8\r\n CTRLALTDEL = 9\r\n VIBRATE = 13\r\n FLASH = 14'; // Display correct command usage
4239
- } else {
4240
- var r = mesh.ExecPowerState(Number(args['_'][0]), Number(args['_'][1]));
4241
- response = 'Power action executed with return code: ' + r + '.';
4242
- }
4243
- }
4244
- break;
4245
- }
4246
- case 'location': {
4247
- getIpLocationData(function (location) {
4248
- sendConsoleText(objToString({ action: 'iplocation', type: 'publicip', value: location }, 0, ' '));
4249
- });
4250
- break;
4251
- }
4252
- case 'parseuri': {
4253
- response = JSON.stringify(http.parseUri(args['_'][0]));
4254
- break;
4255
- }
4256
- case 'scanwifi': {
4257
- if (wifiScanner != null) {
4258
- var wifiPresent = wifiScanner.hasWireless;
4259
- if (wifiPresent) { response = "Perfoming Wifi scan..."; wifiScanner.Scan(); } else { response = "Wifi absent."; }
4260
- } else
4261
- { response = "Wifi module not present."; }
4262
- break;
4263
- }
4264
- case 'modules': {
4265
- response = JSON.stringify(addedModules);
4266
- break;
4267
- }
4268
- case 'listservices': {
4269
- var services = require('service-manager').manager.enumerateService();
4270
- response = JSON.stringify(services, null, 1);
4271
- break;
4272
- }
4273
- case 'getscript': {
4274
- if (args['_'].length != 1) {
4275
- response = "Proper usage: getscript [scriptNumber].";
4276
- } else {
4277
- mesh.SendCommand({ action: 'getScript', type: args['_'][0] });
4278
- }
4279
- break;
4280
- }
4281
- case 'diagnostic':
4282
- {
4283
- if (!mesh.DAIPC.listening) {
4284
- response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
4285
- break;
4286
- }
4287
- var diag = diagnosticAgent_installCheck();
4288
- if (diag) {
4289
- if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
4290
- diagnosticAgent_uninstall();
4291
- response = 'Diagnostic Agent uninstalled';
4292
- }
4293
- else {
4294
- response = 'Diagnostic Agent installed at: ' + diag.appLocation();
4295
- }
4296
- }
4297
- else {
4298
- if (args['_'].length == 1 && args['_'][0] == 'install') {
4299
- diag = diagnosticAgent_installCheck(true);
4300
- if (diag) {
4301
- response = 'Diagnostic agent was installed at: ' + diag.appLocation();
4302
- }
4303
- else {
4304
- response = 'Diagnostic agent installation failed';
4305
- }
4306
- }
4307
- else {
4308
- response = 'Diagnostic Agent Not installed. To install: diagnostic install';
4309
- }
4310
- }
4311
- if (diag) { diag.close(); diag = null; }
4312
- break;
4313
- }
4314
- case 'amtevents': {
4315
- if ((args['_'].length == 1) && (args['_'][0] == 'on')) { obj.showamtevent = true; response = 'Intel AMT configuration events live view enabled.'; }
4316
- else if ((args['_'].length == 1) && (args['_'][0] == 'off')) { delete obj.showamtevent; response = 'Intel AMT configuration events live view disabled.'; }
4317
- else if (obj.amtevents == null) { response = 'No events.'; } else { response = obj.amtevents.join('\r\n'); }
4318
- break;
4319
- }
4320
- case 'amtconfig': {
4321
- if (amt == null) { response = 'Intel AMT not detected.'; break; }
4322
- if (apftunnel != null) { response = 'Intel AMT server tunnel already active'; break; }
4323
- if (!obj.showamtevent) { obj.showamtevent = true; require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'Enabled live view of Intel AMT configuration events, \"amtevents off\" to disable.' }); }
4324
- amt.getMeiState(15, function (state) {
4325
- if ((state == null) || (state.ProvisioningState == null)) { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'Intel AMT not ready for configuration.' }); } else {
4326
- getAmtOsDnsSuffix(state, function () {
4327
- var rx = '';
4328
- var apfarg = {
4329
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
4330
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16).replace(/\+/g, '@').replace(/\//g, '$'),
4331
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16).replace(/\+/g, '@').replace(/\//g, '$'),
4332
- mpskeepalive: 60000,
4333
- clientname: state.OsHostname,
4334
- clientaddress: '127.0.0.1',
4335
- clientuuid: state.UUID,
4336
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
4337
- meiState: state // MEI state will be passed to MPS server
4338
- };
4339
- if ((state.UUID == null) || (state.UUID.length != 36)) {
4340
- rx = "Unable to get Intel AMT UUID";
4341
- } else {
4342
- addAmtEvent('User LMS tunnel start.');
4343
- apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
4344
- apftunnel.onJsonControl = handleApfJsonControl;
4345
- apftunnel.onChannelClosed = function () { addAmtEvent('User LMS tunnel closed.'); apftunnel = null; }
4346
- try { apftunnel.connect(); } catch (ex) { rx = JSON.stringify(ex); }
4347
- }
4348
- if (rx != '') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: rx }); }
4349
- });
4350
- }
4351
- });
4352
- break;
4353
- }
4354
- case 'apf': {
4355
- if (meshCoreObj.intelamt !== null) {
4356
- if (args['_'].length == 1) {
4357
- var connType = -1, connTypeStr = args['_'][0].toLowerCase();
4358
- if (connTypeStr == 'lms') { connType = 2; }
4359
- if (connTypeStr == 'relay') { connType = 1; }
4360
- if (connTypeStr == 'cira') { connType = 0; }
4361
- if (connTypeStr == 'off') { connType = -2; }
4362
- if (connType >= 0) { // Connect
4363
- var apfarg = {
4364
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
4365
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16).replace(/\+/g, '@').replace(/\//g, '$'),
4366
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16).replace(/\+/g, '@').replace(/\//g, '$'),
4367
- mpskeepalive: 60000,
4368
- clientname: require('os').hostname(),
4369
- clientaddress: '127.0.0.1',
4370
- clientuuid: meshCoreObj.intelamt.UUID,
4371
- conntype: connType // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
4372
- };
4373
- if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
4374
- response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
4375
- } else {
4376
- apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
4377
- apftunnel.onJsonControl = handleApfJsonControl;
4378
- apftunnel.onChannelClosed = function () { apftunnel = null; }
4379
- try {
4380
- apftunnel.connect();
4381
- response = "Started APF tunnel";
4382
- } catch (e) {
4383
- response = JSON.stringify(e);
4384
- }
4385
- }
4386
- } else if (connType == -2) { // Disconnect
4387
- try {
4388
- apftunnel.disconnect();
4389
- response = "Stopped APF tunnel";
4390
- } catch (e) {
4391
- response = JSON.stringify(e);
4392
- }
4393
- apftunnel = null;
4394
- } else {
4395
- response = "Invalid command.\r\nUse: apf lms|relay|cira|off";
4396
- }
4397
- } else {
4398
- response = "APF tunnel is " + (apftunnel == null ? "off" : "on") + "\r\nUse: apf lms|relay|cira|off";
4399
- }
4400
- } else {
4401
- response = "APF tunnel requires Intel AMT";
4402
- }
4403
- break;
4404
- }
4405
- case 'task': {
4406
- if (!scriptTask) { response = "Tasks are not supported on this agent"; }
4407
- else {
4408
- if (args['_'][0]) { args.cmd = args['_'][0].toLowerCase(); }
4409
- response = scriptTask.processCommand(args, rights, sessionid);
4410
- }
4411
- break;
4412
- }
4413
- case 'plugin': {
4414
- if (typeof args['_'][0] == 'string') {
4415
- try {
4416
- // Pass off the action to the plugin
4417
- // for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
4418
- // to control the output / actions here.
4419
- response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
4420
- } catch (e) {
4421
- response = "There was an error in the plugin (" + e + ")";
4422
- }
4423
- } else {
4424
- response = "Proper usage: plugin [pluginName] [args].";
4425
- }
4426
- break;
4427
- }
4428
- default: { // This is an unknown command, return an error message
4429
- response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands.";
4430
- break;
4431
- }
4432
- }
4433
- } catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
4434
- if (response != null) { sendConsoleText(response, sessionid); }
4435
-}
4436
-
4437
-// Send a mesh agent console command
4438
-function sendConsoleText(text, sessionid) {
4439
- if (typeof text == 'object') { text = JSON.stringify(text); }
4440
- if (debugConsole && ((sessionid == null) || (sessionid == 'pipe'))) { broadcastToRegisteredApps({ cmd: 'console', value: text }); }
4441
- if (sessionid != 'pipe') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: text, sessionid: sessionid }); }
4442
-}
4443
-
4444
-function removeAgentMessage(msgid) {
4445
- var ret = false;
4446
- if (msgid == null) {
4447
- // Delete all messages
4448
- sendAgentMessage.messages = [];
4449
- ret = true;
4450
- }
4451
- else {
4452
- var i = sendAgentMessage.messages.findIndex(function (v) { return (v.id == msgid); });
4453
- if (i >= 0) {
4454
- sendAgentMessage.messages.splice(i, 1);
4455
- ret = true;
4456
- }
4457
- }
4458
- if (ret) { sendAgentMessage(); }
4459
- return (ret);
4460
-}
4461
-
4462
-// Send a mesh agent message to server, placing a bubble/badge on the agent device
4463
-function sendAgentMessage(msg, icon, serverid, first) {
4464
- if (sendAgentMessage.messages == null) {
4465
- sendAgentMessage.messages = [];
4466
- }
4467
-
4468
- if (arguments.length > 0) {
4469
- if (first == null || (serverid && first && sendAgentMessage.messages.findIndex(function (v) { return (v.msgid == serverid); }) < 0)) {
4470
- sendAgentMessage.messages.push({ msg: msg, icon: icon, msgid: serverid });
4471
- sendAgentMessage.messages.peek().id = sendAgentMessage.messages.peek()._hashCode();
4472
- }
4473
- }
4474
-
4475
- var p = {}, i;
4476
- for (i = 0; i < sendAgentMessage.messages.length; ++i) {
4477
- p[i] = sendAgentMessage.messages[i];
4478
- }
4479
- try {
4480
- require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: p });
4481
- }
4482
- catch (ex) {
4483
- }
4484
- return (arguments.length > 0 ? sendAgentMessage.messages.peek().id : sendAgentMessage.messages);
4485
-}
4486
-function getOpenDescriptors() {
4487
- var r = [];
4488
- switch (process.platform) {
4489
- case "freebsd": {
4490
- var child = require('child_process').execFile('/bin/sh', ['sh']);
4491
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
4492
- child.stderr.on('data', function (c) { });
4493
-
4494
- child.stdin.write("procstat -f " + process.pid + " | tr '\\n' '`' | awk -F'`' '");
4495
- child.stdin.write('{');
4496
- child.stdin.write(' DEL="";');
4497
- child.stdin.write(' printf "[";');
4498
- child.stdin.write(' for(i=1;i<NF;++i)');
4499
- child.stdin.write(' {');
4500
- child.stdin.write(' A=split($i,B," ");');
4501
- child.stdin.write(' if(B[3] ~ /^[0-9]/)');
4502
- child.stdin.write(' {');
4503
- child.stdin.write(' printf "%s%s", DEL, B[3];');
4504
- child.stdin.write(' DEL=",";');
4505
- child.stdin.write(' }');
4506
- child.stdin.write(' }');
4507
- child.stdin.write(' printf "]";');
4508
- child.stdin.write("}'");
4509
-
4510
- child.stdin.write('\nexit\n');
4511
- child.waitExit();
4512
-
4513
- try { r = JSON.parse(child.stdout.str.trim()); } catch (ex) { }
4514
- break;
4515
- }
4516
- case "linux": {
4517
- var child = require('child_process').execFile('/bin/sh', ['sh']);
4518
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
4519
- child.stderr.on('data', function (c) { });
4520
-
4521
- child.stdin.write("ls /proc/" + process.pid + "/fd | tr '\\n' '`' | awk -F'`' '");
4522
- child.stdin.write('{');
4523
- child.stdin.write(' printf "[";');
4524
- child.stdin.write(' DEL="";');
4525
- child.stdin.write(' for(i=1;i<NF;++i)');
4526
- child.stdin.write(' {');
4527
- child.stdin.write(' printf "%s%s",DEL,$i;');
4528
- child.stdin.write(' DEL=",";');
4529
- child.stdin.write(' }');
4530
- child.stdin.write(' printf "]";');
4531
- child.stdin.write("}'");
4532
- child.stdin.write('\nexit\n');
4533
- child.waitExit();
4534
-
4535
- try { r = JSON.parse(child.stdout.str.trim()); } catch (ex) { }
4536
- break;
4537
- }
4538
- }
4539
- return r;
4540
-}
4541
-function closeDescriptors(libc, descriptors) {
4542
- var fd = null;
4543
- while (descriptors.length > 0) {
4544
- fd = descriptors.pop();
4545
- if (fd > 2) {
4546
- libc.close(fd);
4547
- }
4548
- }
4549
-}
4550
-function linux_execv(name, agentfilename, sessionid) {
4551
- var libs = require('monitor-info').getLibInfo('libc');
4552
- var libc = null;
4553
-
4554
- if ((libs.length == 0 || libs.length == null) && require('MeshAgent').ARCHID == 33) {
4555
- var child = require('child_process').execFile('/bin/sh', ['sh']);
4556
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
4557
- child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
4558
- child.stdin.write("ls /lib/libc.* | tr '\\n' '`' | awk -F'`' '{ " + ' printf "["; DEL=""; for(i=1;i<NF;++i) { printf "%s{\\"path\\":\\"%s\\"}",DEL,$i; DEL=""; } printf "]"; }\'\nexit\n');
4559
- child.waitExit();
4560
-
4561
- try {
4562
- libs = JSON.parse(child.stdout.str.trim());
4563
- }
4564
- catch (e) {
4565
- }
4566
- }
4567
-
4568
- while (libs.length > 0) {
4569
- try {
4570
- libc = require('_GenericMarshal').CreateNativeProxy(libs.pop().path);
4571
- break;
4572
- }
4573
- catch (e) {
4574
- libc = null;
4575
- continue;
4576
- }
4577
- }
4578
- if (libc != null) {
4579
- try {
4580
- libc.CreateMethod('execv');
4581
- libc.CreateMethod('close');
4582
- }
4583
- catch (e) {
4584
- libc = null;
4585
- }
4586
- }
4587
-
4588
- if (libc == null) {
4589
- // Couldn't find libc.so, fallback to using service manager to restart agent
4590
- if (sessionid != null) { sendConsoleText('Restarting service via service-manager...', sessionid) }
4591
- try {
4592
- // restart service
4593
- var s = require('service-manager').manager.getService(name);
4594
- s.restart();
4595
- }
4596
- catch (zz) {
4597
- sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
4598
- sendAgentMessage('Self Update encountered an error trying to restart service', 3);
4599
- }
4600
- return;
4601
- }
4602
-
4603
- if (sessionid != null) { sendConsoleText('Restarting service via execv()...', sessionid) }
4604
-
4605
- var i;
4606
- var args;
4607
- var argarr = [process.execPath];
4608
- var argtmp = [];
4609
- var path = require('_GenericMarshal').CreateVariable(process.execPath);
4610
-
4611
- if (require('MeshAgent').getStartupOptions != null) {
4612
- var options = require('MeshAgent').getStartupOptions();
4613
- for (i in options) {
4614
- argarr.push('--' + i + '="' + options[i] + '"');
4615
- }
4616
- }
4617
-
4618
- args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
4619
- for (i = 0; i < argarr.length; ++i) {
4620
- var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
4621
- argtmp.push(arg);
4622
- arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
4623
- }
4624
-
4625
- var descriptors = getOpenDescriptors();
4626
- closeDescriptors(libc, descriptors);
4627
-
4628
- libc.execv(path, args);
4629
- if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
4630
- sendAgentMessage('Self Update failed because execv() failed', 3);
4631
-}
4632
-
4633
-function bsd_execv(name, agentfilename, sessionid) {
4634
- var child = require('child_process').execFile('/bin/sh', ['sh']);
4635
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
4636
- child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
4637
- child.stdin.write("cat /usr/lib/libc.so | awk '");
4638
- child.stdin.write('{');
4639
- child.stdin.write(' a=split($0, tok, "(");');
4640
- child.stdin.write(' if(a>1)');
4641
- child.stdin.write(' {');
4642
- child.stdin.write(' split(tok[2], b, ")");');
4643
- child.stdin.write(' split(b[1], c, " ");');
4644
- child.stdin.write(' print c[1];');
4645
- child.stdin.write(' }');
4646
- child.stdin.write("}'\nexit\n");
4647
- child.waitExit();
4648
- if (child.stdout.str.trim() == '') {
4649
- if (sessionid != null) { sendConsoleText('Self Update failed because cannot find libc.so', sessionid) }
4650
- sendAgentMessage('Self Update failed because cannot find libc.so', 3);
4651
- return;
4652
- }
4653
-
4654
- var libc = null;
4655
- try {
4656
- libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
4657
- libc.CreateMethod('execv');
4658
- libc.CreateMethod('close');
4659
- }
4660
- catch (e) {
4661
- if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
4662
- sendAgentMessage('Self Update failed: ' + e.toString(), 3);
4663
- return;
4664
- }
4665
-
4666
- var i;
4667
- var path = require('_GenericMarshal').CreateVariable(process.execPath);
4668
- var argarr = [process.execPath];
4669
- var argtmp = [];
4670
- var args;
4671
- var options = require('MeshAgent').getStartupOptions();
4672
- for (i in options) {
4673
- argarr.push('--' + i + '="' + options[i] + '"');
4674
- }
4675
- args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
4676
- for (i = 0; i < argarr.length; ++i) {
4677
- var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
4678
- argtmp.push(arg);
4679
- arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
4680
- }
4681
-
4682
- if (sessionid != null) { sendConsoleText('Restarting service via execv()', sessionid) }
4683
-
4684
- var descriptors = getOpenDescriptors();
4685
- closeDescriptors(libc, descriptors);
4686
-
4687
- libc.execv(path, args);
4688
- if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
4689
- sendAgentMessage('Self Update failed because execv() failed', 3);
4690
-}
4691
-
4692
-function windows_execve(name, agentfilename, sessionid) {
4693
- var libc;
4694
- try {
4695
- libc = require('_GenericMarshal').CreateNativeProxy('msvcrt.dll');
4696
- libc.CreateMethod('_wexecve');
4697
- }
4698
- catch (xx) {
4699
- sendConsoleText('Self Update failed because msvcrt.dll is missing', sessionid);
4700
- sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
4701
- return;
4702
- }
4703
-
4704
- var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
4705
- var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
4706
- var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
4707
- var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + process.cwd() + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' +
4708
- ' "' + process.execPath + '" & copy "' + process.cwd() + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + process.cwd() + agentfilename + '.update.exe"', { wide: true });
4709
-
4710
- arg1.pointerBuffer().copy(args.toBuffer());
4711
- arg2.pointerBuffer().copy(args.toBuffer(), require('_GenericMarshal').PointerSize);
4712
-
4713
- libc._wexecve(cmd, args, 0);
4714
-}
4715
-
4716
-// Start a JavaScript based Agent Self-Update
4717
-function agentUpdate_Start(updateurl, updateoptions) {
4718
- // If this value is null
4719
- var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
4720
-
4721
- // If the url starts with *, switch it to use the same protoco, host and port as the control channel.
4722
- if (updateurl != null) {
4723
- updateurl = getServerTargetUrlEx(updateurl);
4724
- if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
4725
- }
4726
-
4727
- if (agentUpdate_Start._selfupdate != null) {
4728
- // We were already called, so we will ignore this duplicate request
4729
- if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
4730
- }
4731
- else {
4732
- if (agentUpdate_Start._retryCount == null) { agentUpdate_Start._retryCount = 0; }
4733
- if (require('MeshAgent').ARCHID == null && updateurl == null) {
4734
- // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
4735
- sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
4736
- }
4737
- else {
4738
- var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
4739
- var name = require('MeshAgent').serviceName;
4740
- if (name == null) { name = (process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); } // This is an older agent that doesn't expose the service name, so use the default
4741
- try {
4742
- var s = require('service-manager').manager.getService(name);
4743
- if (!s.isMe()) {
4744
- if (process.platform == 'win32') { s.close(); }
4745
- sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
4746
- return;
4747
- }
4748
- if (process.platform == 'win32') { s.close(); }
4749
- }
4750
- catch (zz) {
4751
- sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
4752
- sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
4753
- return;
4754
- }
4755
-
4756
- if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
4757
- var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
4758
- options.protocol = 'https:';
4759
- if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); sendConsoleText('Downloading update from: ' + options.path, sessionid); }
4760
- options.rejectUnauthorized = false;
4761
- options.checkServerIdentity = function checkServerIdentity(certs) {
4762
- // If the tunnel certificate matches the control channel certificate, accept the connection
4763
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
4764
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
4765
-
4766
- // Check that the certificate is the one expected by the server, fail if not.
4767
- if (checkServerIdentity.servertlshash == null) {
4768
- if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
4769
- sendConsoleText('Self Update failed, because the url cannot be verified: ' + updateurl, sessionid);
4770
- sendAgentMessage('Self Update failed, because the url cannot be verified: ' + updateurl, 3);
4771
- throw new Error('BadCert');
4772
- }
4773
- if (certs[0].digest == null) { return; }
4774
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) {
4775
- sendConsoleText('Self Update failed, because the supplied certificate does not match', sessionid);
4776
- sendAgentMessage('Self Update failed, because the supplied certificate does not match', 3);
4777
- throw new Error('BadCert')
4778
- }
4779
- }
4780
- options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
4781
- agentUpdate_Start._selfupdate = require('https').get(options);
4782
- agentUpdate_Start._selfupdate.on('error', function (e) {
4783
- sendConsoleText('Self Update failed, because there was a problem trying to download the update from ' + updateurl, sessionid);
4784
- sendAgentMessage('Self Update failed, because there was a problem trying to download the update from ' + updateurl, 3);
4785
- agentUpdate_Start._selfupdate = null;
4786
- });
4787
- agentUpdate_Start._selfupdate.on('response', function (img) {
4788
- this._file = require('fs').createWriteStream(agentfilename + (process.platform == 'win32' ? '.update.exe' : '.update'), { flags: 'wb' });
4789
- this._filehash = require('SHA384Stream').create();
4790
- this._filehash.on('hash', function (h) {
4791
- if (updateoptions != null && updateoptions.hash != null) {
4792
- if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) {
4793
- if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
4794
- } else {
4795
- agentUpdate_Start._retryCount++;
4796
- sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, sessionid);
4797
- sendConsoleText(updateoptions.hash + " != " + h.toString('hex'));
4798
- sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, 3);
4799
- agentUpdate_Start._selfupdate = null;
4800
-
4801
- if (agentUpdate_Start._retryCount < 4) {
4802
- // Retry the download again
4803
- sendConsoleText('Self Update will try again in 60 seconds...', sessionid);
4804
- agentUpdate_Start._timeout = setTimeout(agentUpdate_Start, 60000, updateurl, updateoptions);
4805
- }
4806
- else {
4807
- sendConsoleText('Self Update giving up, too many failures...', sessionid);
4808
- sendAgentMessage('Self Update giving up, too many failures...', 3);
4809
- }
4810
- return;
4811
- }
4812
- }
4813
- else {
4814
- sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
4815
- }
4816
-
4817
- // Send an indication to the server that we got the update download correctly.
4818
- try { require('MeshAgent').SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
4819
-
4820
- if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
4821
- if (process.platform == 'win32') {
4822
- // Use _wexecve() equivalent to perform the update
4823
- windows_execve(name, agentfilename, sessionid);
4824
- }
4825
- else {
4826
- var m = require('fs').statSync(process.execPath).mode;
4827
- require('fs').chmodSync(process.cwd() + agentfilename + '.update', m);
4828
-
4829
- // remove binary
4830
- require('fs').unlinkSync(process.execPath);
4831
-
4832
- // copy update
4833
- require('fs').copyFileSync(process.cwd() + agentfilename + '.update', process.execPath);
4834
- require('fs').chmodSync(process.execPath, m);
4835
-
4836
- // erase update
4837
- require('fs').unlinkSync(process.cwd() + agentfilename + '.update');
4838
-
4839
- switch (process.platform) {
4840
- case 'freebsd':
4841
- bsd_execv(name, agentfilename, sessionid);
4842
- break;
4843
- case 'linux':
4844
- linux_execv(name, agentfilename, sessionid);
4845
- break;
4846
- default:
4847
- try {
4848
- // restart service
4849
- var s = require('service-manager').manager.getService(name);
4850
- s.restart();
4851
- }
4852
- catch (zz) {
4853
- sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
4854
- sendAgentMessage('Self Update encountered an error trying to restart service', 3);
4855
- }
4856
- break;
4857
- }
4858
- }
4859
- });
4860
- img.pipe(this._file);
4861
- img.pipe(this._filehash);
4862
- });
4863
- }
4864
- }
4865
-}
4866
-
4867
-
4868
-
4869
-
4870
-// Called before the process exits
4871
-//process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
4872
-
4873
-// Called when the server connection state changes
4874
-function handleServerConnection(state) {
4875
- meshServerConnectionState = state;
4876
- if (meshServerConnectionState == 0) {
4877
- // Server disconnected
4878
- if (selfInfoUpdateTimer != null) { clearInterval(selfInfoUpdateTimer); selfInfoUpdateTimer = null; }
4879
- lastSelfInfo = null;
4880
- } else {
4881
- // Server connected, send mesh core information
4882
- if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) {
4883
- // Outdated Agent, will have insecure tunnels
4884
- sendAgentMessage("This agent has an outdated certificate validation mechanism, consider updating.", 3, 118);
4885
- }
4886
- else if (global._MSH == null) {
4887
- sendAgentMessage("This is an old agent version, consider updating.", 3, 117);
4888
- }
4889
-
4890
- var oldNodeId = db.Get('OldNodeId');
4891
- if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); }
4892
-
4893
- // Send SMBios tables if present
4894
- if (SMBiosTablesRaw != null) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
4895
-
4896
- // Update the server on with basic info, logged in users and more advanced stuff, like Intel ME and Network Settings
4897
- meInfoStr = null;
4898
- sendPeriodicServerUpdate(null, true);
4899
- if (selfInfoUpdateTimer == null) {
4900
- selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); // 20 minutes
4901
- selfInfoUpdateTimer.metadata = 'meshcore (InfoUpdate Timer)';
4902
- }
4903
-
4904
- // Send any state messages
4905
- if (Object.keys(tunnelUserCount.msg).length > 0) {
4906
- sendAgentMessage();
4907
- broadcastSessionsToRegisteredApps();
4908
- }
4909
-
4910
- // Send update of registered applications to the server
4911
- updateRegisteredAppsToServer();
4912
- }
4913
-
4914
- // Send server state update to registered applications
4915
- broadcastToRegisteredApps({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer });
4916
-}
4917
-
4918
-// Update the server with the latest network interface information
4919
-var sendNetworkUpdateNagleTimer = null;
4920
-function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
4921
-function sendNetworkUpdate(force) {
4922
- sendNetworkUpdateNagleTimer = null;
4923
-
4924
- try {
4925
- // Update the network interfaces information data
4926
- var netInfo = { netif2: require('os').networkInterfaces() };
4927
- if (netInfo.netif2) {
4928
- netInfo.action = 'netinfo';
4929
- var netInfoStr = JSON.stringify(netInfo);
4930
- if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
4931
- }
4932
- } catch (ex) { }
4933
-}
4934
-
4935
-// Called periodically to check if we need to send updates to the server
4936
-function sendPeriodicServerUpdate(flags, force) {
4937
- if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
4938
- if (!flags) { flags = 0xFFFFFFFF; }
4939
-
4940
- // If we have a connected MEI, get Intel ME information
4941
- if ((flags & 1) && (amt != null) && (amt.state == 2)) {
4942
- delete meshCoreObj.intelamt;
4943
- amt.getMeiState(9, function (meinfo) {
4944
- meshCoreObj.intelamt = meinfo;
4945
- meshCoreObj.intelamt.microlms = amt.lmsstate;
4946
- meshCoreObjChanged();
4947
- });
4948
- }
4949
-
4950
- // Update network information
4951
- if (flags & 2) { sendNetworkUpdateNagle(false); }
4952
-
4953
- // Update anti-virus information
4954
- if ((flags & 4) && (process.platform == 'win32')) {
4955
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
4956
- try { meshCoreObj.av = require('win-info').av(); meshCoreObjChanged(); } catch (e) { av = null; } // Antivirus
4957
- //if (process.platform == 'win32') { try { meshCoreObj.pr = require('win-info').pendingReboot(); meshCoreObjChanged(); } catch (e) { meshCoreObj.pr = null; } } // Pending reboot
4958
- }
4959
- if (process.platform == 'win32') {
4960
- if (require('MeshAgent')._securitycenter == null) {
4961
- try {
4962
- require('MeshAgent')._securitycenter = require('win-securitycenter').status();
4963
- meshCoreObj['wsc'] = require('MeshAgent')._securitycenter; // Windows Security Central (WSC)
4964
- require('win-securitycenter').on('changed', function () {
4965
- require('MeshAgent')._securitycenter = require('win-securitycenter').status();
4966
- meshCoreObj['wsc'] = require('MeshAgent')._securitycenter; // Windows Security Central (WSC)
4967
- require('MeshAgent').SendCommand({ action: 'coreinfo', wsc: require('MeshAgent')._securitycenter });
4968
- });
4969
- } catch (e) { }
4970
- }
4971
- }
4972
-
4973
- // Send available data right now
4974
- if (force) {
4975
- meshCoreObj = sortObjRec(meshCoreObj);
4976
- var x = JSON.stringify(meshCoreObj);
4977
- if (x != LastPeriodicServerUpdate) {
4978
- LastPeriodicServerUpdate = x;
4979
- mesh.SendCommand(meshCoreObj);
4980
- }
4981
- }
4982
-}
4983
-
4984
-// Once we are done collecting all the data, send to server if needed
4985
-var LastPeriodicServerUpdate = null;
4986
-var PeriodicServerUpdateNagleTimer = null;
4987
-function meshCoreObjChanged() {
4988
- if (PeriodicServerUpdateNagleTimer == null) {
4989
- PeriodicServerUpdateNagleTimer = setTimeout(meshCoreObjChangedEx, 500);
4990
- }
4991
-}
4992
-function meshCoreObjChangedEx() {
4993
- PeriodicServerUpdateNagleTimer = null;
4994
- meshCoreObj = sortObjRec(meshCoreObj);
4995
- var x = JSON.stringify(meshCoreObj);
4996
- if (x != LastPeriodicServerUpdate) {
4997
- try { LastPeriodicServerUpdate = x; mesh.SendCommand(meshCoreObj); } catch (ex) { }
4998
- }
4999
-}
This file is too large to show in full.
agents/meshcore.js
+8
-10
@@ -1122,7 +1122,7 @@ function handleServerCommand(data) {
1122
// Kill a process
1123
if (data.value) {
1124
MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
1125
- try { process.kill(data.value); } catch (ex) { sendConsoleText("pskill: " + JSON.stringify(e)); }
1125
+ try { process.kill(data.value); } catch (ex) { sendConsoleText("pskill: " + JSON.stringify(ex)); }
1126
}
1127
break;
1128
}
@@ -1188,7 +1188,7 @@ function handleServerCommand(data) {
1188
require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
1189
}
1190
} catch (ex) {
1191
- sendConsoleText(e);
1191
+ sendConsoleText(ex);
1192
}
1193
break;
1194
}
@@ -1683,7 +1683,7 @@ function getSystemInformation(func) {
1683
func(results);
1684
}
1685
*/
1686
- } catch (ex) { func(null, e); }
1686
+ } catch (ex) { func(null, ex); }
1687
}
1688
1689
// Get a formated response for a given directory path
@@ -2446,8 +2446,7 @@ function onTunnelData(data) {
2446
try {
2447
this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2448
MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2449
- }
2450
- catch (ex) {
2449
+ } catch (ex) {
2450
if (process.platform != 'darwin') {
2451
MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2452
}
@@ -2499,8 +2498,7 @@ function onTunnelData(data) {
2498
try {
2499
this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2500
MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
2502
- }
2503
- catch (ex) {
2501
+ } catch (ex) {
2502
MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
2503
}
2504
if (this.httprequest.desktop.kvm.connectionBar) {
@@ -2906,7 +2904,7 @@ function onTunnelData(data) {
2904
2905
switch (cmd.action) {
2906
case 'plugin': {
2909
- try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (ex) { throw e; }
2907
+ try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (ex) { throw ex; }
2908
break;
2909
}
2910
default: {
@@ -3577,10 +3575,10 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
3575
if (process.platform == 'win32') {
3576
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
3577
var writtenSize = 0;
3580
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { response = e; }
3578
+ try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { response = ex; }
3579
if (writtenSize != actualSize) {
3580
response = "Size updated from: " + writtenSize + " to: " + actualSize;
3583
- try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { response = e; }
3581
+ try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { response = ex; }
3582
} else
3583
{ response = "Agent Size: " + actualSize + " kb"; }
3584
} else