Removed debug files
Ylian Saint-Hilaire committed
Oct 21, 2020 at 15:36 UTC
8f965dd4fc797cd5d09040716abd75818355d1a0
2 files changed
-7827
agents/meshcore-bad.js
deleted
-3924
@@ -1,3924 +0,0 @@
1
-/*
2
-Copyright 2018-2020 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
-
21
-// NOTE: This seems to cause big problems, don't enable the debugger in the server's meshcore.
22
-//attachDebugger({ webport: 9999, wait: 1 }).then(function (prt) { console.log('Point Browser for Debug to port: ' + prt); });
23
-
24
-// Mesh Rights
25
-var MNG_ERROR = 65;
26
-var MESHRIGHT_EDITMESH = 1;
27
-var MESHRIGHT_MANAGEUSERS = 2;
28
-var MESHRIGHT_MANAGECOMPUTERS = 4;
29
-var MESHRIGHT_REMOTECONTROL = 8;
30
-var MESHRIGHT_AGENTCONSOLE = 16;
31
-var MESHRIGHT_SERVERFILES = 32;
32
-var MESHRIGHT_WAKEDEVICE = 64;
33
-var MESHRIGHT_SETNOTES = 128;
34
-var MESHRIGHT_REMOTEVIEW = 256;
35
-var MESHRIGHT_NOTERMINAL = 512;
36
-var MESHRIGHT_NOFILES = 1024;
37
-var MESHRIGHT_NOAMT = 2048;
38
-var MESHRIGHT_LIMITEDINPUT = 4096;
39
-var MESHRIGHT_LIMITEVENTS = 8192;
40
-var MESHRIGHT_CHATNOTIFY = 16384;
41
-var MESHRIGHT_UNINSTALL = 32768;
42
-var MESHRIGHT_NODESKTOP = 65536;
43
-
44
-function createMeshCore(agent) {
45
- var obj = {};
46
- if (process.platform == 'win32' && require('user-sessions').isRoot()) {
47
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
48
- try {
49
- var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
50
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
51
- if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
52
- } catch (x) { }
53
-
54
- // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
55
- try {
56
- var meshCheck = false;
57
- try { meshCheck = require('service-manager').manager.getService('Mesh Agent').isMe(); } catch (e) { }
58
- if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService('Mesh Agent')) { require('win-bcd').enableSafeModeService('Mesh Agent'); }
59
- } catch (e) { }
60
- }
61
-
62
- if (process.platform == 'darwin' && !process.versions) {
63
- // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
64
- var child = require('child_process').execFile('/bin/sh', ['sh']);
65
- child.stdout.str = '';
66
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
67
- 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, \">\"); ");
68
- 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]; } }");
69
- child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
70
- child.waitExit();
71
- if (child.stdout.str.trim() == 'Crashed') {
72
- child = require('child_process').execFile('/bin/sh', ['sh']);
73
- child.stdout.str = '';
74
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
75
- child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
76
- child.waitExit();
77
-
78
- if (parseInt(child.stdout.str.trim()) == process.pid) {
79
- // The currently running MeshAgent is us, so we can continue with the update
80
- var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
81
- var tokens = plist.split('<key>KeepAlive</key>');
82
- if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
83
- var tmp = tokens[1].split('</dict>');
84
- tmp.shift();
85
- tokens[1] = '\n <true/>' + tmp.join('</dict>');
86
- tokens = tokens.join('<key>KeepAlive</key>');
87
-
88
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
89
-
90
- var fix = '';
91
- fix += ("function macosRepair()\n");
92
- fix += ("{\n");
93
- fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
94
- fix += (" child.stdout.str = '';\n");
95
- fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
96
- fix += (" child.stderr.on('data', function (chunk) { });\n");
97
- fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
98
- fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
99
- fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
100
- fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
101
- fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
102
- fix += (" child.waitExit();\n");
103
- fix += ("}\n");
104
- fix += ("macosRepair();\n");
105
- fix += ("process.exit();\n");
106
- require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
107
-
108
- var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
109
- plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
110
- plist += '<plist version="1.0">\n';
111
- plist += ' <dict>\n';
112
- plist += ' <key>Label</key>\n';
113
- plist += (' <string>meshagentRepair</string>\n');
114
- plist += ' <key>ProgramArguments</key>\n';
115
- plist += ' <array>\n';
116
- plist += (' <string>' + process.execPath + '</string>\n');
117
- plist += ' <string>macosRepair.js</string>\n';
118
- plist += ' </array>\n';
119
- plist += ' <key>WorkingDirectory</key>\n';
120
- plist += (' <string>' + process.cwd() + '</string>\n');
121
- plist += ' <key>RunAtLoad</key>\n';
122
- plist += ' <true/>\n';
123
- plist += ' </dict>\n';
124
- plist += '</plist>';
125
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
126
-
127
- child = require('child_process').execFile('/bin/sh', ['sh']);
128
- child.stdout.str = '';
129
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
130
- child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
131
- child.waitExit();
132
- }
133
- }
134
- }
135
- }
136
-
137
- // Create Secure IPC for Diagnostic Agent Communications
138
- obj.DAIPC = require('net').createServer();
139
- if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
140
- obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
141
- try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
142
- obj.DAIPC._daipc = [];
143
- obj.DAIPC.on('connection', function (c) {
144
- c._send = function (j) {
145
- var data = JSON.stringify(j);
146
- var packet = Buffer.alloc(data.length + 4);
147
- packet.writeUInt32LE(data.length + 4, 0);
148
- Buffer.from(data).copy(packet, 4);
149
- this.write(packet);
150
- };
151
- this._daipc.push(c);
152
- c.parent = this;
153
- c.on('end', function () { removeRegisteredApp(this); });
154
- c.on('data', function (chunk) {
155
- if (chunk.length < 4) { this.unshift(chunk); return; }
156
- var len = chunk.readUInt32LE(0);
157
- if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
158
- if (chunk.length < len) { this.unshift(chunk); return; }
159
-
160
- var data = chunk.slice(4, len);
161
- try { data = JSON.parse(data.toString()); } catch (e) { }
162
- if ((data == null) || (typeof data.cmd != 'string')) return;
163
-
164
- try {
165
- switch (data.cmd) {
166
- case 'requesthelp':
167
- if (this._registered == null) return;
168
- sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
169
- var help = {};
170
- help[this._registered] = data.value;
171
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (e) { }
172
- MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
173
- break;
174
- case 'cancelhelp':
175
- if (this._registered == null) return;
176
- sendConsoleText('Cancel Help (' + this._registered + ')');
177
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
178
- break;
179
- case 'register':
180
- if (typeof data.value == 'string') {
181
- this._registered = data.value;
182
- var apps = {};
183
- apps[data.value] = 1;
184
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
185
- this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
186
- }
187
- break;
188
- case 'query':
189
- switch (data.value) {
190
- case 'connection':
191
- data.result = require('MeshAgent').ConnectedServer;
192
- this._send(data);
193
- break;
194
- case 'descriptors':
195
- require('ChainViewer').getSnapshot().then(function (f) {
196
- this.tag.payload.result = f;
197
- this.tag.ipc._send(this.tag.payload);
198
- }).parentPromise.tag = { ipc: this, payload: data };
199
- break;
200
- }
201
- break;
202
- case 'amtstate':
203
- if (amt == null) return;
204
- var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
205
- func.pipe = this;
206
- amt.getAmtInfo(func);
207
- break;
208
- case 'sessions':
209
- this._send({ cmd: 'sessions', sessions: tunnelUserCount });
210
- break;
211
- }
212
- }
213
- catch (e) { removeRegisteredApp(this); this.end(); return; }
214
- });
215
- });
216
-
217
- // Send current sessions to registered apps
218
- function broadcastSessionsToRegisteredApps(x) {
219
- broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
220
- }
221
-
222
- // Send this object to all registered local applications
223
- function broadcastToRegisteredApps(x) {
224
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
225
- for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); } }
226
- }
227
-
228
- // Send list of registered apps to the server
229
- function updateRegisteredAppsToServer() {
230
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
231
- var apps = {};
232
- 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]++; } }
233
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
234
- }
235
-
236
- // Remove a registered app
237
- function removeRegisteredApp(pipe) {
238
- for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
239
- if (pipe._registered != null) updateRegisteredAppsToServer();
240
- }
241
-
242
- function diagnosticAgent_uninstall() {
243
- require('service-manager').manager.uninstallService('meshagentDiagnostic');
244
- require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
245
- };
246
- function diagnosticAgent_installCheck(install) {
247
- try {
248
- var diag = require('service-manager').manager.getService('meshagentDiagnostic');
249
- return (diag);
250
- }
251
- catch (e) {
252
- }
253
- if (!install) { return (null); }
254
-
255
- var svc = null;
256
- try {
257
- require('service-manager').manager.installService(
258
- {
259
- name: 'meshagentDiagnostic',
260
- displayName: "Mesh Agent Diagnostic Service",
261
- description: "Mesh Agent Diagnostic Service",
262
- servicePath: process.execPath,
263
- parameters: ['-recovery']
264
- //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
265
- });
266
- svc = require('service-manager').manager.getService('meshagentDiagnostic');
267
- }
268
- catch (e) {
269
- return (null);
270
- }
271
- var proxyConfig = require('global-tunnel').proxyConfig;
272
- var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
273
- var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
274
- ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
275
- ddb.Put('disableUpdate', '1');
276
- ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
277
- ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
278
- ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
279
- if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
280
- if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
281
- if (proxyConfig) {
282
- ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
283
- } else {
284
- ddb.Put('ignoreProxyFile', '1');
285
- }
286
-
287
- require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
288
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
289
-
290
- delete ddb;
291
-
292
- // Set a recurrent task, to run the Diagnostic Agent every 2 days
293
- 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' });
294
- //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
295
-
296
- return (svc);
297
- }
298
-
299
- // Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
300
- if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
301
- // Setup manual battery monitoring
302
- require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
303
- if (require('MeshAgent')._batteryFileTimer != null) return;
304
- require('MeshAgent')._batteryFileTimer = setTimeout(function () {
305
- try {
306
- require('MeshAgent')._batteryFileTimer = null;
307
- var data = null;
308
- try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
309
- if ((data != null) && (data.length < 10)) {
310
- data = data.split(',');
311
- if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
312
- var level = parseInt(data[1]);
313
- if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
314
- }
315
- }
316
- } catch (e) { }
317
- }, 1000);
318
- });
319
- } else {
320
- // Setup normal battery monitoring
321
- if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) {
322
- require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
323
- _battLevelChanged.self._currentBatteryLevel = val;
324
- _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
325
- };
326
- require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
327
- require('MeshAgent')._powerChanged = function _powerChanged(val) {
328
- _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
329
- _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
330
- };
331
- require('MeshAgent')._powerChanged.self = require('MeshAgent');
332
- require('MeshAgent').on('Connected', function (status) {
333
- if (status == 0) {
334
- require('power-monitor').removeListener('acdc', this._powerChanged);
335
- require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
336
- } else {
337
- require('power-monitor').on('acdc', this._powerChanged);
338
- require('power-monitor').on('batteryLevel', this._battLevelChanged);
339
- }
340
- });
341
- }
342
- }
343
-
344
-
345
- /*
346
- function borderController() {
347
- this.container = null;
348
- this.Start = function Start(user) {
349
- if (this.container == null) {
350
- if (process.platform == 'win32') {
351
- try {
352
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.SessionId });
353
- } catch (e) {
354
- this.container = require('ScriptContainer').Create({ processIsolation: 1 });
355
- }
356
- } else {
357
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.uid });
358
- }
359
- this.container.parent = this;
360
- this.container.addModule('monitor-info', getJSModule('monitor-info'));
361
- this.container.addModule('monitor-border', getJSModule('monitor-border'));
362
- this.container.addModule('promise', getJSModule('promise'));
363
- this.container.once('exit', function (code) { sendConsoleText('Border Process Exited with code: ' + code); this.parent.container = this.parent._container = null; });
364
- this.container.ExecuteString("var border = require('monitor-border'); border.Start();");
365
- }
366
- }
367
- this.Stop = function Stop() {
368
- if (this.container != null) {
369
- this._container = this.container;
370
- this._container.parent = this;
371
- this.container = null;
372
- this._container.exit();
373
- }
374
- }
375
- }
376
- obj.borderManager = new borderController();
377
- */
378
-
379
- // MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
380
- var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? ('MeshCore CRC-' + 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
381
-
382
-
383
- // Get the operating system description string
384
- try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; }); } catch (e) { }
385
-
386
- var meshServerConnectionState = 0;
387
- var tunnels = {};
388
- var lastMeInfo = null;
389
- var lastNetworkInfo = null;
390
- var lastPublicLocationInfo = null;
391
- var selfInfoUpdateTimer = null;
392
- var http = require('http');
393
- var net = require('net');
394
- var fs = require('fs');
395
- var rtc = require('ILibWebRTC');
396
- var amt = null;
397
- var processManager = require('process-manager');
398
- var wifiScannerLib = null;
399
- var wifiScanner = null;
400
- var networkMonitor = null;
401
- var amtscanner = null;
402
- var nextTunnelIndex = 1;
403
- var apftunnel = null;
404
- var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
405
-
406
- // Add to the server event log
407
- function MeshServerLog(msg, state) {
408
- if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
409
- if (state) {
410
- if (state.userid) { msg.userid = state.userid; }
411
- if (state.username) { msg.username = state.username; }
412
- if (state.sessionid) { msg.sessionid = state.sessionid; }
413
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
414
- }
415
- mesh.SendCommand(msg);
416
- }
417
-
418
- // Add to the server event log, use internationalized events
419
- function MeshServerLogEx(id, args, msg, state) {
420
- var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
421
- if (state) {
422
- if (state.userid) { msg.userid = state.userid; }
423
- if (state.username) { msg.username = state.username; }
424
- if (state.sessionid) { msg.sessionid = state.sessionid; }
425
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
426
- }
427
- mesh.SendCommand(msg);
428
- }
429
-
430
- // If we are running in Duktape, agent will be null
431
- if (agent == null) {
432
- // Running in native agent, Import libraries
433
- db = require('SimpleDataStore').Shared();
434
- sha = require('SHA256Stream');
435
- mesh = require('MeshAgent');
436
- childProcess = require('child_process');
437
- if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
438
- // Check if this computer supports a desktop
439
- try
440
- {
441
- if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support))
442
- {
443
- meshCoreObj.caps |= 1;
444
- }
445
- else if(process.platform == 'linux' || process.platform == 'freebsd')
446
- {
447
- require('monitor-info').on('kvmSupportDetected', function (value)
448
- {
449
- meshCoreObj.caps |= 1;
450
- mesh.SendCommand(meshCoreObj);
451
- });
452
- }
453
- } catch (e) { }
454
- }
455
- } else {
456
- // Running in nodejs
457
- meshCoreObj.value += '-NodeJS';
458
- meshCoreObj.caps = 8;
459
- mesh = agent.getMeshApi();
460
- }
461
-
462
- mesh.DAIPC = obj.DAIPC;
463
-
464
- /*
465
- var AMTScanner = require("AMTScanner");
466
- var scan = new AMTScanner();
467
-
468
- scan.on("found", function (data) {
469
- if (typeof data === 'string') {
470
- console.log(data);
471
- } else {
472
- console.log(JSON.stringify(data, null, " "));
473
- }
474
- });
475
- scan.scan("10.2.55.140", 1000);
476
- scan.scan("10.2.55.139-10.2.55.145", 1000);
477
- scan.scan("10.2.55.128/25", 2000);
478
- */
479
-
480
- /*
481
- // Try to load up the network monitor
482
- try {
483
- networkMonitor = require('NetworkMonitor');
484
- networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
485
- networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
486
- networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
487
- } catch (e) { networkMonitor = null; }
488
- */
489
-
490
- // Try to load up the Intel AMT scanner
491
- try {
492
- var AMTScannerModule = require('amt-scanner');
493
- amtscanner = new AMTScannerModule();
494
- //amtscanner.on('found', function (data) { if (typeof data != 'string') { data = JSON.stringify(data, null, " "); } sendConsoleText(data); });
495
- } catch (e) { amtscanner = null; }
496
-
497
- // Fetch the SMBios Tables
498
- var SMBiosTables = null;
499
- var SMBiosTablesRaw = null;
500
- try {
501
- var SMBiosModule = null;
502
- try { SMBiosModule = require('smbios'); } catch (e) { }
503
- if (SMBiosModule != null) {
504
- SMBiosModule.get(function (data) {
505
- if (data != null) {
506
- SMBiosTablesRaw = data;
507
- SMBiosTables = require('smbios').parse(data)
508
- if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
509
-
510
- // If SMBios tables say that Intel AMT is present, try to connect MEI
511
- if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true))
512
- {
513
- var amtmodule = require('amt-manage');
514
- amt = new amtmodule(mesh, db, false);
515
- amt.on('portBinding_LMS', function (map)
516
- {
517
- var j = { action: 'lmsinfo', value: { ports: map.keys() } };
518
- mesh.SendCommand(j);
519
- });
520
- amt.on('stateChange_LMS', function (v)
521
- {
522
- if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; }
523
- switch(v)
524
- {
525
- case 0:
526
- meshCoreObj.intelamt.microlms = 'DISABLED';
527
- break;
528
- case 1:
529
- meshCoreObj.intelamt.microlms = 'CONNECTING';
530
- break;
531
- case 2:
532
- meshCoreObj.intelamt.microlms = 'CONNECTED';
533
- break;
534
- default:
535
- break;
536
- }
537
- mesh.SendCommand(meshCoreObj);
538
- });
539
- amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } }
540
- amt.start();
541
- }
542
- }
543
- });
544
- }
545
- } catch (e) { sendConsoleText("ex1: " + e); }
546
-
547
- // Try to load up the WIFI scanner
548
- try {
549
- var wifiScannerLib = require('wifi-scanner');
550
- wifiScanner = new wifiScannerLib();
551
- wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
552
- } catch (e) { wifiScannerLib = null; wifiScanner = null; }
553
-
554
- // Get our location (lat/long) using our public IP address
555
- var getIpLocationDataExInProgress = false;
556
- var getIpLocationDataExCounts = [0, 0];
557
- function getIpLocationDataEx(func) {
558
- if (getIpLocationDataExInProgress == true) { return false; }
559
- try {
560
- getIpLocationDataExInProgress = true;
561
- getIpLocationDataExCounts[0]++;
562
- var options = http.parseUri("http://ipinfo.io/json");
563
- options.method = 'GET';
564
- http.request(options, function (resp) {
565
- if (resp.statusCode == 200) {
566
- var geoData = '';
567
- resp.data = function (geoipdata) { geoData += geoipdata; };
568
- resp.end = function () {
569
- var location = null;
570
- try {
571
- if (typeof geoData == 'string') {
572
- var result = JSON.parse(geoData);
573
- if (result.ip && result.loc) { location = result; }
574
- }
575
- } catch (e) { }
576
- if (func) { getIpLocationDataExCounts[1]++; func(location); }
577
- }
578
- } else { func(null); }
579
- getIpLocationDataExInProgress = false;
580
- }).end();
581
- return true;
582
- }
583
- catch (e) { return false; }
584
- }
585
-
586
- // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
587
- function clearGatewayMac(str) {
588
- if (str == null) return null;
589
- var x = JSON.parse(str);
590
- for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
591
- return JSON.stringify(x);
592
- }
593
-
594
- function getIpLocationData(func) {
595
- // Get the location information for the cache if possible
596
- var publicLocationInfo = db.Get('publicLocationInfo');
597
- if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
598
- if (publicLocationInfo == null) {
599
- // Nothing in the cache, fetch the data
600
- getIpLocationDataEx(function (locationData) {
601
- if (locationData != null) {
602
- publicLocationInfo = {};
603
- publicLocationInfo.netInfoStr = lastNetworkInfo;
604
- publicLocationInfo.locationData = locationData;
605
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
606
- if (func) func(locationData); // Report the new location
607
- } else {
608
- if (func) func(null); // Report no location
609
- }
610
- });
611
- } else {
612
- // Check the cache
613
- if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
614
- // Cache match
615
- if (func) func(publicLocationInfo.locationData);
616
- } else {
617
- // Cache mismatch
618
- getIpLocationDataEx(function (locationData) {
619
- if (locationData != null) {
620
- publicLocationInfo = {};
621
- publicLocationInfo.netInfoStr = lastNetworkInfo;
622
- publicLocationInfo.locationData = locationData;
623
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
624
- if (func) func(locationData); // Report the new location
625
- } else {
626
- if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
627
- }
628
- });
629
- }
630
- }
631
- }
632
-
633
- // Polyfill String.endsWith
634
- if (!String.prototype.endsWith) {
635
- String.prototype.endsWith = function (searchString, position) {
636
- var subjectString = this.toString();
637
- if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
638
- position -= searchString.length;
639
- var lastIndex = subjectString.lastIndexOf(searchString, position);
640
- return lastIndex !== -1 && lastIndex === position;
641
- };
642
- }
643
-
644
- // Polyfill path.join
645
- obj.path = {
646
- join: function () {
647
- var x = [];
648
- for (var i in arguments) {
649
- var w = arguments[i];
650
- if (w != null) {
651
- while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
652
- if (i != 0) {
653
- while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
654
- }
655
- x.push(w);
656
- }
657
- }
658
- if (x.length == 0) return '/';
659
- return x.join('/');
660
- }
661
- };
662
-
663
- // Replace a string with a number if the string is an exact number
664
- function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
665
-
666
- // Convert decimal to hex
667
- function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
668
-
669
- // Convert a raw string to a hex string
670
- function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
671
-
672
- // Convert a buffer into a string
673
- function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
674
-
675
- // Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
676
- function hex2rstr(d) {
677
- if (typeof d != "string" || d.length == 0) return '';
678
- var r = '', m = ('' + d).match(/../g), t;
679
- while (t = m.shift()) r += String.fromCharCode('0x' + t);
680
- return r
681
- }
682
-
683
- // Convert an object to string with all functions
684
- function objToString(x, p, pad, ret) {
685
- if (ret == undefined) ret = '';
686
- if (p == undefined) p = 0;
687
- if (x == null) { return '[null]'; }
688
- if (p > 8) { return '[...]'; }
689
- if (x == undefined) { return '[undefined]'; }
690
- if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; }
691
- if (typeof x == 'buffer') { return '[buffer]'; }
692
- if (typeof x != 'object') { return x; }
693
- var r = '{' + (ret ? '\r\n' : ' ');
694
- for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
695
- return r + addPad(p, pad) + '}';
696
- }
697
-
698
- // Return p number of spaces
699
- function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
700
-
701
- // Split a string taking into account the quoats. Used for command line parsing
702
- function splitArgs(str) {
703
- var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
704
- do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
705
- return myArray;
706
- }
707
-
708
- // Parse arguments string array into an object
709
- function parseArgs(argv) {
710
- var results = { '_': [] }, current = null;
711
- for (var i = 1, len = argv.length; i < len; i++) {
712
- var x = argv[i];
713
- if (x.length > 2 && x[0] == '-' && x[1] == '-') {
714
- if (current != null) { results[current] = true; }
715
- current = x.substring(2);
716
- } else {
717
- if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
718
- }
719
- }
720
- if (current != null) { results[current] = true; }
721
- return results;
722
- }
723
-
724
- // Get server target url with a custom path
725
- function getServerTargetUrl(path) {
726
- var x = mesh.ServerUrl;
727
- //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
728
- if (x == null) { return null; }
729
- if (path == null) { path = ''; }
730
- x = http.parseUri(x);
731
- if (x == null) return null;
732
- return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
733
- }
734
-
735
- // Get server url. If the url starts with "*/..." change it, it not use the url as is.
736
- function getServerTargetUrlEx(url) {
737
- if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
738
- return url;
739
- }
740
-
741
- // Send a wake-on-lan packet
742
- function sendWakeOnLan(hexMac) {
743
- hexMac = hexMac.split(':').join('');
744
- var count = 0;
745
- try {
746
- var interfaces = require('os').networkInterfaces();
747
- var magic = 'FFFFFFFFFFFF';
748
- for (var x = 1; x <= 16; ++x) { magic += hexMac; }
749
- var magicbin = Buffer.from(magic, 'hex');
750
-
751
- for (var adapter in interfaces) {
752
- if (interfaces.hasOwnProperty(adapter)) {
753
- for (var i = 0; i < interfaces[adapter].length; ++i) {
754
- var addr = interfaces[adapter][i];
755
- if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
756
- try {
757
- var socket = require('dgram').createSocket({ type: 'udp4' });
758
- socket.bind({ address: addr.address });
759
- socket.setBroadcast(true);
760
- socket.setMulticastInterface(addr.address);
761
- socket.setMulticastTTL(1);
762
- socket.send(magicbin, 7, '255.255.255.255');
763
- socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')';
764
- count++;
765
- }
766
- catch (e) { }
767
- }
768
- }
769
- }
770
- }
771
- } catch (e) { }
772
- return count;
773
- }
774
-
775
- // Handle a mesh agent command
776
- function handleServerCommand(data) {
777
- if (typeof data == 'object') {
778
- // If this is a console command, parse it and call the console handler
779
- switch (data.action) {
780
- case 'msg': {
781
- switch (data.type) {
782
- case 'console': { // Process a console command
783
- if (data.value && data.sessionid) {
784
- MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
785
- var args = splitArgs(data.value);
786
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
787
- }
788
- break;
789
- }
790
- case 'tunnel': {
791
- if (data.value != null) { // Process a new tunnel connection request
792
- // Create a new tunnel object
793
- var xurl = getServerTargetUrlEx(data.value);
794
- if (xurl != null) {
795
- xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
796
- var woptions = http.parseUri(xurl);
797
- woptions.perMessageDeflate = false;
798
- if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
799
- woptions.rejectUnauthorized = 0;
800
- //sendConsoleText(JSON.stringify(woptions));
801
- //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
802
- var tunnel = http.request(woptions);
803
- tunnel.upgrade = onTunnelUpgrade;
804
- tunnel.on('error', function (e) { sendConsoleText("ERROR: Unable to connect relay tunnel to: " + this.url + ", " + JSON.stringify(e)); });
805
- tunnel.sessionid = data.sessionid;
806
- tunnel.rights = data.rights;
807
- tunnel.consent = data.consent;
808
- tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}";
809
- tunnel.username = data.username + (data.guestname ? (' - ' + data.guestname) : '');
810
- tunnel.realname = (data.realname ? data.realname : data.username) + (data.guestname ? (' - ' + data.guestname) : '');
811
- tunnel.userid = data.userid;
812
- tunnel.remoteaddr = data.remoteaddr;
813
- tunnel.state = 0;
814
- tunnel.url = xurl;
815
- tunnel.protocol = 0;
816
- tunnel.soptions = data.soptions;
817
- tunnel.tcpaddr = data.tcpaddr;
818
- tunnel.tcpport = data.tcpport;
819
- tunnel.udpaddr = data.udpaddr;
820
- tunnel.udpport = data.udpport;
821
- tunnel.end();
822
- // Put the tunnel in the tunnels list
823
- var index = nextTunnelIndex++;
824
- tunnel.index = index;
825
- tunnels[index] = tunnel;
826
-
827
- //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
828
- }
829
- }
830
- break;
831
- }
832
- case 'messagebox': {
833
- // Display a message box
834
- if (data.title && data.msg) {
835
- MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
836
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
837
- try { require('message-box').create(data.title, data.msg, 120); } catch (e) { }
838
- }
839
- break;
840
- }
841
- case 'ps': {
842
- // Return the list of running processes
843
- if (data.sessionid) {
844
- processManager.getProcesses(function (plist) {
845
- mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
846
- });
847
- }
848
- break;
849
- }
850
- case 'pskill': {
851
- // Kill a process
852
- if (data.value) {
853
- MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
854
- try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
855
- }
856
- break;
857
- }
858
- case 'services': {
859
- // Return the list of installed services
860
- var services = null;
861
- try { services = require('service-manager').manager.enumerateService(); } catch (e) { }
862
- if (services != null) { mesh.SendCommand({ action: 'msg', type: 'services', value: JSON.stringify(services), sessionid: data.sessionid }); }
863
- break;
864
- }
865
- case 'serviceStop': {
866
- // Stop a service
867
- try {
868
- var service = require('service-manager').manager.getService(data.serviceName);
869
- if (service != null) { service.stop(); }
870
- } catch (e) { }
871
- break;
872
- }
873
- case 'serviceStart': {
874
- // Start a service
875
- try {
876
- var service = require('service-manager').manager.getService(data.serviceName);
877
- if (service != null) { service.start(); }
878
- } catch (e) { }
879
- break;
880
- }
881
- case 'serviceRestart': {
882
- // Restart a service
883
- try {
884
- var service = require('service-manager').manager.getService(data.serviceName);
885
- if (service != null) { service.restart(); }
886
- } catch (e) { }
887
- break;
888
- }
889
- case 'deskBackground':
890
- {
891
- // Toggle desktop background
892
- try {
893
- if (process.platform == 'win32') {
894
- var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
895
- var sid = undefined;
896
- if (stype == 1) {
897
- if (require('MeshAgent')._tsid != null) {
898
- stype = 5;
899
- sid = require('MeshAgent')._tsid;
900
- }
901
- }
902
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
903
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: stype, uid: sid });
904
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
905
- child.stderr.on('data', function () { });
906
- child.waitExit();
907
- var current = child.stdout.str.trim();
908
- if (current != '') { require('MeshAgent')._wallpaper = current; }
909
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: stype, uid: sid });
910
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
911
- child.stderr.on('data', function () { });
912
- child.waitExit();
913
- } else {
914
- var id = require('user-sessions').consoleUid();
915
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
916
- if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
917
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
918
- }
919
- } catch (e) {
920
- sendConsoleText(e);
921
- }
922
- break;
923
- }
924
- case 'openUrl': {
925
- // Open a local web browser and return success/fail
926
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
927
- sendConsoleText("OpenURL: " + data.url);
928
- if (data.url) { mesh.SendCommand({ action: 'msg', type: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
929
- break;
930
- }
931
- case 'getclip': {
932
- // Send the load clipboard back to the user
933
- //sendConsoleText('getClip: ' + JSON.stringify(data));
934
- if (require('MeshAgent').isService) {
935
- require('clipboard').dispatchRead().then(function (str) {
936
- if (str) {
937
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
938
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
939
- }
940
- });
941
- } else {
942
- require("clipboard").read().then(function (str) {
943
- if (str) {
944
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
945
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
946
- }
947
- });
948
- }
949
- break;
950
- }
951
- case 'setclip': {
952
- // Set the load clipboard to a user value
953
- //sendConsoleText('setClip: ' + JSON.stringify(data));
954
- if (typeof data.data == 'string') {
955
- MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
956
- if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
957
- mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
958
- }
959
- break;
960
- }
961
- case 'userSessions': {
962
- // Send back current user sessions list, this is Windows only.
963
- //sendConsoleText('userSessions: ' + JSON.stringify(data));
964
- if (process.platform != 'win32') break;
965
- var p = require('user-sessions').enumerateUsers();
966
- p.sessionid = data.sessionid;
967
- p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u, tag: data.tag }); });
968
- break;
969
- }
970
- default:
971
- // Unknown action, ignore it.
972
- break;
973
- }
974
- break;
975
- }
976
- case 'acmactivate': {
977
- if (amt != null) {
978
- MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
979
- amt.setAcmResponse(data);
980
- }
981
- break;
982
- }
983
- case 'wakeonlan': {
984
- // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
985
- sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
986
- for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
987
- break;
988
- }
989
- case 'runcommands': {
990
- if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; }
991
- sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds);
992
-
993
- // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
994
- var options = {};
995
- if (data.runAsUser > 0) {
996
- try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
997
- options.type = require('child_process').SpawnTypes.TERM;
998
- }
999
- if (data.runAsUser == 2) {
1000
- if (options.uid == null) break;
1001
- if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1002
- }
1003
-
1004
- if (process.platform == 'win32') {
1005
- if (data.type == 1) {
1006
- // Windows command shell
1007
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1008
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1009
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1010
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1011
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1012
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1013
- } else if (data.type == 2) {
1014
- // Windows Powershell
1015
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1016
- mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
1017
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1018
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1019
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1020
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1021
- }
1022
- } else if (data.type == 3) {
1023
- // Linux shell
1024
- mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1025
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1026
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1027
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1028
- mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
1029
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1030
- }
1031
- break;
1032
- }
1033
- case 'uninstallagent':
1034
- // Uninstall this agent
1035
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1036
- if (require('service-manager').manager.getService(agentName).isMe()) {
1037
- try { diagnosticAgent_uninstall(); } catch (e) { }
1038
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1039
- 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 });
1040
- }
1041
- break;
1042
- case 'poweraction': {
1043
- // Server telling us to execute a power action
1044
- if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
1045
- var forced = 0;
1046
- if (data.forced == 1) { forced = 1; }
1047
- data.actiontype = parseInt(data.actiontype);
1048
- MeshServerLogEx(25, [data.actiontype, forced], "Performing power action=" + data.actiontype + ", forced=" + forced, data);
1049
- sendConsoleText("Performing power action=" + data.actiontype + ", forced=" + forced + '.');
1050
- var r = mesh.ExecPowerState(data.actiontype, forced);
1051
- sendConsoleText("ExecPowerState returned code: " + r);
1052
- }
1053
- break;
1054
- }
1055
- case 'iplocation': {
1056
- // 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
1057
- getIpLocationData(function (location) { mesh.SendCommand({ action: 'iplocation', type: 'publicip', value: location }); });
1058
- break;
1059
- }
1060
- case 'toast': {
1061
- // Display a toast message
1062
- if (data.title && data.msg) {
1063
- MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1064
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1065
- try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
1066
- }
1067
- break;
1068
- }
1069
- case 'openUrl': {
1070
- // Open a local web browser and return success/fail
1071
- //sendConsoleText('OpenURL: ' + data.url);
1072
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1073
- if (data.url) { mesh.SendCommand({ action: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1074
- break;
1075
- }
1076
- case 'amtconfig': {
1077
- // Perform Intel AMT activation and/or configuration
1078
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'amtconfig' });
1079
- if ((apftunnel != null) || (amt == null)) break;
1080
- getMeiState(15, function (state) {
1081
- if ((state == null) || (state.ProvisioningState == null)) return;
1082
- if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
1083
- var apfarg = {
1084
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
1085
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16), // TODO: User a server provided encrypted cookie for CIRA-LMS login
1086
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
1087
- mpskeepalive: 60000,
1088
- clientname: state.OsHostname,
1089
- clientaddress: '127.0.0.1',
1090
- clientuuid: state.UUID,
1091
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
1092
- meiState: state // MEI state will be passed to MPS server
1093
- };
1094
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'apf-on' });
1095
- apftunnel = require('apfclient')({ debug: false }, apfarg);
1096
- apftunnel.onJsonControl = function (data) {
1097
- if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); } // Display a console message (DEBUG)
1098
- if (data.action == 'mestate') { getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
1099
- if (data.action == 'deactivate') { // Request CCM deactivation
1100
- var amtMeiModule, amtMei;
1101
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { apftunnel.sendMeiDeactivationState(1); return; }
1102
- amtMei.on('error', function (e) { apftunnel.sendMeiDeactivationState(1); });
1103
- amtMei.unprovision(1, function (status) { apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
1104
- }
1105
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
1106
- }
1107
- apftunnel.onChannelClosed = function () { apftunnel = null; require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'apf-off' }); }
1108
- try { apftunnel.connect(); } catch (ex) { }
1109
- });
1110
- break;
1111
- }
1112
- case 'getScript': {
1113
- // Received a configuration script from the server
1114
- sendConsoleText('getScript: ' + JSON.stringify(data));
1115
- break;
1116
- }
1117
- case 'sysinfo': {
1118
- // Fetch system information
1119
- getSystemInformation(function (results) {
1120
- if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1121
- });
1122
- break;
1123
- }
1124
- case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
1125
- case 'pong': { break; }
1126
- case 'plugin': {
1127
- try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; }
1128
- break;
1129
- }
1130
- case 'coredump':
1131
- // Set the current agent coredump situation.
1132
- if (data.value === true) {
1133
- // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1134
- process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
1135
- } else if (data.value === false) {
1136
- process.coreDumpLocation = null;
1137
- }
1138
- break;
1139
- case 'getcoredump':
1140
- // Ask the agent if a core dump is currently available, if yes, also return the hash of the agent.
1141
- var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1142
- var coreDumpPath = null;
1143
- if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1144
- if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath))) { r.exists = (db.Get('CoreDumpTime') != require('fs').statSync(coreDumpPath).mtime); }
1145
- if (r.exists == true) { r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); }
1146
- mesh.SendCommand(JSON.stringify(r));
1147
- default:
1148
- // Unknown action, ignore it.
1149
- break;
1150
- }
1151
- }
1152
- }
1153
-
1154
- // Called when a file changed in the file system
1155
- /*
1156
- function onFileWatcher(a, b) {
1157
- console.log('onFileWatcher', a, b, this.path);
1158
- var response = getDirectoryInfo(this.path);
1159
- if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
1160
- }
1161
- */
1162
-
1163
- function getSystemInformation(func) {
1164
- try {
1165
- var results = { hardware: require('identifiers').get() }; // Hardware info
1166
- if (results.hardware && results.hardware.windows) {
1167
- // Remove extra entries and things that change quickly
1168
- var x = results.hardware.windows.osinfo;
1169
- try { delete x.FreePhysicalMemory; } catch (e) { }
1170
- try { delete x.FreeSpaceInPagingFiles; } catch (e) { }
1171
- try { delete x.FreeVirtualMemory; } catch (e) { }
1172
- try { delete x.LocalDateTime; } catch (e) { }
1173
- try { delete x.MaxProcessMemorySize; } catch (e) { }
1174
- try { delete x.TotalVirtualMemorySize; } catch (e) { }
1175
- try { delete x.TotalVisibleMemorySize; } catch (e) { }
1176
- try {
1177
- if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1178
- if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1179
- if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1180
- } catch (e) { }
1181
- }
1182
- if (process.platform == 'win32') { results.pendingReboot = require('win-info').pendingReboot(); } // Pending reboot
1183
- /*
1184
- if (process.platform == 'win32') {
1185
- var defragResult = function (r) {
1186
- if (typeof r == 'object') { results[this.callname] = r; }
1187
- if (this.callname == 'defrag') {
1188
- var pr = require('win-info').installedApps(); // Installed apps
1189
- pr.callname = 'installedApps';
1190
- pr.sessionid = data.sessionid;
1191
- pr.then(defragResult, defragResult);
1192
- }
1193
- else {
1194
- results.winpatches = require('win-info').qfe(); // Windows patches
1195
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1196
- func(results);
1197
- }
1198
- }
1199
- var pr = require('win-info').defrag({ volume: 'C:' }); // Defrag TODO
1200
- pr.callname = 'defrag';
1201
- pr.sessionid = data.sessionid;
1202
- pr.then(defragResult, defragResult);
1203
- } else {
1204
- */
1205
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1206
- func(results);
1207
- //}
1208
- } catch (e) { func(null, e); }
1209
- }
1210
-
1211
- // Get a formated response for a given directory path
1212
- function getDirectoryInfo(reqpath) {
1213
- var response = { path: reqpath, dir: [] };
1214
- if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
1215
- // List all the drives in the root, or the root itself
1216
- var results = null;
1217
- try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1218
- if (results != null) {
1219
- for (var i = 0; i < results.length; ++i) {
1220
- var drive = { n: results[i].name, t: 1 };
1221
- if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1222
- response.dir.push(drive);
1223
- }
1224
- }
1225
- } else {
1226
- // List all the files and folders in this path
1227
- if (reqpath == '') { reqpath = '/'; }
1228
- var results = null, xpath = obj.path.join(reqpath, '*');
1229
- //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1230
- try { results = fs.readdirSync(xpath); } catch (e) { }
1231
- if (results != null) {
1232
- for (var i = 0; i < results.length; ++i) {
1233
- if ((results[i] != '.') && (results[i] != '..')) {
1234
- var stat = null, p = obj.path.join(reqpath, results[i]);
1235
- //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1236
- try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1237
- if ((stat != null) && (stat != undefined)) {
1238
- if (stat.isDirectory() == true) {
1239
- response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1240
- } else {
1241
- response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1242
- }
1243
- }
1244
- }
1245
- }
1246
- }
1247
- }
1248
- return response;
1249
- }
1250
-
1251
- // Tunnel callback operations
1252
- function onTunnelUpgrade(response, s, head) {
1253
- this.s = s;
1254
- s.httprequest = this;
1255
- s.end = onTunnelClosed;
1256
- s.tunnel = this;
1257
- s.descriptorMetadata = "MeshAgent_relayTunnel";
1258
-
1259
- if (require('MeshAgent').idleTimeout != null)
1260
- {
1261
- s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1262
- s.on('timeout', function ()
1263
- {
1264
- this.ping();
1265
- this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1266
- });
1267
- }
1268
-
1269
- //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1270
-
1271
- if (this.tcpport != null) {
1272
- // This is a TCP relay connection, pause now and try to connect to the target.
1273
- s.pause();
1274
- s.data = onTcpRelayServerTunnelData;
1275
- var connectionOptions = { port: parseInt(this.tcpport) };
1276
- if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
1277
- s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
1278
- s.tcprelay.peerindex = this.index;
1279
-
1280
- // Add the TCP session to the count and update the server
1281
- if (s.httprequest.userid != null) {
1282
- if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
1283
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1284
- broadcastSessionsToRegisteredApps();
1285
- }
1286
- } if (this.udpport != null) {
1287
- // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1288
- s.data = onUdpRelayServerTunnelData;
1289
- s.udprelay = require('dgram').createSocket({ type: 'udp4' });
1290
- s.udprelay.bind({ port: 0 });
1291
- s.udprelay.peerindex = this.index;
1292
- s.udprelay.on('message', onUdpRelayTargetTunnelConnect);
1293
- s.udprelay.udpport = this.udpport;
1294
- s.udprelay.udpaddr = this.udpaddr;
1295
- s.udprelay.first = true;
1296
-
1297
- // Add the UDP session to the count and update the server
1298
- if (s.httprequest.userid != null) {
1299
- if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
1300
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1301
- broadcastSessionsToRegisteredApps();
1302
- }
1303
- } else {
1304
- // This is a normal connect for KVM/Terminal/Files
1305
- s.data = onTunnelData;
1306
- }
1307
- }
1308
-
1309
- // Called when UDP relay data is received // TODO****
1310
- function onUdpRelayTargetTunnelConnect(data) {
1311
- var peerTunnel = tunnels[this.peerindex];
1312
- peerTunnel.s.write(data);
1313
- }
1314
-
1315
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1316
- function onUdpRelayServerTunnelData(data) {
1317
- if (this.udprelay.first === true) {
1318
- delete this.udprelay.first; // Skip the first 'c' that is received.
1319
- } else {
1320
- this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1321
- }
1322
- }
1323
-
1324
- // Called when the TCP relay target is connected
1325
- function onTcpRelayTargetTunnelConnect() {
1326
- var peerTunnel = tunnels[this.peerindex];
1327
- this.pipe(peerTunnel.s); // Pipe Target --> Server
1328
- peerTunnel.s.first = true;
1329
- peerTunnel.s.resume();
1330
- }
1331
-
1332
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1333
- function onTcpRelayServerTunnelData(data) {
1334
- if (this.first == true) {
1335
- this.first = false;
1336
- this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1337
- }
1338
- }
1339
-
1340
- function onTunnelClosed() {
1341
- var tunnel = tunnels[this.httprequest.index];
1342
- if (tunnel == null) return; // Stop duplicate calls.
1343
-
1344
- // If this is a routing session, clean up and send the new session counts.
1345
- if (this.httprequest.userid != null) {
1346
- if (this.httprequest.tcpport != null) {
1347
- if (tunnelUserCount.tcp[this.httprequest.userid] != null) { tunnelUserCount.tcp[this.httprequest.userid]--; if (tunnelUserCount.tcp[this.httprequest.userid] <= 0) { delete tunnelUserCount.tcp[this.httprequest.userid]; } }
1348
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1349
- broadcastSessionsToRegisteredApps();
1350
- } else if (this.httprequest.udpport != null) {
1351
- if (tunnelUserCount.udp[this.httprequest.userid] != null) { tunnelUserCount.udp[this.httprequest.userid]--; if (tunnelUserCount.udp[this.httprequest.userid] <= 0) { delete tunnelUserCount.udp[this.httprequest.userid]; } }
1352
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1353
- broadcastSessionsToRegisteredApps();
1354
- }
1355
- }
1356
-
1357
- // Sent tunnel statistics to the server, only send this if compression was used.
1358
- if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString())) {
1359
- mesh.SendCommand({
1360
- action: 'tunnelCloseStats',
1361
- url: tunnel.url,
1362
- userid: tunnel.userid,
1363
- protocol: tunnel.protocol,
1364
- sessionid: tunnel.sessionid,
1365
- sent: this.bytesSent_uncompressed.toString(),
1366
- sentActual: this.bytesSent_actual.toString(),
1367
- sentRatio: this.bytesSent_ratio,
1368
- received: this.bytesReceived_uncompressed.toString(),
1369
- receivedActual: this.bytesReceived_actual.toString(),
1370
- receivedRatio: this.bytesReceived_ratio
1371
- });
1372
- }
1373
-
1374
- //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1375
- if (this.httprequest.index) { delete tunnels[this.httprequest.index]; }
1376
-
1377
- /*
1378
- // Close the watcher if required
1379
- if (this.httprequest.watcher != undefined) {
1380
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
1381
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
1382
- delete this.httprequest.watcher;
1383
- }
1384
- */
1385
-
1386
- // If there is a upload or download active on this connection, close the file
1387
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
1388
- if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1389
-
1390
- // Clean up WebRTC
1391
- if (this.webrtc != null) {
1392
- 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; }
1393
- if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1394
- try { this.webrtc.close(); } catch (e) { }
1395
- this.webrtc.removeAllListeners('connected');
1396
- this.webrtc.removeAllListeners('disconnected');
1397
- this.webrtc.removeAllListeners('dataChannel');
1398
- delete this.webrtc;
1399
- }
1400
-
1401
- // Clean up WebSocket
1402
- this.removeAllListeners('data');
1403
- }
1404
- function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1405
- function onTunnelData(data) {
1406
- //console.log("OnTunnelData");
1407
- //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1408
-
1409
- // If this is upload data, save it to file
1410
- if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
1411
- // Save the data to file being uploaded.
1412
- if (data[0] == 0) {
1413
- // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1414
- 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.
1415
- } else {
1416
- // If data does not start with zero, save as-is.
1417
- 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.
1418
- }
1419
- this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
1420
- return;
1421
- }
1422
-
1423
- if (this.httprequest.state == 0) {
1424
- // Check if this is a relay connection
1425
- if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1426
- }
1427
- else
1428
- {
1429
- // Handle tunnel data
1430
- 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
1431
- // Take a look at the protocol
1432
- if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1433
- this.httprequest.protocol = parseInt(data);
1434
- if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1435
- if (this.httprequest.protocol == 10) {
1436
- //
1437
- // Basic file transfer
1438
- //
1439
- var stats = null;
1440
- if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1441
- try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1442
- try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1443
- if (this.httprequest.downloadFile) {
1444
- //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1445
- this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1446
- this.httprequest.downloadFile.pipe(this);
1447
- this.httprequest.downloadFile.end = function () { }
1448
- } else {
1449
- //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1450
- this.write(JSON.stringify({ op: 'cancel' }));
1451
- }
1452
- }
1453
- else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
1454
- {
1455
- //
1456
- // Remote Terminal
1457
- //
1458
-
1459
- // Check user access rights for terminal
1460
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1461
- // Disengage this tunnel, user does not have the rights to do this!!
1462
- this.httprequest.protocol = 999999;
1463
- this.httprequest.s.end();
1464
- sendConsoleText("Error: No Terminal Control Rights.");
1465
- return;
1466
- }
1467
-
1468
- this.descriptorMetadata = "Remote Terminal";
1469
-
1470
- if (process.platform == 'win32')
1471
- {
1472
- if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
1473
- {
1474
- this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1475
- this.httprequest.s.end();
1476
- return;
1477
- }
1478
- }
1479
-
1480
- var prom = require('promise');
1481
- this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1482
- this.httprequest.tpromise.that = this;
1483
- this.httprequest.tpromise.httprequest = this.httprequest;
1484
-
1485
- this.end = function ()
1486
- {
1487
- if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1488
- if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
1489
-
1490
- // Remove the terminal session to the count to update the server
1491
- if (this.httprequest.userid != null)
1492
- {
1493
- if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } }
1494
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1495
- broadcastSessionsToRegisteredApps();
1496
- }
1497
-
1498
- if (process.platform == 'win32')
1499
- {
1500
- // Unpipe the web socket
1501
- this.unpipe(this.httprequest._term);
1502
- if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1503
-
1504
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1505
- if (this.rtcchannel)
1506
- {
1507
- this.rtcchannel.unpipe(this.httprequest._term);
1508
- if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1509
- }
1510
-
1511
- // Clean up
1512
- if (this.httprequest._term) { this.httprequest._term.end(); }
1513
- this.httprequest._term = null;
1514
- }
1515
- };
1516
-
1517
- // Perform User-Consent if needed.
1518
- if (this.httprequest.consent && (this.httprequest.consent & 16))
1519
- {
1520
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1521
- var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
1522
- if (this.httprequest.soptions != null) {
1523
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1524
- if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1525
- }
1526
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
1527
- this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1528
- this.httprequest.tpromise._consent.then(
1529
- function ()
1530
- {
1531
- // Success
1532
- MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1533
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1534
- this.retPromise._consent = null;
1535
- this.retPromise._res();
1536
- },
1537
- function (e)
1538
- {
1539
- // Denied
1540
- MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1541
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1542
- this.retPromise._rej(e.toString());
1543
- });
1544
- }
1545
- else
1546
- {
1547
- // User-Consent is not required, so just resolve this promise
1548
- this.httprequest.tpromise._res();
1549
- }
1550
-
1551
-
1552
- this.httprequest.tpromise.then(
1553
- function ()
1554
- {
1555
- this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1556
- this.httprequest.connectionPromise.ws = this.that;
1557
-
1558
- // Start Terminal
1559
- if(process.platform == 'win32')
1560
- {
1561
- try
1562
- {
1563
- var cols = 80, rows = 25;
1564
- if (this.httprequest.xoptions)
1565
- {
1566
- if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1567
- if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1568
- }
1569
-
1570
- if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1571
- {
1572
- // Admin Terminal
1573
- if (require('win-virtual-terminal').supported)
1574
- {
1575
- // ConPTY PseudoTerminal
1576
- // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1577
-
1578
- // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1579
- 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] } });
1580
- this.httprequest._dispatcher.httprequest = this.httprequest;
1581
- this.httprequest._dispatcher.on('connection', function (c)
1582
- {
1583
- if (this.httprequest.connectionPromise.completed)
1584
- {
1585
- c.end();
1586
- }
1587
- else
1588
- {
1589
- this.httprequest.connectionPromise._res(c);
1590
- }
1591
- });
1592
- }
1593
- else
1594
- {
1595
- // Legacy Terminal
1596
- this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1597
- }
1598
- }
1599
- else
1600
- {
1601
- // Logged in user
1602
- var userPromise = require('user-sessions').enumerateUsers();
1603
- userPromise.that = this;
1604
- userPromise.then(function (u)
1605
- {
1606
- var that = this.that;
1607
- if (u.Active.length > 0)
1608
- {
1609
- var username = u.Active[0].Username;
1610
- if (require('win-virtual-terminal').supported)
1611
- {
1612
- // ConPTY PseudoTerminal
1613
- 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] } });
1614
- }
1615
- else
1616
- {
1617
- // Legacy Terminal
1618
- 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] } });
1619
- }
1620
- that.httprequest._dispatcher.ws = that;
1621
- that.httprequest._dispatcher.on('connection', function (c)
1622
- {
1623
- if (this.ws.httprequest.connectionPromise.completed)
1624
- {
1625
- c.end();
1626
- }
1627
- else
1628
- {
1629
- this.ws.httprequest.connectionPromise._res(c);
1630
- }
1631
- });
1632
- }
1633
- });
1634
- }
1635
- }
1636
- catch (e)
1637
- {
1638
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1639
- }
1640
- }
1641
- else
1642
- {
1643
- try
1644
- {
1645
- var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1646
- var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1647
- var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1648
-
1649
- var env = { HISTCONTROL: 'ignoreboth' };
1650
- if (this.httprequest.xoptions)
1651
- {
1652
- if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1653
- if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1654
- }
1655
- var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1656
- if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1657
- {
1658
- if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1659
- this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1660
- }
1661
- else if (bash)
1662
- {
1663
- var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1664
- // Spaces at the beginning of lines are needed to hide commands from the command history
1665
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1666
- this.httprequest.connectionPromise._res(p);
1667
- }
1668
- else if (sh)
1669
- {
1670
- var p = childProcess.execFile(sh, ['sh'], options); // Start sh
1671
- // Spaces at the beginning of lines are needed to hide commands from the command history
1672
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1673
- this.httprequest.connectionPromise._res(p);
1674
- }
1675
- else
1676
- {
1677
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
1678
- }
1679
- }
1680
- catch (e)
1681
- {
1682
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1683
- }
1684
- }
1685
-
1686
- this.httprequest.connectionPromise.then(
1687
- function (term)
1688
- {
1689
- // SUCCESS
1690
- var stdoutstream;
1691
- var stdinstream;
1692
- if (process.platform == 'win32')
1693
- {
1694
- this.ws.httprequest._term = term;
1695
- this.ws.httprequest._term.tunnel = this.ws;
1696
- stdoutstream = stdinstream = term;
1697
- }
1698
- else
1699
- {
1700
- term.descriptorMetadata = 'Remote Terminal';
1701
- this.ws.httprequest.process = term;
1702
- this.ws.httprequest.process.tunnel = this.ws;
1703
- term.stderr.stdout = term.stdout;
1704
- term.stderr.on('data', function (c) { this.stdout.write(c); });
1705
- stdoutstream = term.stdout;
1706
- stdinstream = term.stdin;
1707
- this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
1708
- term.prependListener('exit', function () { this.tunnel.end(); });
1709
- }
1710
-
1711
- this.ws.removeAllListeners('data');
1712
- this.ws.on('data', onTunnelControlData);
1713
-
1714
- stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
1715
- this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
1716
-
1717
- // Add the terminal session to the count to update the server
1718
- if (this.ws.httprequest.userid != null)
1719
- {
1720
- if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
1721
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1722
- broadcastSessionsToRegisteredApps();
1723
- }
1724
-
1725
- // Toast Notification, if required
1726
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
1727
- {
1728
- // User Notifications is required
1729
- var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
1730
- if (this.ws.httprequest.soptions != null) {
1731
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1732
- 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); }
1733
- }
1734
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
1735
- }
1736
- },
1737
- function (e)
1738
- {
1739
- // FAILED to connect terminal
1740
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1741
- this.ws.end();
1742
- });
1743
- },
1744
- function (e)
1745
- {
1746
- // DO NOT start terminal
1747
- this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1748
- this.that.end();
1749
- });
1750
- }
1751
- else if (this.httprequest.protocol == 2)
1752
- {
1753
- //
1754
- // Remote KVM
1755
- //
1756
-
1757
- // Check user access rights for desktop
1758
- if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
1759
- // Disengage this tunnel, user does not have the rights to do this!!
1760
- this.httprequest.protocol = 999999;
1761
- this.httprequest.s.end();
1762
- sendConsoleText("Error: No Desktop Control Rights.");
1763
- return;
1764
- }
1765
-
1766
- this.descriptorMetadata = "Remote KVM";
1767
-
1768
- // Look for a TSID
1769
- var tsid = null;
1770
- if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
1771
- require('MeshAgent')._tsid = tsid;
1772
-
1773
- // Remote desktop using native pipes
1774
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this };
1775
- this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
1776
- this.desktop = this.httprequest.desktop;
1777
-
1778
- // Add ourself to the list of remote desktop sessions
1779
- if (this.httprequest.desktop.kvm.tunnels == null) { this.httprequest.desktop.kvm.tunnels = []; }
1780
- this.httprequest.desktop.kvm.tunnels.push(this);
1781
-
1782
- // Send a metadata update to all desktop sessions
1783
- var users = {};
1784
- if (this.httprequest.desktop.kvm.tunnels != null) {
1785
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1786
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1787
- tunnelUserCount.desktop = users;
1788
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
1789
- broadcastSessionsToRegisteredApps();
1790
- }
1791
-
1792
- this.end = function () {
1793
- --this.desktop.kvm.connectionCount;
1794
-
1795
- // Remove ourself from the list of remote desktop session
1796
- var i = this.desktop.kvm.tunnels.indexOf(this);
1797
- if (i >= 0) { this.desktop.kvm.tunnels.splice(i, 1); }
1798
-
1799
- // Send a metadata update to all desktop sessions
1800
- var users = {};
1801
- if (this.httprequest.desktop.kvm.tunnels != null) {
1802
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1803
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1804
- tunnelUserCount.desktop = users;
1805
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
1806
- broadcastSessionsToRegisteredApps();
1807
- }
1808
-
1809
- // Unpipe the web socket
1810
- try
1811
- {
1812
- this.unpipe(this.httprequest.desktop.kvm);
1813
- this.httprequest.desktop.kvm.unpipe(this);
1814
- }
1815
- catch(e) { }
1816
-
1817
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1818
- if (this.rtcchannel)
1819
- {
1820
- try
1821
- {
1822
- this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
1823
- this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
1824
- }
1825
- catch(e) { }
1826
- }
1827
-
1828
- // Place wallpaper back if needed
1829
- // TODO
1830
-
1831
- if (this.desktop.kvm.connectionCount == 0) {
1832
- // Display a toast message. This may not be supported on all platforms.
1833
- // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
1834
-
1835
- this.httprequest.desktop.kvm.end();
1836
- if (this.httprequest.desktop.kvm.connectionBar) {
1837
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1838
- this.httprequest.desktop.kvm.connectionBar.close();
1839
- this.httprequest.desktop.kvm.connectionBar = null;
1840
- }
1841
- } else {
1842
- for (var i in this.httprequest.desktop.kvm.users) {
1843
- if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar) {
1844
- 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; } }
1845
- this.httprequest.desktop.kvm.users.splice(i, 1);
1846
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1847
- this.httprequest.desktop.kvm.connectionBar.close();
1848
- this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1849
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
1850
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1851
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1852
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1853
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1854
- }
1855
- this.httprequest.desktop.kvm.end();
1856
- });
1857
- break;
1858
- }
1859
- }
1860
- }
1861
- };
1862
- if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
1863
- this.httprequest.desktop.kvm.connectionCount++;
1864
- this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
1865
- this.httprequest.desktop.kvm.users.push(this.httprequest.username);
1866
- this.httprequest.desktop.kvm.rusers.sort();
1867
- this.httprequest.desktop.kvm.users.sort();
1868
- } else {
1869
- this.httprequest.desktop.kvm.connectionCount = 1;
1870
- this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
1871
- this.httprequest.desktop.kvm.users = [this.httprequest.username];
1872
- }
1873
-
1874
- if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
1875
- // If we have remote control rights, pipe the KVM input
1876
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
1877
- } else {
1878
- // We need to only pipe non-mouse & non-keyboard inputs.
1879
- //sendConsoleText('Warning: No Remote Desktop Input Rights.');
1880
- // TODO!!!
1881
- }
1882
-
1883
- // Perform notification if needed. Toast messages may not be supported on all platforms.
1884
- if (this.httprequest.consent && (this.httprequest.consent & 8))
1885
- {
1886
- // User Consent Prompt is required
1887
- // Send a console message back using the console channel, "\n" is supported.
1888
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1889
- var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
1890
- if (this.httprequest.soptions != null) {
1891
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1892
- if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1893
- }
1894
- var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
1895
- pr.ws = this;
1896
- this.pause();
1897
- this._consentpromise = pr;
1898
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }});
1899
- pr.then(
1900
- function ()
1901
- {
1902
- // Success
1903
- this.ws._consentpromise = null;
1904
- MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1905
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1906
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
1907
- // User Notifications is required
1908
- var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1909
- if (this.ws.httprequest.soptions != null) {
1910
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1911
- 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); }
1912
- }
1913
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
1914
- }
1915
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40)) {
1916
- // Connection Bar is required
1917
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
1918
- this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1919
- this.ws.httprequest.desktop.kvm.connectionBar.close();
1920
- }
1921
- try {
1922
- this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1923
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1924
- }
1925
- catch (e) {
1926
- if (process.platform != 'darwin') {
1927
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1928
- }
1929
- }
1930
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
1931
- this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
1932
- this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
1933
- MeshServerLogEx(33, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1934
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1935
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1936
- }
1937
- this.httprequest.desktop.kvm.end();
1938
- });
1939
- }
1940
- }
1941
- this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
1942
- this.ws.resume();
1943
- },
1944
- function (e)
1945
- {
1946
- // User Consent Denied/Failed
1947
- this.ws._consentpromise = null;
1948
- MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1949
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1950
- });
1951
- } else {
1952
- // User Consent Prompt is not required
1953
- if (this.httprequest.consent && (this.httprequest.consent & 1)) {
1954
- // User Notifications is required
1955
- MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1956
- var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1957
- if (this.httprequest.soptions != null) {
1958
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
1959
- if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1960
- }
1961
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
1962
- } else {
1963
- MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1964
- }
1965
- if (this.httprequest.consent && (this.httprequest.consent & 0x40)) {
1966
- // Connection Bar is required
1967
- if (this.httprequest.desktop.kvm.connectionBar) {
1968
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1969
- this.httprequest.desktop.kvm.connectionBar.close();
1970
- }
1971
- try {
1972
- 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);
1973
- MeshServerLogEx(37, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
1974
- }
1975
- catch (e) {
1976
- MeshServerLogEx(38, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
1977
- }
1978
- if (this.httprequest.desktop.kvm.connectionBar) {
1979
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
1980
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1981
- MeshServerLogEx(39, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1982
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1983
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1984
- }
1985
- this.httprequest.desktop.kvm.end();
1986
- });
1987
- }
1988
- }
1989
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
1990
- }
1991
-
1992
- this.removeAllListeners('data');
1993
- this.on('data', onTunnelControlData);
1994
- //this.write('MeshCore KVM Hello!1');
1995
-
1996
- } else if (this.httprequest.protocol == 5) {
1997
- //
1998
- // Remote Files
1999
- //
2000
-
2001
- // Check user access rights for files
2002
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
2003
- // Disengage this tunnel, user does not have the rights to do this!!
2004
- this.httprequest.protocol = 999999;
2005
- this.httprequest.s.end();
2006
- sendConsoleText("Error: No files control rights.");
2007
- return;
2008
- }
2009
-
2010
- this.descriptorMetadata = "Remote Files";
2011
-
2012
- // Add the files session to the count to update the server
2013
- if (this.httprequest.userid != null) {
2014
- if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
2015
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2016
- broadcastSessionsToRegisteredApps();
2017
- }
2018
-
2019
- this.end = function () {
2020
- // Remove the files session from the count to update the server
2021
- if (this.httprequest.userid != null) {
2022
- if (tunnelUserCount.files[this.httprequest.userid] != null) { tunnelUserCount.files[this.httprequest.userid]--; if (tunnelUserCount.files[this.httprequest.userid] <= 0) { delete tunnelUserCount.files[this.httprequest.userid]; } }
2023
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2024
- broadcastSessionsToRegisteredApps();
2025
- }
2026
- };
2027
-
2028
- // Perform notification if needed. Toast messages may not be supported on all platforms.
2029
- if (this.httprequest.consent && (this.httprequest.consent & 32)) {
2030
- // User Consent Prompt is required
2031
- // Send a console message back using the console channel, "\n" is supported.
2032
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2033
- var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
2034
- if (this.httprequest.soptions != null) {
2035
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2036
- if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2037
- }
2038
- var pr = require('message-box').create(consentTitle, consentMessage, 30);
2039
- pr.ws = this;
2040
- this.pause();
2041
- this._consentpromise = pr;
2042
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2043
- pr.then(
2044
- function ()
2045
- {
2046
- // Success
2047
- this.ws._consentpromise = null;
2048
- MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2049
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2050
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
2051
- // User Notifications is required
2052
- var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2053
- if (this.ws.httprequest.soptions != null) {
2054
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2055
- 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); }
2056
- }
2057
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2058
- }
2059
- this.ws.resume();
2060
- },
2061
- function (e)
2062
- {
2063
- // User Consent Denied/Failed
2064
- this.ws._consentpromise = null;
2065
- MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2066
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2067
- });
2068
- } else {
2069
- // User Consent Prompt is not required
2070
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
2071
- // User Notifications is required
2072
- MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2073
- var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2074
- if (this.httprequest.soptions != null) {
2075
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2076
- if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2077
- }
2078
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2079
- } else {
2080
- MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2081
- }
2082
- this.resume();
2083
- }
2084
-
2085
- // Setup files
2086
- // NOP
2087
- }
2088
- } else if (this.httprequest.protocol == 1) {
2089
- // Send data into terminal stdin
2090
- //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2091
- } else if (this.httprequest.protocol == 2) {
2092
- // Send data into remote desktop
2093
- if (this.httprequest.desktop.state == 0) {
2094
- this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2095
- this.httprequest.desktop.state = 1;
2096
- } else {
2097
- this.httprequest.desktop.write(data);
2098
- }
2099
- } else if (this.httprequest.protocol == 5) {
2100
- // Process files commands
2101
- var cmd = null;
2102
- try { cmd = JSON.parse(data); } catch (e) { };
2103
- if (cmd == null) { return; }
2104
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2105
- if (cmd.action == undefined) { return; }
2106
- //sendConsoleText('CMD: ' + JSON.stringify(cmd));
2107
-
2108
- if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2109
- //console.log(objToString(cmd, 0, ' '));
2110
- switch (cmd.action) {
2111
- case 'ls': {
2112
- /*
2113
- // Close the watcher if required
2114
- var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
2115
- if ((this.httprequest.watcher != undefined) && (samepath == false)) {
2116
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
2117
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
2118
- delete this.httprequest.watcher;
2119
- }
2120
- */
2121
-
2122
- // Send the folder content to the browser
2123
- var response = getDirectoryInfo(cmd.path);
2124
- if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
2125
- this.write(Buffer.from(JSON.stringify(response)));
2126
-
2127
- /*
2128
- // Start the directory watcher
2129
- if ((cmd.path != '') && (samepath == false)) {
2130
- var watcher = fs.watch(cmd.path, onFileWatcher);
2131
- watcher.tunnel = this.httprequest;
2132
- watcher.path = cmd.path;
2133
- this.httprequest.watcher = watcher;
2134
- //console.log('Starting watcher: ' + this.httprequest.watcher.path);
2135
- }
2136
- */
2137
- break;
2138
- }
2139
- case 'mkdir': {
2140
- // Create a new empty folder
2141
- fs.mkdirSync(cmd.path);
2142
- MeshServerLogEx(44, [cmd.path], "Create folder: \"" + cmd.path + "\"", this.httprequest);
2143
- break;
2144
- }
2145
- case 'rm': {
2146
- // Delete, possibly recursive delete
2147
- for (var i in cmd.delfiles) {
2148
- var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2149
- try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2150
- if ((delcount == 1) && !cmd.rec) {
2151
- MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2152
- } else {
2153
- if (cmd.rec) {
2154
- MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2155
- } else {
2156
- MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2157
- }
2158
- }
2159
- }
2160
- break;
2161
- }
2162
- case 'markcoredump': {
2163
- // If we are asking for the coredump file, set the right path.
2164
- var coreDumpPath = null;
2165
- if (process.platform == 'win32') {
2166
- if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2167
- } else {
2168
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2169
- }
2170
- if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
2171
- break;
2172
- }
2173
- case 'rename': {
2174
- // Rename a file or folder
2175
- var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
2176
- var newfullpath = obj.path.join(cmd.path, cmd.newname);
2177
- MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
2178
- try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
2179
- break;
2180
- }
2181
- case 'download': {
2182
- // Download a file
2183
- var sendNextBlock = 0;
2184
- if (cmd.sub == 'start') { // Setup the download
2185
- if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
2186
- if (process.platform == 'win32') {
2187
- if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2188
- } else {
2189
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2190
- }
2191
- }
2192
- MeshServerLogEx(49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
2193
- if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2194
- this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2195
- 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; }
2196
- if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2197
- } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
2198
- 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; }
2199
- }
2200
- // Send the next download block(s)
2201
- while (sendNextBlock > 0) {
2202
- sendNextBlock--;
2203
- var buf = Buffer.alloc(16384);
2204
- var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
2205
- this.filedownload.ptr += len;
2206
- if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
2207
- this.write(buf.slice(0, len + 4)); // Write as binary
2208
- }
2209
- break;
2210
- }
2211
- /*
2212
- case 'download': {
2213
- // Packet download of a file, agent to browser
2214
- if (cmd.path == undefined) break;
2215
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2216
- //console.log('Download: ' + filepath);
2217
- try { this.httprequest.downloadFile = fs.openSync(filepath, 'rbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'downloaderror', reqid: cmd.reqid }))); break; }
2218
- this.httprequest.downloadFileId = cmd.reqid;
2219
- this.httprequest.downloadFilePtr = 0;
2220
- if (this.httprequest.downloadFile) { this.write(Buffer.from(JSON.stringify({ action: 'downloadstart', reqid: this.httprequest.downloadFileId }))); }
2221
- break;
2222
- }
2223
- case 'download2': {
2224
- // Stream download of a file, agent to browser
2225
- if (cmd.path == undefined) break;
2226
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2227
- try { this.httprequest.downloadFile = fs.createReadStream(filepath, { flags: 'rbN' }); } catch (e) { console.log(e); }
2228
- this.httprequest.downloadFile.pipe(this);
2229
- this.httprequest.downloadFile.end = function () { }
2230
- break;
2231
- }
2232
- */
2233
- case 'upload': {
2234
- // Upload a file, browser to agent
2235
- if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
2236
- if (cmd.path == undefined) break;
2237
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2238
- this.httprequest.uploadFilePath = filepath;
2239
- MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
2240
- try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
2241
- this.httprequest.uploadFileid = cmd.reqid;
2242
- if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
2243
- break;
2244
- }
2245
- case 'uploaddone': {
2246
- // Indicates that an upload is done
2247
- if (this.httprequest.uploadFile) {
2248
- fs.closeSync(this.httprequest.uploadFile);
2249
- this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2250
- delete this.httprequest.uploadFile;
2251
- delete this.httprequest.uploadFileid;
2252
- delete this.httprequest.uploadFilePath;
2253
- }
2254
- break;
2255
- }
2256
- case 'uploadcancel': {
2257
- // Indicates that an upload is canceled
2258
- if (this.httprequest.uploadFile) {
2259
- fs.closeSync(this.httprequest.uploadFile);
2260
- fs.unlinkSync(this.httprequest.uploadFilePath);
2261
- this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2262
- delete this.httprequest.uploadFile;
2263
- delete this.httprequest.uploadFileid;
2264
- delete this.httprequest.uploadFilePath;
2265
- }
2266
- break;
2267
- }
2268
- case 'copy': {
2269
- // Copy a bunch of files from scpath to dspath
2270
- for (var i in cmd.names) {
2271
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2272
- MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2273
- if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
2274
- }
2275
- break;
2276
- }
2277
- case 'move': {
2278
- // Move a bunch of files from scpath to dspath
2279
- for (var i in cmd.names) {
2280
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2281
- MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2282
- if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
2283
- }
2284
- break;
2285
- }
2286
- case 'zip':
2287
- // Zip a bunch of files
2288
- if (this.zip != null) return; // Zip operating is currently running, exit now.
2289
-
2290
- // Check that the specified files exist & build full paths
2291
- var fp, stat, p = [];
2292
- 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); } }
2293
- if (p.length == 0) return; // No files, quit now.
2294
-
2295
- // Setup file compression
2296
- var ofile = cmd.path + '/' + cmd.output;
2297
- this.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zipping' })));
2298
- this.zipfile = ofile;
2299
- delete this.zipcancel;
2300
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2301
- out.xws = this;
2302
- out.on('close', function () {
2303
- this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2304
- this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2305
- if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
2306
- delete this.xws.zipcancel;
2307
- delete this.xws.zipfile;
2308
- delete this.xws.zip;
2309
- });
2310
- this.zip = require('zip-writer').write({ files: p, basePath: cmd.path });
2311
- this.zip.xws = this;
2312
- 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));
2313
- this.zip.pipe(out);
2314
- break;
2315
- case 'cancel':
2316
- // Cancel zip operation if present
2317
- try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (e) { }
2318
- this.zip = null;
2319
- break;
2320
- default:
2321
- // Unknown action, ignore it.
2322
- break;
2323
- }
2324
- } else if (this.httprequest.protocol == 7) { // Plugin data exchange
2325
- var cmd = null;
2326
- try { cmd = JSON.parse(data); } catch (e) { };
2327
- if (cmd == null) { return; }
2328
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2329
- if (cmd.action == undefined) return;
2330
-
2331
- switch (cmd.action) {
2332
- case 'plugin': {
2333
- try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2334
- break;
2335
- }
2336
- default: {
2337
- // probably shouldn't happen, but just in case this feature is expanded
2338
- }
2339
- }
2340
-
2341
- }
2342
- //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
2343
- }
2344
- }
2345
-
2346
- // Delete a directory with a files and directories within it
2347
- function deleteFolderRecursive(path, rec) {
2348
- var count = 0;
2349
- if (fs.existsSync(path)) {
2350
- if (rec == true) {
2351
- fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
2352
- var curPath = obj.path.join(path, file);
2353
- if (fs.statSync(curPath).isDirectory()) { // recurse
2354
- count += deleteFolderRecursive(curPath, true);
2355
- } else { // delete file
2356
- fs.unlinkSync(curPath);
2357
- count++;
2358
- }
2359
- });
2360
- }
2361
- fs.unlinkSync(path);
2362
- count++;
2363
- }
2364
- return count;
2365
- };
2366
-
2367
- // Called when receiving control data on WebRTC
2368
- function onTunnelWebRTCControlData(data) {
2369
- if (typeof data != 'string') return;
2370
- var obj;
2371
- try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2372
- if (obj.type == 'close') {
2373
- //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2374
- try { this.close(); } catch (e) { }
2375
- try { this.xrtc.close(); } catch (e) { }
2376
- }
2377
- }
2378
-
2379
- // Called when receiving control data on websocket
2380
- function onTunnelControlData(data, ws) {
2381
- var obj;
2382
- if (ws == null) { ws = this; }
2383
- if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
2384
- else if (typeof data == 'object') { obj = data; } else { return; }
2385
- //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2386
- //console.log('onTunnelControlData: ' + JSON.stringify(data));
2387
-
2388
- if (obj.action) {
2389
- switch (obj.action) {
2390
- case 'lock': {
2391
- // Lock the current user out of the desktop
2392
- try {
2393
- if (process.platform == 'win32') {
2394
- MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
2395
- var child = require('child_process');
2396
- child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
2397
- }
2398
- } catch (e) { }
2399
- break;
2400
- }
2401
- default:
2402
- // Unknown action, ignore it.
2403
- break;
2404
- }
2405
- return;
2406
- }
2407
-
2408
- switch (obj.type) {
2409
- case 'options': {
2410
- // These are additional connection options passed in the control channel.
2411
- //sendConsoleText('options: ' + JSON.stringify(obj));
2412
- delete obj.type;
2413
- ws.httprequest.xoptions = obj;
2414
-
2415
- // Set additional user consent options if present
2416
- if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
2417
-
2418
- break;
2419
- }
2420
- case 'close': {
2421
- // We received the close on the websocket
2422
- //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
2423
- try { ws.close(); } catch (e) { }
2424
- break;
2425
- }
2426
- case 'termsize': {
2427
- // Indicates a change in terminal size
2428
- if (process.platform == 'win32')
2429
- {
2430
- if (ws.httprequest._dispatcher == null) return;
2431
- //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
2432
- if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
2433
- } else
2434
- {
2435
- if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
2436
- //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
2437
-
2438
- if (ws.httprequest.process.tcsetsize) { ws.httprequest.process.tcsetsize(obj.rows, obj.cols); }
2439
- }
2440
- break;
2441
- }
2442
- case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
2443
- if (ws.httprequest.protocol == 1) { // Terminal
2444
- // 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
2445
- if (process.platform == 'win32') {
2446
- ws.httprequest._term.unpipe(ws);
2447
- } else {
2448
- ws.httprequest.process.stdout.unpipe(ws);
2449
- ws.httprequest.process.stderr.unpipe(ws);
2450
- }
2451
- } else if (ws.httprequest.protocol == 2) { // Desktop
2452
- // 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
2453
- ws.httprequest.desktop.kvm.unpipe(ws);
2454
- } else {
2455
- // Switch things around so all WebRTC data goes to onTunnelData().
2456
- ws.rtcchannel.httprequest = ws.httprequest;
2457
- ws.rtcchannel.removeAllListeners('data');
2458
- ws.rtcchannel.on('data', onTunnelData);
2459
- }
2460
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // End of data marker
2461
- break;
2462
- }
2463
- case 'webrtc1': {
2464
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2465
- // Switch the user input from websocket to webrtc at this point.
2466
- if (process.platform == 'win32') {
2467
- ws.unpipe(ws.httprequest._term);
2468
- ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2469
- } else {
2470
- ws.unpipe(ws.httprequest.process.stdin);
2471
- ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2472
- }
2473
- ws.resume(); // Resume the websocket to keep receiving control data
2474
- } else if (ws.httprequest.protocol == 2) { // Desktop
2475
- // Switch the user input from websocket to webrtc at this point.
2476
- ws.unpipe(ws.httprequest.desktop.kvm);
2477
- try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
2478
- ws.resume(); // Resume the websocket to keep receiving control data
2479
- }
2480
- ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
2481
- break;
2482
- }
2483
- case 'webrtc2': {
2484
- // Other side received websocket end of data marker, start sending data on WebRTC channel
2485
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2486
- if (process.platform == 'win32') {
2487
- ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2488
- } else {
2489
- ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2490
- ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2491
- }
2492
- } else if (ws.httprequest.protocol == 2) { // Desktop
2493
- ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2494
- }
2495
- break;
2496
- }
2497
- case 'offer': {
2498
- // This is a WebRTC offer.
2499
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) return; // TODO: Terminal is currently broken with WebRTC. Reject WebRTC upgrade for now.
2500
- ws.webrtc = rtc.createConnection();
2501
- ws.webrtc.websocket = ws;
2502
- ws.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
2503
- ws.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
2504
- ws.webrtc.on('dataChannel', function (rtcchannel) {
2505
- //sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
2506
- rtcchannel.maxFragmentSize = 32768;
2507
- rtcchannel.xrtc = this;
2508
- rtcchannel.websocket = this.websocket;
2509
- this.rtcchannel = rtcchannel;
2510
- this.websocket.rtcchannel = rtcchannel;
2511
- this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
2512
- this.websocket.rtcchannel.on('end', function () {
2513
- // The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes.
2514
- //sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');
2515
- if (this.websocket.desktop && this.websocket.desktop.kvm)
2516
- {
2517
- try
2518
- {
2519
- this.unpipe(this.websocket.desktop.kvm);
2520
- this.websocket.httprequest.desktop.kvm.unpipe(this);
2521
- }
2522
- catch (e) { }
2523
- }
2524
- });
2525
- this.websocket.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc0\"}'); // Indicate we are ready for WebRTC switch-over.
2526
- });
2527
- var sdp = null;
2528
- try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (e) { }
2529
- if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
2530
- break;
2531
- }
2532
- case 'ping': {
2533
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"pong\"}"); // Send pong response
2534
- break;
2535
- }
2536
- case 'pong': { // NOP
2537
- break;
2538
- }
2539
- case 'rtt': {
2540
- ws.write({ type: 'rtt', ctrlChannel: '102938', time: obj.time });
2541
- break;
2542
- }
2543
- }
2544
- }
2545
-
2546
- // Console state
2547
- var consoleWebSockets = {};
2548
- var consoleHttpRequest = null;
2549
-
2550
- // Console HTTP response
2551
- function consoleHttpResponse(response) {
2552
- response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
2553
- response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; }
2554
- };
2555
-
2556
- // Open a web browser to a specified URL on current user's desktop
2557
- function openUserDesktopUrl(url) {
2558
- if ((url.toLowerCase().startsWith('http://') == false) && (url.toLowerCase().startsWith('https://') == false)) { return null; }
2559
- var child = null;
2560
- try {
2561
- switch (process.platform) {
2562
- case 'win32':
2563
- var user = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2564
- child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd']);
2565
- child.stderr.on('data', function () { });
2566
- child.stdout.on('data', function () { });
2567
- child.stdin.write('SCHTASKS /CREATE /F /TN MeshChatTask /SC ONCE /ST 00:00 /RU ' + user + ' /TR "' + process.env['windir'] + '\\system32\\cmd.exe /C START ' + url + '"\r\n');
2568
- child.stdin.write('SCHTASKS /RUN /TN MeshChatTask\r\n');
2569
- child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\n');
2570
- child.stdin.write('exit\r\n');
2571
- child.waitExit();
2572
- break;
2573
- case 'linux':
2574
- child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { uid: require('user-sessions').consoleUid() });
2575
- break;
2576
- case 'darwin':
2577
- child = require('child_process').execFile('/usr/bin/open', ['open', url], { uid: require('user-sessions').consoleUid() });
2578
- break;
2579
- default:
2580
- // Unknown platform, ignore this command.
2581
- break;
2582
- }
2583
- } catch (e) { }
2584
- return child;
2585
- }
2586
-
2587
- // Process a mesh agent console command
2588
- function processConsoleCommand(cmd, args, rights, sessionid) {
2589
- try {
2590
- var response = null;
2591
- switch (cmd) {
2592
- case 'help': { // Displays available commands
2593
- var fin = '', f = '', availcommands = 'amtconfig,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg';
2594
- if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
2595
- if (process.platform != 'freebsd') { availcommands += ',vm';}
2596
- if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
2597
- try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { }
2598
-
2599
- availcommands = availcommands.split(',').sort();
2600
- while (availcommands.length > 0) {
2601
- if (f.length > 90) { fin += (f + ',\r\n'); f = ''; }
2602
- f += (((f != '') ? ', ' : ' ') + availcommands.shift());
2603
- }
2604
- if (f != '') { fin += f; }
2605
- response = "Available commands: \r\n" + fin + ".";
2606
- break;
2607
- }
2608
- case 'agentmsg': {
2609
- if (args['_'].length == 0) {
2610
- response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage
2611
- } else {
2612
- if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
2613
- var msgIndex = 1, iconIndex = 0;
2614
- while (tunnelUserCount.msg[msgIndex] != null) { msgIndex++; }
2615
- if (args['_'].length >= 3) { try { iconIndex = parseInt(args['_'][2]); } catch (e) { } }
2616
- if (typeof iconIndex != 'number') { iconIndex = 0; }
2617
- tunnelUserCount.msg[msgIndex] = { msg: args['_'][1], icon: iconIndex };
2618
- response = 'Agent message ' + msgIndex + ' added.';
2619
- } else if ((args['_'][0] == 'remove') && (args['_'].length > 1)) {
2620
- var msgIndex = 0;
2621
- try { msgIndex = parseInt(args['_'][1]); } catch (x) { }
2622
- if (tunnelUserCount.msg[msgIndex] == null) { response = "Message not found."; } else { delete tunnelUserCount.msg[msgIndex]; response = "Message removed."; }
2623
- } else if (args['_'][0] == 'list') {
2624
- response = JSON.stringify(tunnelUserCount.msg, null, 2);
2625
- }
2626
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
2627
- broadcastSessionsToRegisteredApps();
2628
- }
2629
- break;
2630
- }
2631
- case 'clearagentmsg': {
2632
- tunnelUserCount.msg = {};
2633
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
2634
- broadcastSessionsToRegisteredApps();
2635
- break;
2636
- }
2637
- case 'coredump':
2638
- if (args['_'].length != 1) {
2639
- response = "Proper usage: coredump on|off|status|clear"; // Display usage
2640
- } else {
2641
- switch (args['_'][0].toLowerCase())
2642
- {
2643
- case 'on':
2644
- process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
2645
- response = 'coredump is now on';
2646
- break;
2647
- case 'off':
2648
- process.coreDumpLocation = null;
2649
- response = 'coredump is now off';
2650
- break;
2651
- case 'status':
2652
- response = 'coredump is: ' + ((process.coreDumpLocation == null) ? 'off' : 'on');
2653
- if (process.coreDumpLocation != null) {
2654
- if (process.platform == 'win32') {
2655
- if (fs.existsSync(process.coreDumpLocation)) { response += '\r\n CoreDump present at: ' + process.coreDumpLocation; }
2656
- } else {
2657
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { response += '\r\n CoreDump present at: ' + process.cwd() + 'core'; }
2658
- }
2659
- }
2660
- break;
2661
- case 'clear':
2662
- db.Put('CoreDumpTime', null);
2663
- response = 'coredump db cleared';
2664
- break;
2665
- default:
2666
- response = "Proper usage: coredump on|off|status"; // Display usage
2667
- break;
2668
- }
2669
- }
2670
- break;
2671
- case 'service':
2672
- if (args['_'].length != 1)
2673
- {
2674
- response = "Proper usage: service status|restart"; // Display usage
2675
- }
2676
- else
2677
- {
2678
- var s = require('service-manager').manager.getService(process.platform == 'win32' ? 'Mesh Agent' : 'meshagent');
2679
- switch(args['_'][0].toLowerCase())
2680
- {
2681
- case 'status':
2682
- response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]'));
2683
- break;
2684
- case 'restart':
2685
- if (s.isMe())
2686
- {
2687
- s.restart();
2688
- }
2689
- else
2690
- {
2691
- response = 'Restarting another agent instance is not allowed';
2692
- }
2693
- break;
2694
- default:
2695
- response = "Proper usage: service status|restart"; // Display usage
2696
- break;
2697
- }
2698
- if (process.platform == 'win32') { s.close(); }
2699
- }
2700
- break;
2701
- case 'zip':
2702
- if (args['_'].length == 0) {
2703
- response = "Proper usage: zip (output file name), input1 [, input n]"; // Display usage
2704
- } else {
2705
- var p = args['_'].join(' ').split(',');
2706
- var ofile = p.shift();
2707
- sendConsoleText('Writing ' + ofile + '...');
2708
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2709
- out.fname = ofile;
2710
- out.sessionid = sessionid;
2711
- out.on('close', function () { sendConsoleText('DONE writing ' + this.fname, this.sessionid); });
2712
- var zip = require('zip-writer').write({ files: p });
2713
- zip.pipe(out);
2714
- }
2715
- break;
2716
- case 'unzip':
2717
- if (args['_'].length == 0) {
2718
- response = "Proper usage: unzip input, destination"; // Display usage
2719
- } else {
2720
- var p = args['_'].join(' ').split(',');
2721
- if (p.length != 2) { response = "Proper usage: unzip input, destination"; break; } // Display usage
2722
- var prom = require('zip-reader').read(p[0]);
2723
- prom._dest = p[1];
2724
- prom.self = this;
2725
- prom.sessionid = sessionid;
2726
- prom.then(function (zipped) {
2727
- sendConsoleText('Extracting to ' + this._dest + '...', this.sessionid);
2728
- zipped.extractAll(this._dest).then(function () { sendConsoleText('finished unzipping', this.sessionid); }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); }).parentPromise.sessionid = this.sessionid;
2729
- }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); });
2730
- }
2731
- break;
2732
- case 'setbattery':
2733
- // require('MeshAgent').SendCommand({ action: 'battery', state: 'dc', level: 55 });
2734
- if ((args['_'].length > 0) && ((args['_'][0] == 'ac') || (args['_'][0] == 'dc'))) {
2735
- var b = { action: 'battery', state: args['_'][0] };
2736
- if (args['_'].length == 2) { b.level = parseInt(args['_'][1]); }
2737
- require('MeshAgent').SendCommand(b);
2738
- } else {
2739
- require('MeshAgent').SendCommand({ action: 'battery' });
2740
- }
2741
- break;
2742
- case 'fdsnapshot':
2743
- require('ChainViewer').getSnapshot().then(function (c) { sendConsoleText(c, this.sessionid); }).parentPromise.sessionid = sessionid;
2744
- break;
2745
- case 'fdcount':
2746
- require('DescriptorEvents').getDescriptorCount().then(
2747
- function (c)
2748
- {
2749
- sendConsoleText('Descriptor Count: ' + c, this.sessionid);
2750
- }, function (e)
2751
- {
2752
- sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid);
2753
- }).parentPromise.sessionid = sessionid;
2754
- break;
2755
- case 'uac':
2756
- if (process.platform != 'win32')
2757
- {
2758
- response = 'Unknown command "uac", type "help" for list of avaialble commands.';
2759
- break;
2760
- }
2761
- if (args['_'].length != 1)
2762
- {
2763
- response = 'Proper usage: uac [get|interactive|secure]';
2764
- }
2765
- else
2766
- {
2767
- switch(args['_'][0].toUpperCase())
2768
- {
2769
- case 'GET':
2770
- var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop');
2771
- response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop");
2772
- break;
2773
- case 'INTERACTIVE':
2774
- try
2775
- {
2776
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0);
2777
- response = 'UAC mode changed to: Interactive Desktop';
2778
- }
2779
- catch (e)
2780
- {
2781
- response = "Unable to change UAC Mode";
2782
- }
2783
- break;
2784
- case 'SECURE':
2785
- try
2786
- {
2787
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1);
2788
- response = 'UAC mode changed to: Secure Desktop';
2789
- }
2790
- catch(e)
2791
- {
2792
- response = "Unable to change UAC Mode";
2793
- }
2794
- break;
2795
- default:
2796
- response = 'Proper usage: uac [get|interactive|secure]';
2797
- break;
2798
- }
2799
- }
2800
- break;
2801
- case 'vm':
2802
- response = 'Virtual Machine = ' + require('identifiers').isVM();
2803
- break;
2804
- case 'startupoptions':
2805
- response = JSON.stringify(require('MeshAgent').getStartupOptions());
2806
- break;
2807
- case 'kvmmode':
2808
- if (require('MeshAgent').maxKvmTileSize == null)
2809
- {
2810
- response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands.";
2811
- }
2812
- else
2813
- {
2814
- if(require('MeshAgent').maxKvmTileSize == 0)
2815
- {
2816
- response = 'KVM Mode: Full JUMBO';
2817
- }
2818
- else
2819
- {
2820
- response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO');
2821
- response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize/1024) + ' Kbytes')));
2822
- }
2823
- }
2824
- break;
2825
- case 'alert':
2826
- if (args['_'].length == 0)
2827
- {
2828
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2829
- }
2830
- else
2831
- {
2832
- var p = args['_'].join(' ').split(',');
2833
- if(p.length<2)
2834
- {
2835
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2836
- }
2837
- else
2838
- {
2839
- this._alert = require('message-box').create(p[0], p[1], p.length==3?parseInt(p[2]):9999,1);
2840
- }
2841
- }
2842
- break;
2843
- case 'agentsize':
2844
- var actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
2845
- if (process.platform == 'win32') {
2846
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
2847
- var writtenSize = 0;
2848
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { response = e; }
2849
- if (writtenSize != actualSize) {
2850
- response = "Size updated from: " + writtenSize + " to: " + actualSize;
2851
- try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { response = e; }
2852
- } else { response = "Agent Size: " + actualSize + " kb"; }
2853
- } else { response = "Agent Size: " + actualSize + " kb"; }
2854
- break;
2855
- case 'versions':
2856
- response = JSON.stringify(process.versions, null, ' ');
2857
- break;
2858
- case 'wpfhwacceleration':
2859
- if (process.platform != 'win32') { throw ("wpfhwacceleration setting is only supported on Windows"); }
2860
- if (args['_'].length != 1) {
2861
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS)"; // Display usage
2862
- }
2863
- else {
2864
- var reg = require('win-registry');
2865
- var uname = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2866
- var key = reg.usernameToUserKey(uname);
2867
-
2868
- switch (args['_'][0].toUpperCase()) {
2869
- default:
2870
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS|DEFAULT)"; // Display usage
2871
- break;
2872
- case 'ON':
2873
- try {
2874
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 0);
2875
- response = "OK";
2876
- } catch (e) { response = "FAILED"; }
2877
- break;
2878
- case 'OFF':
2879
- try {
2880
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 1);
2881
- response = 'OK';
2882
- } catch (e) { response = 'FAILED'; }
2883
- break;
2884
- case 'STATUS':
2885
- var s;
2886
- try { s = reg.QueryKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration') == 1 ? 'DISABLED' : 'ENABLED'; } catch (e) { s = 'DEFAULT'; }
2887
- response = "WPF Hardware Acceleration: " + s;
2888
- break;
2889
- case 'DEFAULT':
2890
- try { reg.DeleteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration'); } catch (e) { }
2891
- response = 'OK';
2892
- break;
2893
- }
2894
- }
2895
- break;
2896
- case 'tsid':
2897
- if (process.platform == 'win32') {
2898
- if (args['_'].length != 1) {
2899
- response = "TSID: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
2900
- } else {
2901
- var i = parseInt(args['_'][0]);
2902
- require('MeshAgent')._tsid = (isNaN(i) ? null : i);
2903
- response = "TSID set to: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
2904
- }
2905
- } else { response = "TSID command only supported on Windows"; }
2906
- break;
2907
- case 'activeusers':
2908
- if (process.platform == 'win32') {
2909
- var p = require('user-sessions').enumerateUsers();
2910
- p.sessionid = sessionid;
2911
- p.then(function (u) {
2912
- var v = [];
2913
- for (var i in u) {
2914
- if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
2915
- }
2916
- sendConsoleText(JSON.stringify(v, null, 1), this.sessionid);
2917
- });
2918
- } else { response = "activeusers command only supported on Windows"; }
2919
- break;
2920
- case 'wallpaper':
2921
- if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available)) {
2922
- response = "wallpaper command not supported on this platform";
2923
- }
2924
- else {
2925
- if (args['_'].length != 1) {
2926
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
2927
- }
2928
- else {
2929
- switch (args['_'][0].toUpperCase()) {
2930
- default:
2931
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
2932
- break;
2933
- case 'GET':
2934
- case 'TOGGLE':
2935
- if (process.platform == 'win32') {
2936
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
2937
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: id });
2938
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
2939
- child.stderr.on('data', function () { });
2940
- child.waitExit();
2941
- var current = child.stdout.str.trim();
2942
- if (args['_'][0].toUpperCase() == 'GET') {
2943
- response = current;
2944
- break;
2945
- }
2946
- if (current != '') {
2947
- require('MeshAgent')._wallpaper = current;
2948
- response = 'Wallpaper cleared';
2949
- } else {
2950
- response = 'Wallpaper restored';
2951
- }
2952
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: id });
2953
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
2954
- child.stderr.on('data', function () { });
2955
- child.waitExit();
2956
- }
2957
- else {
2958
- var id = require('user-sessions').consoleUid();
2959
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
2960
- if (args['_'][0].toUpperCase() == 'GET') {
2961
- response = current;
2962
- break;
2963
- }
2964
- if (current != '/dev/null') {
2965
- require('MeshAgent')._wallpaper = current;
2966
- response = 'Wallpaper cleared';
2967
- } else {
2968
- response = 'Wallpaper restored';
2969
- }
2970
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
2971
- }
2972
- break;
2973
- }
2974
- }
2975
- }
2976
- break;
2977
- case 'safemode':
2978
- if (process.platform != 'win32') {
2979
- response = 'safemode only supported on Windows Platforms'
2980
- }
2981
- else {
2982
- if (args['_'].length != 1) {
2983
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
2984
- }
2985
- else {
2986
- switch (args['_'][0].toUpperCase()) {
2987
- default:
2988
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
2989
- break;
2990
- case 'ON':
2991
- require('win-bcd').setKey('safeboot', 'Network');
2992
- require('win-bcd').enableSafeModeService('Mesh Agent');
2993
- break;
2994
- case 'OFF':
2995
- require('win-bcd').deleteKey('safeboot');
2996
- break;
2997
- case 'STATUS':
2998
- var nextboot = require('win-bcd').getKey('safeboot');
2999
- if (nextboot) {
3000
- switch (nextboot) {
3001
- case 'Network':
3002
- case 'network':
3003
- nextboot = 'SAFE_MODE_NETWORK';
3004
- break;
3005
- default:
3006
- nextboot = 'SAFE_MODE';
3007
- break;
3008
- }
3009
- }
3010
- response = 'Current: ' + require('win-bcd').bootMode + ', NextBoot: ' + (nextboot ? nextboot : 'NORMAL');
3011
- break;
3012
- }
3013
- }
3014
- }
3015
- break;
3016
- /*
3017
- case 'border':
3018
- {
3019
- if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
3020
- if (meshCoreObj.users.length > 0) {
3021
- obj.borderManager.Start(meshCoreObj.users[0]);
3022
- response = 'Border blinking is on.';
3023
- } else {
3024
- response = 'Cannot turn on border blinking, no logged in users.';
3025
- }
3026
- } else if ((args['_'].length == 1) && (args['_'][0] == 'off')) {
3027
- obj.borderManager.Stop();
3028
- response = 'Border blinking is off.';
3029
- } else {
3030
- response = 'Proper usage: border "on|off"'; // Display correct command usage
3031
- }
3032
- }
3033
- break;
3034
- */
3035
- case 'av':
3036
- if (process.platform == 'win32') {
3037
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3038
- response = JSON.stringify(require('win-info').av(), null, 1);
3039
- } else {
3040
- response = 'Not supported on the platform';
3041
- }
3042
- break;
3043
- case 'log':
3044
- if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
3045
- break;
3046
- case 'getclip':
3047
- if (require('MeshAgent').isService) {
3048
- require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });
3049
- } else {
3050
- require("clipboard").read().then(function (str) { sendConsoleText(str, sessionid); });
3051
- }
3052
- break;
3053
- case 'setclip': {
3054
- if (args['_'].length != 1) {
3055
- response = 'Proper usage: setclip "sample text"';
3056
- } else {
3057
- if (require('MeshAgent').isService) {
3058
- require('clipboard').dispatchWrite(args['_'][0]);
3059
- response = 'Setting clipboard to: "' + args['_'][0] + '"';
3060
- }
3061
- else {
3062
- require("clipboard")(args['_'][0]); response = 'Setting clipboard to: "' + args['_'][0] + '"';
3063
- }
3064
- }
3065
- break;
3066
- }
3067
- /*
3068
- case 'amtreset': {
3069
- if (amt != null) { amt.reset(); response = 'Done.'; }
3070
- break;
3071
- }
3072
- case 'amtlmsreset': {
3073
- if (amt != null) { amt.lmsreset(); response = 'Done.'; }
3074
- break;
3075
- }
3076
- case 'amtccm': {
3077
- if (amt == null) { response = 'Intel AMT not supported.'; } else {
3078
- if (args['_'].length != 1) { response = 'Proper usage: amtccm (adminPassword)'; } // Display usage
3079
- else { amt.setPolicy({ type: 0 }); amt.activeToCCM(args['_'][0]); }
3080
- }
3081
- break;
3082
- }
3083
- case 'amtacm': {
3084
- if (amt == null) { response = 'Intel AMT not supported.'; } else {
3085
- amt.setPolicy({ type: 0 });
3086
- amt.getAmtInfo(function (meinfo) { amt.activeToACM(meinfo); });
3087
- }
3088
- break;
3089
- }
3090
- case 'amtdeactivate': {
3091
- if (amt == null) { response = 'Intel AMT not supported.'; } else { amt.setPolicy({ type: 0 }); amt.deactivateCCM(); }
3092
- break;
3093
- }
3094
- */
3095
- case 'openurl': {
3096
- if (args['_'].length != 1) { response = 'Proper usage: openurl (url)'; } // Display usage
3097
- else { if (openUserDesktopUrl(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } }
3098
- break;
3099
- }
3100
- case 'users': {
3101
- if (meshCoreObj.users == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + meshCoreObj.users.join(', ') + '.'; }
3102
- require('user-sessions').enumerateUsers().then(function (u) { for (var i in u) { sendConsoleText(u[i]); } });
3103
- break;
3104
- }
3105
- case 'toast': {
3106
- if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
3107
- if (require('MeshAgent')._tsid == null) {
3108
- require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
3109
- }
3110
- else {
3111
- require('toaster').Toast('MeshCentral', args['_'][0], require('MeshAgent')._tsid).then(sendConsoleText, sendConsoleText);
3112
- }
3113
- }
3114
- break;
3115
- }
3116
- case 'setdebug': {
3117
- if (args['_'].length < 1) { response = 'Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile'; } // Display usage
3118
- else { if (args['_'][0] == '*') { console.setDestination(2); } else { console.setDestination(parseInt(args['_'][0]), sessionid); } }
3119
- break;
3120
- }
3121
- case 'ps': {
3122
- processManager.getProcesses(function (plist) {
3123
- var x = '';
3124
- for (var i in plist) { x += i + ((plist[i].user) ? (', ' + plist[i].user) : '') + ', ' + plist[i].cmd + '\r\n'; }
3125
- sendConsoleText(x, sessionid);
3126
- });
3127
- break;
3128
- }
3129
- case 'kill': {
3130
- if ((args['_'].length < 1)) {
3131
- response = 'Proper usage: kill [pid]'; // Display correct command usage
3132
- } else {
3133
- process.kill(parseInt(args['_'][0]));
3134
- response = 'Killed process ' + args['_'][0] + '.';
3135
- }
3136
- break;
3137
- }
3138
- case 'smbios': {
3139
- if (SMBiosTables == null) { response = 'SMBios tables not available.'; } else { response = objToString(SMBiosTables, 0, ' ', true); }
3140
- break;
3141
- }
3142
- case 'rawsmbios': {
3143
- if (SMBiosTablesRaw == null) { response = 'SMBios tables not available.'; } else {
3144
- response = '';
3145
- for (var i in SMBiosTablesRaw) {
3146
- var header = false;
3147
- for (var j in SMBiosTablesRaw[i]) {
3148
- if (SMBiosTablesRaw[i][j].length > 0) {
3149
- if (header == false) { response += ('Table type #' + i + ((require('smbios').smTableTypes[i] == null) ? '' : (', ' + require('smbios').smTableTypes[i]))) + '\r\n'; header = true; }
3150
- response += (' ' + SMBiosTablesRaw[i][j].toString('hex')) + '\r\n';
3151
- }
3152
- }
3153
- }
3154
- }
3155
- break;
3156
- }
3157
- case 'eval': { // Eval JavaScript
3158
- if (args['_'].length < 1) {
3159
- response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
3160
- } else {
3161
- response = JSON.stringify(mesh.eval(args['_'][0])); // This can only be run by trusted administrator.
3162
- }
3163
- break;
3164
- }
3165
- case 'uninstallagent': // Uninstall this agent
3166
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3167
- if (!require('service-manager').manager.getService(agentName).isMe()) {
3168
- response = 'Uininstall failed, this instance is not the service instance';
3169
- } else {
3170
- try { diagnosticAgent_uninstall(); } catch (e) { }
3171
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
3172
- 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 });
3173
- }
3174
- break;
3175
- case 'notify': { // Send a notification message to the mesh
3176
- if (args['_'].length != 1) {
3177
- response = 'Proper usage: notify "message" [--session]'; // Display correct command usage
3178
- } else {
3179
- var notification = { action: 'msg', type: 'notify', value: args['_'][0], tag: 'console' };
3180
- if (args.session) { notification.sessionid = sessionid; } // If "--session" is specified, notify only this session, if not, the server will notify the mesh
3181
- mesh.SendCommand(notification); // no sessionid or userid specified, notification will go to the entire mesh
3182
- response = "ok";
3183
- }
3184
- break;
3185
- }
3186
- case 'cpuinfo': { // Return system information
3187
- // CPU & memory utilization
3188
- pr = require('sysinfo').cpuUtilization();
3189
- pr.sessionid = sessionid;
3190
- pr.then(function (data) {
3191
- sendConsoleText(JSON.stringify({ cpu: data, memory: require('sysinfo').memUtilization() }, null, 1), this.sessionid);
3192
- }, function (e) {
3193
- sendConsoleText(e);
3194
- });
3195
- break;
3196
- }
3197
- case 'sysinfo': { // Return system information
3198
- getSystemInformation(function (results, err) {
3199
- if (results == null) { sendConsoleText(err, this.sessionid); } else {
3200
- sendConsoleText(JSON.stringify(results, null, 1), this.sessionid);
3201
- }
3202
- });
3203
- break;
3204
- }
3205
- case 'info': { // Return information about the agent and agent core module
3206
- 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 + '.';
3207
- if (amt != null) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amt.lmsstate] + '.'; }
3208
- if (meshCoreObj.osdesc) { response += '\r\nOS: ' + meshCoreObj.osdesc + '.'; }
3209
- response += '\r\nModules: ' + addedModules.join(', ') + '.';
3210
- response += '\r\nServer Connection: ' + mesh.isControlChannelConnected + ', State: ' + meshServerConnectionState + '.';
3211
- response += '\r\lastMeInfo: ' + lastMeInfo + '.';
3212
- var oldNodeId = db.Get('OldNodeId');
3213
- if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
3214
- if (process.platform == 'linux' || process.platform == 'freebsd') { response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.'; }
3215
- break;
3216
- }
3217
- case 'osinfo': { // Return the operating system information
3218
- var i = 1;
3219
- if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; }
3220
- for (var j = 0; j < i; j++) {
3221
- var pr = require('os').name();
3222
- pr.sessionid = sessionid;
3223
- pr.then(function (v) {
3224
- sendConsoleText("OS: " + v + (process.platform == 'win32' ? (require('win-virtual-terminal').supported ? ' [ConPTY: YES]' : ' [ConPTY: NO]') : ''), this.sessionid);
3225
- });
3226
- }
3227
- break;
3228
- }
3229
- case 'sendcaps': { // Send capability flags to the server
3230
- if (args['_'].length == 0) {
3231
- response = 'Proper usage: sendcaps (number)'; // Display correct command usage
3232
- } else {
3233
- meshCoreObj.caps = parseInt(args['_'][0]);
3234
- mesh.SendCommand(meshCoreObj);
3235
- response = JSON.stringify(meshCoreObj);
3236
- }
3237
- break;
3238
- }
3239
- case 'sendosdesc': { // Send OS description
3240
- if (args['_'].length > 0) {
3241
- meshCoreObj.osdesc = args['_'][0];
3242
- mesh.SendCommand(meshCoreObj);
3243
- response = JSON.stringify(meshCoreObj);
3244
- } else {
3245
- response = 'Proper usage: sendosdesc [os description]'; // Display correct command usage
3246
- }
3247
- break;
3248
- }
3249
- case 'args': { // Displays parsed command arguments
3250
- response = 'args ' + objToString(args, 0, ' ', true);
3251
- break;
3252
- }
3253
- case 'print': { // Print a message on the mesh agent console, does nothing when running in the background
3254
- var r = [];
3255
- for (var i in args['_']) { r.push(args['_'][i]); }
3256
- console.log(r.join(' '));
3257
- response = 'Message printed on agent console.';
3258
- break;
3259
- }
3260
- case 'type': { // Returns the content of a file
3261
- if (args['_'].length == 0) {
3262
- response = 'Proper usage: type (filepath) [maxlength]'; // Display correct command usage
3263
- } else {
3264
- var max = 4096;
3265
- if ((args['_'].length > 1) && (typeof args['_'][1] == 'number')) { max = args['_'][1]; }
3266
- if (max > 4096) max = 4096;
3267
- var buf = Buffer.alloc(max), fd = fs.openSync(args['_'][0], "r"), r = fs.readSync(fd, buf, 0, max); // Read the file content
3268
- response = buf.toString();
3269
- var i = response.indexOf('\n');
3270
- if ((i > 0) && (response[i - 1] != '\r')) { response = response.split('\n').join('\r\n'); }
3271
- if (r == max) response += '...';
3272
- fs.closeSync(fd);
3273
- }
3274
- break;
3275
- }
3276
- case 'dbkeys': { // Return all data store keys
3277
- response = JSON.stringify(db.Keys);
3278
- break;
3279
- }
3280
- case 'dbget': { // Return the data store value for a given key
3281
- if (db == null) { response = 'Database not accessible.'; break; }
3282
- if (args['_'].length != 1) {
3283
- response = 'Proper usage: dbget (key)'; // Display the value for a given database key
3284
- } else {
3285
- response = db.Get(args['_'][0]);
3286
- }
3287
- break;
3288
- }
3289
- case 'dbset': { // Set a data store key and value pair
3290
- if (db == null) { response = 'Database not accessible.'; break; }
3291
- if (args['_'].length != 2) {
3292
- response = 'Proper usage: dbset (key) (value)'; // Set a database key
3293
- } else {
3294
- var r = db.Put(args['_'][0], args['_'][1]);
3295
- response = 'Key set: ' + r;
3296
- }
3297
- break;
3298
- }
3299
- case 'dbcompact': { // Compact the data store
3300
- if (db == null) { response = 'Database not accessible.'; break; }
3301
- var r = db.Compact();
3302
- response = 'Database compacted: ' + r;
3303
- break;
3304
- }
3305
- case 'httpget': {
3306
- if (consoleHttpRequest != null) {
3307
- response = 'HTTP operation already in progress.';
3308
- } else {
3309
- if (args['_'].length != 1) {
3310
- response = 'Proper usage: httpget (url)';
3311
- } else {
3312
- var options = http.parseUri(args['_'][0]);
3313
- options.method = 'GET';
3314
- if (options == null) {
3315
- response = 'Invalid url.';
3316
- } else {
3317
- try { consoleHttpRequest = http.request(options, consoleHttpResponse); } catch (e) { response = 'Invalid HTTP GET request'; }
3318
- consoleHttpRequest.sessionid = sessionid;
3319
- if (consoleHttpRequest != null) {
3320
- consoleHttpRequest.end();
3321
- response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
3322
- }
3323
- }
3324
- }
3325
- }
3326
- break;
3327
- }
3328
- case 'wslist': { // List all web sockets
3329
- response = '';
3330
- for (var i in consoleWebSockets) {
3331
- var httprequest = consoleWebSockets[i];
3332
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3333
- }
3334
- if (response == '') { response = 'no websocket sessions.'; }
3335
- break;
3336
- }
3337
- case 'wsconnect': { // Setup a web socket
3338
- if (args['_'].length == 0) {
3339
- response = 'Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc'; // Display correct command usage
3340
- } else {
3341
- var httprequest = null;
3342
- try {
3343
- var options = http.parseUri(args['_'][0].split('$').join('%24').split('@').join('%40')); // Escape the $ and @ characters in the URL
3344
- options.rejectUnauthorized = 0;
3345
- httprequest = http.request(options);
3346
- } catch (e) { response = 'Invalid HTTP websocket request'; }
3347
- if (httprequest != null) {
3348
- httprequest.upgrade = onWebSocketUpgrade;
3349
- httprequest.on('error', function (e) { sendConsoleText("ERROR: Unable to connect to: " + this.url + ", " + JSON.stringify(e)); });
3350
-
3351
- var index = 1;
3352
- while (consoleWebSockets[index]) { index++; }
3353
- httprequest.sessionid = sessionid;
3354
- httprequest.index = index;
3355
- httprequest.url = args['_'][0];
3356
- consoleWebSockets[index] = httprequest;
3357
- response = 'New websocket session #' + index;
3358
- }
3359
- }
3360
- break;
3361
- }
3362
- case 'wssend': { // Send data on a web socket
3363
- if (args['_'].length == 0) {
3364
- response = 'Proper usage: wssend (socketnumber)\r\n'; // Display correct command usage
3365
- for (var i in consoleWebSockets) {
3366
- var httprequest = consoleWebSockets[i];
3367
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3368
- }
3369
- } else {
3370
- var i = parseInt(args['_'][0]);
3371
- var httprequest = consoleWebSockets[i];
3372
- if (httprequest != undefined) {
3373
- httprequest.s.write(args['_'][1]);
3374
- response = 'ok';
3375
- } else {
3376
- response = 'Invalid web socket number';
3377
- }
3378
- }
3379
- break;
3380
- }
3381
- case 'wsclose': { // Close a websocket
3382
- if (args['_'].length == 0) {
3383
- response = 'Proper usage: wsclose (socketnumber)'; // Display correct command usage
3384
- } else {
3385
- var i = parseInt(args['_'][0]);
3386
- var httprequest = consoleWebSockets[i];
3387
- if (httprequest != undefined) {
3388
- if (httprequest.s != null) { httprequest.s.end(); } else { httprequest.end(); }
3389
- response = 'ok';
3390
- } else {
3391
- response = 'Invalid web socket number';
3392
- }
3393
- }
3394
- break;
3395
- }
3396
- case 'tunnels': { // Show the list of current tunnels
3397
- response = '';
3398
- for (var i in tunnels) { response += 'Tunnel #' + i + ', ' + tunnels[i].url + '\r\n'; }
3399
- if (response == '') { response = 'No websocket sessions.'; }
3400
- break;
3401
- }
3402
- case 'ls': { // Show list of files and folders
3403
- response = '';
3404
- var xpath = '*';
3405
- if (args['_'].length > 0) { xpath = obj.path.join(args['_'][0], '*'); }
3406
- response = 'List of ' + xpath + '\r\n';
3407
- var results = fs.readdirSync(xpath);
3408
- for (var i = 0; i < results.length; ++i) {
3409
- var stat = null, p = obj.path.join(args['_'][0], results[i]);
3410
- try { stat = fs.statSync(p); } catch (e) { }
3411
- if ((stat == null) || (stat == undefined)) {
3412
- response += (results[i] + "\r\n");
3413
- } else {
3414
- response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
3415
- }
3416
- }
3417
- break;
3418
- }
3419
- case 'lsx': { // Show list of files and folders
3420
- response = objToString(getDirectoryInfo(args['_'][0]), 0, ' ', true);
3421
- break;
3422
- }
3423
- case 'lock': { // Lock the current user out of the desktop
3424
- if (process.platform == 'win32') { var child = require('child_process'); child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 }); response = 'Ok'; }
3425
- else { response = 'Not supported on the platform'; }
3426
- break;
3427
- }
3428
- case 'amt': { // Show Intel AMT status
3429
- if (amt != null) {
3430
- amt.getAmtInfo(function (state) {
3431
- var resp = 'Intel AMT not detected.';
3432
- if (state != null) { resp = objToString(state, 0, ' ', true); }
3433
- sendConsoleText(resp, sessionid);
3434
- });
3435
- } else {
3436
- response = 'Intel AMT not detected.';
3437
- }
3438
- break;
3439
- }
3440
- case 'netinfo': { // Show network interface information
3441
- var interfaces = require('os').networkInterfaces();
3442
- response = objToString(interfaces, 0, ' ', true);
3443
- break;
3444
- }
3445
- case 'wakeonlan': { // Send wake-on-lan
3446
- if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
3447
- response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
3448
- } else {
3449
- var count = sendWakeOnLan(args['_'][0]);
3450
- response = 'Sent wake-on-lan on ' + count + ' interface(s).';
3451
- }
3452
- break;
3453
- }
3454
- case 'sendall': { // Send a message to all consoles on this mesh
3455
- sendConsoleText(args['_'].join(' '));
3456
- break;
3457
- }
3458
- case 'power': { // Execute a power action on this computer
3459
- if (mesh.ExecPowerState == undefined) {
3460
- response = 'Power command not supported on this agent.';
3461
- } else {
3462
- if ((args['_'].length == 0) || isNaN(Number(args['_'][0]))) {
3463
- 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
3464
- } else {
3465
- var r = mesh.ExecPowerState(Number(args['_'][0]), Number(args['_'][1]));
3466
- response = 'Power action executed with return code: ' + r + '.';
3467
- }
3468
- }
3469
- break;
3470
- }
3471
- case 'location': {
3472
- getIpLocationData(function (location) {
3473
- sendConsoleText(objToString({ action: 'iplocation', type: 'publicip', value: location }, 0, ' '));
3474
- });
3475
- break;
3476
- }
3477
- case 'parseuri': {
3478
- response = JSON.stringify(http.parseUri(args['_'][0]));
3479
- break;
3480
- }
3481
- case 'scanwifi': {
3482
- if (wifiScanner != null) {
3483
- var wifiPresent = wifiScanner.hasWireless;
3484
- if (wifiPresent) { response = "Perfoming Wifi scan..."; wifiScanner.Scan(); } else { response = "Wifi absent."; }
3485
- } else { response = "Wifi module not present."; }
3486
- break;
3487
- }
3488
- case 'scanamt': {
3489
- if (amtscanner != null) {
3490
- if (args['_'].length != 1) {
3491
- response = 'Usage examples:\r\n scanamt 1.2.3.4\r\n scanamt 1.2.3.0-1.2.3.255\r\n scanamt 1.2.3.0/24\r\n'; // Display correct command usage
3492
- } else {
3493
- response = 'Scanning: ' + args['_'][0] + '...';
3494
- amtscanner.scan(args['_'][0], 2000, function (data) {
3495
- if (data.length > 0) {
3496
- var r = '', pstates = ['NotActivated', 'InActivation', 'Activated'];
3497
- for (var i in data) {
3498
- var x = data[i];
3499
- if (r != '') { r += '\r\n'; }
3500
- r += x.address + ' - Intel AMT v' + x.majorVersion + '.' + x.minorVersion;
3501
- if (x.provisioningState < 3) { r += (', ' + pstates[x.provisioningState]); }
3502
- if (x.provisioningState == 2) { r += (', ' + x.openPorts.join(', ')); }
3503
- r += '.';
3504
- }
3505
- } else {
3506
- r = 'No Intel AMT found.';
3507
- }
3508
- sendConsoleText(r);
3509
- });
3510
- }
3511
- } else { response = "Intel AMT scanner module not present."; }
3512
- break;
3513
- }
3514
- case 'modules': {
3515
- response = JSON.stringify(addedModules);
3516
- break;
3517
- }
3518
- case 'listservices': {
3519
- var services = require('service-manager').manager.enumerateService();
3520
- response = JSON.stringify(services, null, 1);
3521
- break;
3522
- }
3523
- case 'getscript': {
3524
- if (args['_'].length != 1) {
3525
- response = "Proper usage: getscript [scriptNumber].";
3526
- } else {
3527
- mesh.SendCommand({ action: 'getScript', type: args['_'][0] });
3528
- }
3529
- break;
3530
- }
3531
- case 'diagnostic':
3532
- {
3533
- if (!mesh.DAIPC.listening) {
3534
- response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
3535
- break;
3536
- }
3537
- var diag = diagnosticAgent_installCheck();
3538
- if (diag) {
3539
- if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
3540
- diagnosticAgent_uninstall();
3541
- response = 'Diagnostic Agent uninstalled';
3542
- }
3543
- else {
3544
- response = 'Diagnostic Agent installed at: ' + diag.appLocation();
3545
- }
3546
- }
3547
- else {
3548
- if (args['_'].length == 1 && args['_'][0] == 'install') {
3549
- diag = diagnosticAgent_installCheck(true);
3550
- if (diag) {
3551
- response = 'Diagnostic agent was installed at: ' + diag.appLocation();
3552
- }
3553
- else {
3554
- response = 'Diagnostic agent installation failed';
3555
- }
3556
- }
3557
- else {
3558
- response = 'Diagnostic Agent Not installed. To install: diagnostic install';
3559
- }
3560
- }
3561
- if (diag) { diag.close(); diag = null; }
3562
- break;
3563
- }
3564
- case 'amtconfig': {
3565
- if (apftunnel != null) { response = "Intel AMT server tunnel already active"; break; }
3566
- if (amt == null) { response = "No Intel AMT support delected"; break; }
3567
- getMeiState(15, function (state) {
3568
- var rx = '';
3569
- if ((state == null) || (state.ProvisioningState == null)) { rx = "Intel AMT not ready for configuration."; } else {
3570
- var apfarg = {
3571
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3572
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3573
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3574
- mpskeepalive: 60000,
3575
- clientname: state.OsHostname,
3576
- clientaddress: '127.0.0.1',
3577
- clientuuid: state.UUID,
3578
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3579
- meiState: state // MEI state will be passed to MPS server
3580
- };
3581
- if ((state.UUID == null) || (state.UUID.length != 36)) {
3582
- rx = "Unable to get Intel AMT UUID";
3583
- } else {
3584
- apftunnel = require('apfclient')({ debug: false }, apfarg);
3585
- apftunnel.onJsonControl = function (data) {
3586
- if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); } // Display a console message
3587
- if (data.action == 'mestate') { getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
3588
- if (data.action == 'deactivate') { // Request CCM deactivation
3589
- var amtMeiModule, amtMei;
3590
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { apftunnel.sendMeiDeactivationState(1); break; }
3591
- amtMei.on('error', function (e) { apftunnel.sendMeiDeactivationState(1); });
3592
- amtMei.unprovision(1, function (status) { apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
3593
- }
3594
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
3595
- }
3596
- apftunnel.onChannelClosed = function () { apftunnel = null; }
3597
- try {
3598
- apftunnel.connect();
3599
- rx = "Started Intel AMT configuration";
3600
- } catch (ex) {
3601
- rx = JSON.stringify(ex);
3602
- }
3603
- }
3604
- }
3605
- if (rx != '') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: rx }); }
3606
- });
3607
- break;
3608
- }
3609
- case 'apf': {
3610
- if (meshCoreObj.intelamt !== null) {
3611
- if (args['_'].length == 1) {
3612
- var connType = -1, connTypeStr = args['_'][0].toLowerCase();
3613
- if (connTypeStr == 'lms') { connType = 2; }
3614
- if (connTypeStr == 'relay') { connType = 1; }
3615
- if (connTypeStr == 'cira') { connType = 0; }
3616
- if (connTypeStr == 'off') { connType = -2; }
3617
- if (connType >= 0) { // Connect
3618
- var apfarg = {
3619
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3620
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3621
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3622
- mpskeepalive: 60000,
3623
- clientname: require('os').hostname(),
3624
- clientaddress: '127.0.0.1',
3625
- clientuuid: meshCoreObj.intelamt.uuid,
3626
- conntype: connType // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3627
- };
3628
- if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
3629
- response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
3630
- } else {
3631
- apftunnel = require('apfclient')({ debug: false }, apfarg);
3632
- apftunnel.onJsonControl = function (data) {
3633
- if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
3634
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
3635
- }
3636
- apftunnel.onChannelClosed = function () { apftunnel = null; }
3637
- try {
3638
- apftunnel.connect();
3639
- response = "Started APF tunnel";
3640
- } catch (e) {
3641
- response = JSON.stringify(e);
3642
- }
3643
- }
3644
- } else if (connType == -2) { // Disconnect
3645
- try {
3646
- apftunnel.disconnect();
3647
- response = "Stopped APF tunnel";
3648
- } catch (e) {
3649
- response = JSON.stringify(e);
3650
- }
3651
- apftunnel = null;
3652
- } else {
3653
- response = "Invalid command.\r\nUse: apf lms|relay|cira|off";
3654
- }
3655
- } else {
3656
- response = "APF tunnel is " + (apftunnel == null ? "off" : "on") + "\r\nUse: apf lms|relay|cira|off";
3657
- }
3658
- } else {
3659
- response = "APF tunnel requires Intel AMT";
3660
- }
3661
- break;
3662
- }
3663
- case 'plugin': {
3664
- if (typeof args['_'][0] == 'string') {
3665
- try {
3666
- // Pass off the action to the plugin
3667
- // for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
3668
- // to control the output / actions here.
3669
- response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
3670
- } catch (e) {
3671
- response = "There was an error in the plugin (" + e + ")";
3672
- }
3673
- } else {
3674
- response = "Proper usage: plugin [pluginName] [args].";
3675
- }
3676
- break;
3677
- }
3678
- default: { // This is an unknown command, return an error message
3679
- response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands.";
3680
- break;
3681
- }
3682
- }
3683
- } catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
3684
- if (response != null) { sendConsoleText(response, sessionid); }
3685
- }
3686
-
3687
- // Send a mesh agent console command
3688
- function sendConsoleText(text, sessionid) {
3689
- if (typeof text == 'object') { text = JSON.stringify(text); }
3690
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: text, sessionid: sessionid });
3691
- }
3692
-
3693
- // Called before the process exits
3694
- //process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
3695
-
3696
- // Called when the server connection state changes
3697
- function handleServerConnection(state) {
3698
- meshServerConnectionState = state;
3699
- if (meshServerConnectionState == 0) {
3700
- // Server disconnected
3701
- if (selfInfoUpdateTimer != null) { clearInterval(selfInfoUpdateTimer); selfInfoUpdateTimer = null; }
3702
- lastSelfInfo = null;
3703
- } else {
3704
- // Server connected, send mesh core information
3705
- var oldNodeId = db.Get('OldNodeId');
3706
- if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); }
3707
-
3708
- // Update the server with basic info, logged in users and more.
3709
- mesh.SendCommand(meshCoreObj);
3710
-
3711
- // Send SMBios tables if present
3712
- if (SMBiosTablesRaw != null) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
3713
-
3714
- // Update the server on more advanced stuff, like Intel ME and Network Settings
3715
- meInfoStr = null;
3716
- sendPeriodicServerUpdate();
3717
- if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); } // 20 minutes
3718
-
3719
- // Send any state messages
3720
- if (Object.keys(tunnelUserCount.msg).length > 0) {
3721
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (e) { }
3722
- broadcastSessionsToRegisteredApps();
3723
- }
3724
-
3725
- // Send update of registered applications to the server
3726
- updateRegisteredAppsToServer();
3727
- }
3728
-
3729
- // Send server state update to registered applications
3730
- broadcastToRegisteredApps({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer });
3731
- }
3732
-
3733
- // Update the server with the latest network interface information
3734
- var sendNetworkUpdateNagleTimer = null;
3735
- function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
3736
- function sendNetworkUpdate(force) {
3737
- sendNetworkUpdateNagleTimer = null;
3738
-
3739
- // Update the network interfaces information data
3740
- var netInfo = { netif2: require('os').networkInterfaces() };
3741
- if (netInfo.netif2) {
3742
- netInfo.action = 'netinfo';
3743
- var netInfoStr = JSON.stringify(netInfo);
3744
- if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
3745
- }
3746
- }
3747
-
3748
- // Called periodically to check if we need to send updates to the server
3749
- function sendPeriodicServerUpdate(flags) {
3750
- if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
3751
- if (!flags) { flags = 0xFFFFFFFF; }
3752
-
3753
- if ((flags & 1) && (amt != null)) {
3754
- // If we have a connected MEI, get Intel ME information
3755
- amt.getAmtInfo(function (meinfo) {
3756
- try {
3757
- if (meinfo == null) return;
3758
- var intelamt = {};
3759
- if (amt != null)
3760
- {
3761
- switch(amt.lmsstate)
3762
- {
3763
- case 0: intelamt.microlms = 'DISABLED'; break;
3764
- case 1: intelamt.microlms = 'CONNECTING'; break;
3765
- case 2: intelamt.microlms = 'CONNECTED'; break;
3766
- default: intelamt.microlms = 'unknown'; break;
3767
- }
3768
- }
3769
- var p = false;
3770
- if ((meinfo.Versions != null) && (meinfo.Versions.AMT != null)) { intelamt.ver = meinfo.Versions.AMT; p = true; if (meinfo.Versions.Sku != null) { intelamt.sku = parseInt(meinfo.Versions.Sku); } }
3771
- if (meinfo.ProvisioningState != null) { intelamt.state = meinfo.ProvisioningState; p = true; }
3772
- if (meinfo.Flags != null) { intelamt.flags = meinfo.Flags; p = true; }
3773
- if (meinfo.OsHostname != null) { intelamt.host = meinfo.OsHostname; p = true; }
3774
- if (meinfo.UUID != null) { intelamt.uuid = meinfo.UUID; p = true; }
3775
- if ((meinfo.ProvisioningState == 0) && (meinfo.net0 != null) && (meinfo.net0.enabled == 1)) { // If not activated, look to see if we have wired net working.
3776
- // Not activated and we have wired ethernet, look for the trusted DNS
3777
- var dns = meinfo.DNS;
3778
- if (dns == null) {
3779
- // Trusted DNS not set, let's look for the OS network DNS suffix
3780
- var interfaces = require('os').networkInterfaces();
3781
- for (var i in interfaces) {
3782
- for (var j in interfaces[i]) {
3783
- if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { dns = interfaces[i][j].fqdn; }
3784
- }
3785
- }
3786
- }
3787
- if (intelamt.dns != dns) { intelamt.dns = dns; p = true; }
3788
- } else { if (intelamt.dns != null) { delete intelamt.dns; p = true; } }
3789
- if (p == true) {
3790
- var meInfoStr = JSON.stringify(intelamt);
3791
- if (meInfoStr != lastMeInfo) {
3792
- meshCoreObj.intelamt = intelamt;
3793
- mesh.SendCommand(meshCoreObj);
3794
- lastMeInfo = meInfoStr;
3795
- }
3796
- }
3797
- } catch (e) { }
3798
- });
3799
- }
3800
-
3801
- if (flags & 2) {
3802
- // Update network information
3803
- sendNetworkUpdateNagle(false);
3804
- }
3805
-
3806
- if ((flags & 4) && (process.platform == 'win32')) {
3807
- // Update anti-virus information
3808
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3809
- var av, pr;
3810
- try { av = require('win-info').av(); } catch (e) { av = null; } // Antivirus
3811
- //if (process.platform == 'win32') { try { pr = require('win-info').pendingReboot(); } catch (e) { pr = null; } } // Pending reboot
3812
- if ((meshCoreObj.av == null) || (JSON.stringify(meshCoreObj.av) != JSON.stringify(av))) { meshCoreObj.av = av; mesh.SendCommand(meshCoreObj); }
3813
- }
3814
- }
3815
-
3816
- // Starting function
3817
- obj.start = function () {
3818
- // Setup the mesh agent event handlers
3819
- mesh.AddCommandHandler(handleServerCommand);
3820
- mesh.AddConnectHandler(handleServerConnection);
3821
-
3822
- // Parse input arguments
3823
- //var args = parseArgs(process.argv);
3824
- //console.log(args);
3825
-
3826
- //resetMicroLms();
3827
-
3828
- // Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
3829
- try {
3830
- var userSession = require('user-sessions');
3831
- userSession.on('changed', function onUserSessionChanged() {
3832
- userSession.enumerateUsers().then(function (users) {
3833
- var u = [], a = users.Active;
3834
- for (var i = 0; i < a.length; i++) {
3835
- var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
3836
- if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
3837
- }
3838
- meshCoreObj.users = u;
3839
- mesh.SendCommand(meshCoreObj);
3840
- });
3841
- });
3842
- userSession.emit('changed');
3843
- //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
3844
- //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
3845
- } catch (e) { }
3846
- }
3847
-
3848
- obj.stop = function () {
3849
- mesh.AddCommandHandler(null);
3850
- mesh.AddConnectHandler(null);
3851
- }
3852
-
3853
- function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
3854
- function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
3855
- function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
3856
-
3857
- function onWebSocketUpgrade(response, s, head) {
3858
- sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
3859
- this.s = s;
3860
- s.httprequest = this;
3861
- s.end = onWebSocketClosed;
3862
- s.data = onWebSocketData;
3863
- }
3864
-
3865
- // Get Intel MEI State in a flexible way
3866
- // Flags: 1 = Versions, 2 = OsAdmin, 4 = Hashes, 8 = Network
3867
- function getMeiState(flags, func) {
3868
- var amtMeiModule, amtMei;
3869
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { func(null); return; }
3870
- amtMei.on('error', function (e) { func(null); return; });
3871
- try {
3872
- var amtMeiTmpState = { OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
3873
- amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
3874
- if ((flags & 1) != 0) { amtMei.getVersion(function (result) { if (result) { amtMeiTmpState.Versions = {}; for (var version in result.Versions) { amtMeiTmpState.Versions[result.Versions[version].Description] = result.Versions[version].Version; } } }); }
3875
- amtMei.getProvisioningMode(function (result) { if (result) { amtMeiTmpState.ProvisioningMode = result.mode; } });
3876
- amtMei.getProvisioningState(function (result) { if (result) { amtMeiTmpState.ProvisioningState = result.state; } }); // 0: "Not Activated (Pre)", 1: "Not Activated (In)", 2: "Activated"
3877
- amtMei.getEHBCState(function (result) { if ((result != null) && (result.EHBC == true)) { amtMeiTmpState.Flags += 1; } });
3878
- amtMei.getControlMode(function (result) { if (result != null) { if (result.controlMode == 1) { amtMeiTmpState.Flags += 2; } if (result.controlMode == 2) { amtMeiTmpState.Flags += 4; } } }); // Flag 2 = CCM, 4 = ACM
3879
- //amtMei.getMACAddresses(function (result) { if (result) { amtMeiTmpState.mac = result; } });
3880
- if ((flags & 8) != 0) {
3881
- amtMei.getLanInterfaceSettings(0, function (result) {
3882
- if (result) {
3883
- amtMeiTmpState.net0 = result;
3884
- var fqdn = null, interfaces = require('os').networkInterfaces(); // Look for the DNS suffix for the Intel AMT Ethernet interface
3885
- for (var i in interfaces) { for (var j in interfaces[i]) { if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { amtMeiTmpState.OsDnsSuffix = interfaces[i][j].fqdn; } } }
3886
- }
3887
- });
3888
- amtMei.getLanInterfaceSettings(1, function (result) { if (result) { amtMeiTmpState.net1 = result; } });
3889
- }
3890
- amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { amtMeiTmpState.UUID = result.uuid; } });
3891
- if ((flags & 2) != 0) { amtMei.getLocalSystemAccount(function (x) { if ((x != null) && x.user && x.pass) { amtMeiTmpState.OsAdmin = { user: x.user, pass: x.pass }; } }); }
3892
- amtMei.getDnsSuffix(function (result) { if (result != null) { amtMeiTmpState.DnsSuffix = result; } if ((flags & 4) == 0) { if (func != null) { func(amtMeiTmpState); } } });
3893
- if ((flags & 4) != 0) {
3894
- amtMei.getHashHandles(function (handles) {
3895
- if ((handles != null) && (handles.length > 0)) { amtMeiTmpState.Hashes = []; } else { func(amtMeiTmpState); }
3896
- var exitOnCount = handles.length;
3897
- for (var i = 0; i < handles.length; ++i) { this.getCertHashEntry(handles[i], function (hashresult) { amtMeiTmpState.Hashes.push(hashresult); if (--exitOnCount == 0) { if (func != null) { func(amtMeiTmpState); } } }); }
3898
- });
3899
- }
3900
- } catch (e) { if (func != null) { func(null); } return; }
3901
- }
3902
-
3903
- return obj;
3904
-}
3905
-
3906
-//
3907
-// Module startup
3908
-//
3909
-
3910
-try {
3911
- var xexports = null, mainMeshCore = null;
3912
- try { xexports = module.exports; } catch (e) { }
3913
-
3914
- if (xexports != null) {
3915
- // If we are running within NodeJS, export the core
3916
- module.exports.createMeshCore = createMeshCore;
3917
- } else {
3918
- // If we are not running in NodeJS, launch the core
3919
- mainMeshCore = createMeshCore();
3920
- mainMeshCore.start(null);
3921
- }
3922
-} catch (e) {
3923
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException2: " + ex });
3924
-}
agents/meshcore-old.js
deleted
-3903
@@ -1,3903 +0,0 @@
1
-/*
2
-Copyright 2018-2020 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
-
21
-// NOTE: This seems to cause big problems, don't enable the debugger in the server's meshcore.
22
-//attachDebugger({ webport: 9999, wait: 1 }).then(function (prt) { console.log('Point Browser for Debug to port: ' + prt); });
23
-
24
-// Mesh Rights
25
-var MNG_ERROR = 65;
26
-var MESHRIGHT_EDITMESH = 1;
27
-var MESHRIGHT_MANAGEUSERS = 2;
28
-var MESHRIGHT_MANAGECOMPUTERS = 4;
29
-var MESHRIGHT_REMOTECONTROL = 8;
30
-var MESHRIGHT_AGENTCONSOLE = 16;
31
-var MESHRIGHT_SERVERFILES = 32;
32
-var MESHRIGHT_WAKEDEVICE = 64;
33
-var MESHRIGHT_SETNOTES = 128;
34
-var MESHRIGHT_REMOTEVIEW = 256;
35
-var MESHRIGHT_NOTERMINAL = 512;
36
-var MESHRIGHT_NOFILES = 1024;
37
-var MESHRIGHT_NOAMT = 2048;
38
-var MESHRIGHT_LIMITEDINPUT = 4096;
39
-var MESHRIGHT_LIMITEVENTS = 8192;
40
-var MESHRIGHT_CHATNOTIFY = 16384;
41
-var MESHRIGHT_UNINSTALL = 32768;
42
-var MESHRIGHT_NODESKTOP = 65536;
43
-
44
-function createMeshCore(agent) {
45
- var obj = {};
46
- if (process.platform == 'win32' && require('user-sessions').isRoot()) {
47
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
48
- try {
49
- var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
50
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
51
- if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
52
- } catch (x) { }
53
-
54
- // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
55
- try {
56
- var meshCheck = false;
57
- try { meshCheck = require('service-manager').manager.getService('Mesh Agent').isMe(); } catch (e) { }
58
- if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService('Mesh Agent')) { require('win-bcd').enableSafeModeService('Mesh Agent'); }
59
- } catch (e) { }
60
- }
61
-
62
- if (process.platform == 'darwin' && !process.versions) {
63
- // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
64
- var child = require('child_process').execFile('/bin/sh', ['sh']);
65
- child.stdout.str = '';
66
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
67
- 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, \">\"); ");
68
- 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]; } }");
69
- child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
70
- child.waitExit();
71
- if (child.stdout.str.trim() == 'Crashed') {
72
- child = require('child_process').execFile('/bin/sh', ['sh']);
73
- child.stdout.str = '';
74
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
75
- child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
76
- child.waitExit();
77
-
78
- if (parseInt(child.stdout.str.trim()) == process.pid) {
79
- // The currently running MeshAgent is us, so we can continue with the update
80
- var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
81
- var tokens = plist.split('<key>KeepAlive</key>');
82
- if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
83
- var tmp = tokens[1].split('</dict>');
84
- tmp.shift();
85
- tokens[1] = '\n <true/>' + tmp.join('</dict>');
86
- tokens = tokens.join('<key>KeepAlive</key>');
87
-
88
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
89
-
90
- var fix = '';
91
- fix += ("function macosRepair()\n");
92
- fix += ("{\n");
93
- fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
94
- fix += (" child.stdout.str = '';\n");
95
- fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
96
- fix += (" child.stderr.on('data', function (chunk) { });\n");
97
- fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
98
- fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
99
- fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
100
- fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
101
- fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
102
- fix += (" child.waitExit();\n");
103
- fix += ("}\n");
104
- fix += ("macosRepair();\n");
105
- fix += ("process.exit();\n");
106
- require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
107
-
108
- var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
109
- plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
110
- plist += '<plist version="1.0">\n';
111
- plist += ' <dict>\n';
112
- plist += ' <key>Label</key>\n';
113
- plist += (' <string>meshagentRepair</string>\n');
114
- plist += ' <key>ProgramArguments</key>\n';
115
- plist += ' <array>\n';
116
- plist += (' <string>' + process.execPath + '</string>\n');
117
- plist += ' <string>macosRepair.js</string>\n';
118
- plist += ' </array>\n';
119
- plist += ' <key>WorkingDirectory</key>\n';
120
- plist += (' <string>' + process.cwd() + '</string>\n');
121
- plist += ' <key>RunAtLoad</key>\n';
122
- plist += ' <true/>\n';
123
- plist += ' </dict>\n';
124
- plist += '</plist>';
125
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
126
-
127
- child = require('child_process').execFile('/bin/sh', ['sh']);
128
- child.stdout.str = '';
129
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
130
- child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
131
- child.waitExit();
132
- }
133
- }
134
- }
135
- }
136
-
137
- // Create Secure IPC for Diagnostic Agent Communications
138
- obj.DAIPC = require('net').createServer();
139
- if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
140
- obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
141
- try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
142
- obj.DAIPC._daipc = [];
143
- obj.DAIPC.on('connection', function (c) {
144
- c._send = function (j) {
145
- var data = JSON.stringify(j);
146
- var packet = Buffer.alloc(data.length + 4);
147
- packet.writeUInt32LE(data.length + 4, 0);
148
- Buffer.from(data).copy(packet, 4);
149
- this.write(packet);
150
- };
151
- this._daipc.push(c);
152
- c.parent = this;
153
- c.on('end', function () { removeRegisteredApp(this); });
154
- c.on('data', function (chunk) {
155
- if (chunk.length < 4) { this.unshift(chunk); return; }
156
- var len = chunk.readUInt32LE(0);
157
- if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
158
- if (chunk.length < len) { this.unshift(chunk); return; }
159
-
160
- var data = chunk.slice(4, len);
161
- try { data = JSON.parse(data.toString()); } catch (e) { }
162
- if ((data == null) || (typeof data.cmd != 'string')) return;
163
-
164
- try {
165
- switch (data.cmd) {
166
- case 'requesthelp':
167
- if (this._registered == null) return;
168
- sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
169
- var help = {};
170
- help[this._registered] = data.value;
171
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (e) { }
172
- MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
173
- break;
174
- case 'cancelhelp':
175
- if (this._registered == null) return;
176
- sendConsoleText('Cancel Help (' + this._registered + ')');
177
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
178
- break;
179
- case 'register':
180
- if (typeof data.value == 'string') {
181
- this._registered = data.value;
182
- var apps = {};
183
- apps[data.value] = 1;
184
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
185
- this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
186
- }
187
- break;
188
- case 'query':
189
- switch (data.value) {
190
- case 'connection':
191
- data.result = require('MeshAgent').ConnectedServer;
192
- this._send(data);
193
- break;
194
- case 'descriptors':
195
- require('ChainViewer').getSnapshot().then(function (f) {
196
- this.tag.payload.result = f;
197
- this.tag.ipc._send(this.tag.payload);
198
- }).parentPromise.tag = { ipc: this, payload: data };
199
- break;
200
- }
201
- break;
202
- case 'amtstate':
203
- if (amt == null) return;
204
- var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
205
- func.pipe = this;
206
- amt.getAmtInfo(func);
207
- break;
208
- case 'sessions':
209
- this._send({ cmd: 'sessions', sessions: tunnelUserCount });
210
- break;
211
- }
212
- }
213
- catch (e) { removeRegisteredApp(this); this.end(); return; }
214
- });
215
- });
216
-
217
- // Send current sessions to registered apps
218
- function broadcastSessionsToRegisteredApps(x) {
219
- broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
220
- }
221
-
222
- // Send this object to all registered local applications
223
- function broadcastToRegisteredApps(x) {
224
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
225
- for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); } }
226
- }
227
-
228
- // Send list of registered apps to the server
229
- function updateRegisteredAppsToServer() {
230
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
231
- var apps = {};
232
- 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]++; } }
233
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
234
- }
235
-
236
- // Remove a registered app
237
- function removeRegisteredApp(pipe) {
238
- for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
239
- if (pipe._registered != null) updateRegisteredAppsToServer();
240
- }
241
-
242
- function diagnosticAgent_uninstall() {
243
- require('service-manager').manager.uninstallService('meshagentDiagnostic');
244
- require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
245
- };
246
- function diagnosticAgent_installCheck(install) {
247
- try {
248
- var diag = require('service-manager').manager.getService('meshagentDiagnostic');
249
- return (diag);
250
- }
251
- catch (e) {
252
- }
253
- if (!install) { return (null); }
254
-
255
- var svc = null;
256
- try {
257
- require('service-manager').manager.installService(
258
- {
259
- name: 'meshagentDiagnostic',
260
- displayName: "Mesh Agent Diagnostic Service",
261
- description: "Mesh Agent Diagnostic Service",
262
- servicePath: process.execPath,
263
- parameters: ['-recovery']
264
- //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
265
- });
266
- svc = require('service-manager').manager.getService('meshagentDiagnostic');
267
- }
268
- catch (e) {
269
- return (null);
270
- }
271
- var proxyConfig = require('global-tunnel').proxyConfig;
272
- var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
273
- var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
274
- ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
275
- ddb.Put('disableUpdate', '1');
276
- ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
277
- ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
278
- ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
279
- if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
280
- if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
281
- if (proxyConfig) {
282
- ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
283
- } else {
284
- ddb.Put('ignoreProxyFile', '1');
285
- }
286
-
287
- require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
288
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
289
-
290
- delete ddb;
291
-
292
- // Set a recurrent task, to run the Diagnostic Agent every 2 days
293
- 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' });
294
- //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
295
-
296
- return (svc);
297
- }
298
-
299
- // Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
300
- if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
301
- // Setup manual battery monitoring
302
- require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
303
- if (require('MeshAgent')._batteryFileTimer != null) return;
304
- require('MeshAgent')._batteryFileTimer = setTimeout(function () {
305
- try {
306
- require('MeshAgent')._batteryFileTimer = null;
307
- var data = null;
308
- try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
309
- if ((data != null) && (data.length < 10)) {
310
- data = data.split(',');
311
- if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
312
- var level = parseInt(data[1]);
313
- if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
314
- }
315
- }
316
- } catch (e) { }
317
- }, 1000);
318
- });
319
- } else {
320
- // Setup normal battery monitoring
321
- if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) {
322
- require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
323
- _battLevelChanged.self._currentBatteryLevel = val;
324
- _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
325
- };
326
- require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
327
- require('MeshAgent')._powerChanged = function _powerChanged(val) {
328
- _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
329
- _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
330
- };
331
- require('MeshAgent')._powerChanged.self = require('MeshAgent');
332
- require('MeshAgent').on('Connected', function (status) {
333
- if (status == 0) {
334
- require('power-monitor').removeListener('acdc', this._powerChanged);
335
- require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
336
- } else {
337
- require('power-monitor').on('acdc', this._powerChanged);
338
- require('power-monitor').on('batteryLevel', this._battLevelChanged);
339
- }
340
- });
341
- }
342
- }
343
-
344
-
345
- /*
346
- function borderController() {
347
- this.container = null;
348
- this.Start = function Start(user) {
349
- if (this.container == null) {
350
- if (process.platform == 'win32') {
351
- try {
352
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.SessionId });
353
- } catch (e) {
354
- this.container = require('ScriptContainer').Create({ processIsolation: 1 });
355
- }
356
- } else {
357
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.uid });
358
- }
359
- this.container.parent = this;
360
- this.container.addModule('monitor-info', getJSModule('monitor-info'));
361
- this.container.addModule('monitor-border', getJSModule('monitor-border'));
362
- this.container.addModule('promise', getJSModule('promise'));
363
- this.container.once('exit', function (code) { sendConsoleText('Border Process Exited with code: ' + code); this.parent.container = this.parent._container = null; });
364
- this.container.ExecuteString("var border = require('monitor-border'); border.Start();");
365
- }
366
- }
367
- this.Stop = function Stop() {
368
- if (this.container != null) {
369
- this._container = this.container;
370
- this._container.parent = this;
371
- this.container = null;
372
- this._container.exit();
373
- }
374
- }
375
- }
376
- obj.borderManager = new borderController();
377
- */
378
-
379
- // MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
380
- var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? ('MeshCore CRC-' + 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
381
-
382
-
383
- // Get the operating system description string
384
- try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; }); } catch (e) { }
385
-
386
- var meshServerConnectionState = 0;
387
- var tunnels = {};
388
- var lastMeInfo = null;
389
- var lastNetworkInfo = null;
390
- var lastPublicLocationInfo = null;
391
- var selfInfoUpdateTimer = null;
392
- var http = require('http');
393
- var net = require('net');
394
- var fs = require('fs');
395
- var rtc = require('ILibWebRTC');
396
- var amt = null;
397
- var processManager = require('process-manager');
398
- var wifiScannerLib = null;
399
- var wifiScanner = null;
400
- var networkMonitor = null;
401
- var amtscanner = null;
402
- var nextTunnelIndex = 1;
403
- var amtPolicy = null;
404
- var apftunnel = null;
405
- var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
406
-
407
- // Add to the server event log
408
- function MeshServerLog(msg, state) {
409
- if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
410
- if (state) {
411
- if (state.userid) { msg.userid = state.userid; }
412
- if (state.username) { msg.username = state.username; }
413
- if (state.sessionid) { msg.sessionid = state.sessionid; }
414
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
415
- }
416
- mesh.SendCommand(msg);
417
- }
418
-
419
- // Add to the server event log, use internationalized events
420
- function MeshServerLogEx(id, args, msg, state) {
421
- var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
422
- if (state) {
423
- if (state.userid) { msg.userid = state.userid; }
424
- if (state.username) { msg.username = state.username; }
425
- if (state.sessionid) { msg.sessionid = state.sessionid; }
426
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
427
- }
428
- mesh.SendCommand(msg);
429
- }
430
-
431
- // If we are running in Duktape, agent will be null
432
- if (agent == null) {
433
- // Running in native agent, Import libraries
434
- db = require('SimpleDataStore').Shared();
435
- sha = require('SHA256Stream');
436
- mesh = require('MeshAgent');
437
- childProcess = require('child_process');
438
- if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
439
- // Check if this computer supports a desktop
440
- try
441
- {
442
- if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support))
443
- {
444
- meshCoreObj.caps |= 1;
445
- }
446
- else if(process.platform == 'linux' || process.platform == 'freebsd')
447
- {
448
- require('monitor-info').on('kvmSupportDetected', function (value)
449
- {
450
- meshCoreObj.caps |= 1;
451
- mesh.SendCommand(meshCoreObj);
452
- });
453
- }
454
- } catch (e) { }
455
- }
456
- } else {
457
- // Running in nodejs
458
- meshCoreObj.value += '-NodeJS';
459
- meshCoreObj.caps = 8;
460
- mesh = agent.getMeshApi();
461
- }
462
-
463
- mesh.DAIPC = obj.DAIPC;
464
-
465
- /*
466
- var AMTScanner = require("AMTScanner");
467
- var scan = new AMTScanner();
468
-
469
- scan.on("found", function (data) {
470
- if (typeof data === 'string') {
471
- console.log(data);
472
- } else {
473
- console.log(JSON.stringify(data, null, " "));
474
- }
475
- });
476
- scan.scan("10.2.55.140", 1000);
477
- scan.scan("10.2.55.139-10.2.55.145", 1000);
478
- scan.scan("10.2.55.128/25", 2000);
479
- */
480
-
481
- /*
482
- // Try to load up the network monitor
483
- try {
484
- networkMonitor = require('NetworkMonitor');
485
- networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
486
- networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
487
- networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
488
- } catch (e) { networkMonitor = null; }
489
- */
490
-
491
- // Try to load up the Intel AMT scanner
492
- try {
493
- var AMTScannerModule = require('amt-scanner');
494
- amtscanner = new AMTScannerModule();
495
- //amtscanner.on('found', function (data) { if (typeof data != 'string') { data = JSON.stringify(data, null, " "); } sendConsoleText(data); });
496
- } catch (e) { amtscanner = null; }
497
-
498
- // Fetch the SMBios Tables
499
- var SMBiosTables = null;
500
- var SMBiosTablesRaw = null;
501
- try {
502
- var SMBiosModule = null;
503
- try { SMBiosModule = require('smbios'); } catch (e) { }
504
- if (SMBiosModule != null) {
505
- SMBiosModule.get(function (data) {
506
- if (data != null) {
507
- SMBiosTablesRaw = data;
508
- SMBiosTables = require('smbios').parse(data)
509
- if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
510
-
511
- // If SMBios tables say that Intel AMT is present, try to connect MEI
512
- if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true))
513
- {
514
- var amtmodule = require('amt-manage');
515
- amt = new amtmodule(mesh, db, false);
516
- amt.on('portBinding_LMS', function (map)
517
- {
518
- var j = { action: 'lmsinfo', value: { ports: map.keys() } };
519
- mesh.SendCommand(j);
520
- });
521
- amt.on('stateChange_LMS', function (v)
522
- {
523
- if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; }
524
- switch(v)
525
- {
526
- case 0:
527
- meshCoreObj.intelamt.microlms = 'DISABLED';
528
- break;
529
- case 1:
530
- meshCoreObj.intelamt.microlms = 'CONNECTING';
531
- break;
532
- case 2:
533
- meshCoreObj.intelamt.microlms = 'CONNECTED';
534
- break;
535
- default:
536
- break;
537
- }
538
- mesh.SendCommand(meshCoreObj);
539
- });
540
- amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } }
541
- if (amtPolicy != null) { amt.setPolicy(amtPolicy); }
542
- amt.start();
543
- }
544
- }
545
- });
546
- }
547
- } catch (e) { sendConsoleText("ex1: " + e); }
548
-
549
- // Try to load up the WIFI scanner
550
- try {
551
- var wifiScannerLib = require('wifi-scanner');
552
- wifiScanner = new wifiScannerLib();
553
- wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
554
- } catch (e) { wifiScannerLib = null; wifiScanner = null; }
555
-
556
- // Get our location (lat/long) using our public IP address
557
- var getIpLocationDataExInProgress = false;
558
- var getIpLocationDataExCounts = [0, 0];
559
- function getIpLocationDataEx(func) {
560
- if (getIpLocationDataExInProgress == true) { return false; }
561
- try {
562
- getIpLocationDataExInProgress = true;
563
- getIpLocationDataExCounts[0]++;
564
- var options = http.parseUri("http://ipinfo.io/json");
565
- options.method = 'GET';
566
- http.request(options, function (resp) {
567
- if (resp.statusCode == 200) {
568
- var geoData = '';
569
- resp.data = function (geoipdata) { geoData += geoipdata; };
570
- resp.end = function () {
571
- var location = null;
572
- try {
573
- if (typeof geoData == 'string') {
574
- var result = JSON.parse(geoData);
575
- if (result.ip && result.loc) { location = result; }
576
- }
577
- } catch (e) { }
578
- if (func) { getIpLocationDataExCounts[1]++; func(location); }
579
- }
580
- } else { func(null); }
581
- getIpLocationDataExInProgress = false;
582
- }).end();
583
- return true;
584
- }
585
- catch (e) { return false; }
586
- }
587
-
588
- // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
589
- function clearGatewayMac(str) {
590
- if (str == null) return null;
591
- var x = JSON.parse(str);
592
- for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
593
- return JSON.stringify(x);
594
- }
595
-
596
- function getIpLocationData(func) {
597
- // Get the location information for the cache if possible
598
- var publicLocationInfo = db.Get('publicLocationInfo');
599
- if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
600
- if (publicLocationInfo == null) {
601
- // Nothing in the cache, fetch the data
602
- getIpLocationDataEx(function (locationData) {
603
- if (locationData != null) {
604
- publicLocationInfo = {};
605
- publicLocationInfo.netInfoStr = lastNetworkInfo;
606
- publicLocationInfo.locationData = locationData;
607
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
608
- if (func) func(locationData); // Report the new location
609
- } else {
610
- if (func) func(null); // Report no location
611
- }
612
- });
613
- } else {
614
- // Check the cache
615
- if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
616
- // Cache match
617
- if (func) func(publicLocationInfo.locationData);
618
- } else {
619
- // Cache mismatch
620
- getIpLocationDataEx(function (locationData) {
621
- if (locationData != null) {
622
- publicLocationInfo = {};
623
- publicLocationInfo.netInfoStr = lastNetworkInfo;
624
- publicLocationInfo.locationData = locationData;
625
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
626
- if (func) func(locationData); // Report the new location
627
- } else {
628
- if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
629
- }
630
- });
631
- }
632
- }
633
- }
634
-
635
- // Polyfill String.endsWith
636
- if (!String.prototype.endsWith) {
637
- String.prototype.endsWith = function (searchString, position) {
638
- var subjectString = this.toString();
639
- if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
640
- position -= searchString.length;
641
- var lastIndex = subjectString.lastIndexOf(searchString, position);
642
- return lastIndex !== -1 && lastIndex === position;
643
- };
644
- }
645
-
646
- // Polyfill path.join
647
- obj.path = {
648
- join: function () {
649
- var x = [];
650
- for (var i in arguments) {
651
- var w = arguments[i];
652
- if (w != null) {
653
- while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
654
- if (i != 0) {
655
- while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
656
- }
657
- x.push(w);
658
- }
659
- }
660
- if (x.length == 0) return '/';
661
- return x.join('/');
662
- }
663
- };
664
-
665
- // Replace a string with a number if the string is an exact number
666
- function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
667
-
668
- // Convert decimal to hex
669
- function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
670
-
671
- // Convert a raw string to a hex string
672
- function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
673
-
674
- // Convert a buffer into a string
675
- function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
676
-
677
- // Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
678
- function hex2rstr(d) {
679
- if (typeof d != "string" || d.length == 0) return '';
680
- var r = '', m = ('' + d).match(/../g), t;
681
- while (t = m.shift()) r += String.fromCharCode('0x' + t);
682
- return r
683
- }
684
-
685
- // Convert an object to string with all functions
686
- function objToString(x, p, pad, ret) {
687
- if (ret == undefined) ret = '';
688
- if (p == undefined) p = 0;
689
- if (x == null) { return '[null]'; }
690
- if (p > 8) { return '[...]'; }
691
- if (x == undefined) { return '[undefined]'; }
692
- if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; }
693
- if (typeof x == 'buffer') { return '[buffer]'; }
694
- if (typeof x != 'object') { return x; }
695
- var r = '{' + (ret ? '\r\n' : ' ');
696
- for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
697
- return r + addPad(p, pad) + '}';
698
- }
699
-
700
- // Return p number of spaces
701
- function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
702
-
703
- // Split a string taking into account the quoats. Used for command line parsing
704
- function splitArgs(str) {
705
- var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
706
- do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
707
- return myArray;
708
- }
709
-
710
- // Parse arguments string array into an object
711
- function parseArgs(argv) {
712
- var results = { '_': [] }, current = null;
713
- for (var i = 1, len = argv.length; i < len; i++) {
714
- var x = argv[i];
715
- if (x.length > 2 && x[0] == '-' && x[1] == '-') {
716
- if (current != null) { results[current] = true; }
717
- current = x.substring(2);
718
- } else {
719
- if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
720
- }
721
- }
722
- if (current != null) { results[current] = true; }
723
- return results;
724
- }
725
-
726
- // Get server target url with a custom path
727
- function getServerTargetUrl(path) {
728
- var x = mesh.ServerUrl;
729
- //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
730
- if (x == null) { return null; }
731
- if (path == null) { path = ''; }
732
- x = http.parseUri(x);
733
- if (x == null) return null;
734
- return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
735
- }
736
-
737
- // Get server url. If the url starts with "*/..." change it, it not use the url as is.
738
- function getServerTargetUrlEx(url) {
739
- if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
740
- return url;
741
- }
742
-
743
- // Send a wake-on-lan packet
744
- function sendWakeOnLan(hexMac) {
745
- hexMac = hexMac.split(':').join('');
746
- var count = 0;
747
- try {
748
- var interfaces = require('os').networkInterfaces();
749
- var magic = 'FFFFFFFFFFFF';
750
- for (var x = 1; x <= 16; ++x) { magic += hexMac; }
751
- var magicbin = Buffer.from(magic, 'hex');
752
-
753
- for (var adapter in interfaces) {
754
- if (interfaces.hasOwnProperty(adapter)) {
755
- for (var i = 0; i < interfaces[adapter].length; ++i) {
756
- var addr = interfaces[adapter][i];
757
- if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
758
- try {
759
- var socket = require('dgram').createSocket({ type: 'udp4' });
760
- socket.bind({ address: addr.address });
761
- socket.setBroadcast(true);
762
- socket.setMulticastInterface(addr.address);
763
- socket.setMulticastTTL(1);
764
- socket.send(magicbin, 7, '255.255.255.255');
765
- socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')';
766
- count++;
767
- }
768
- catch (e) { }
769
- }
770
- }
771
- }
772
- }
773
- } catch (e) { }
774
- return count;
775
- }
776
-
777
- // Handle a mesh agent command
778
- function handleServerCommand(data) {
779
- if (typeof data == 'object') {
780
- // If this is a console command, parse it and call the console handler
781
- switch (data.action) {
782
- case 'msg': {
783
- switch (data.type) {
784
- case 'console': { // Process a console command
785
- if (data.value && data.sessionid) {
786
- MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
787
- var args = splitArgs(data.value);
788
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
789
- }
790
- break;
791
- }
792
- case 'tunnel': {
793
- if (data.value != null) { // Process a new tunnel connection request
794
- // Create a new tunnel object
795
- var xurl = getServerTargetUrlEx(data.value);
796
- if (xurl != null) {
797
- xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
798
- var woptions = http.parseUri(xurl);
799
- woptions.perMessageDeflate = false;
800
- if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
801
- woptions.rejectUnauthorized = 0;
802
- //sendConsoleText(JSON.stringify(woptions));
803
- //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
804
- var tunnel = http.request(woptions);
805
- tunnel.upgrade = onTunnelUpgrade;
806
- tunnel.on('error', function (e) { sendConsoleText("ERROR: Unable to connect relay tunnel to: " + this.url + ", " + JSON.stringify(e)); });
807
- tunnel.sessionid = data.sessionid;
808
- tunnel.rights = data.rights;
809
- tunnel.consent = data.consent;
810
- tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}";
811
- tunnel.username = data.username + (data.guestname ? (' - ' + data.guestname) : '');
812
- tunnel.realname = (data.realname ? data.realname : data.username) + (data.guestname ? (' - ' + data.guestname) : '');
813
- tunnel.userid = data.userid;
814
- tunnel.remoteaddr = data.remoteaddr;
815
- tunnel.state = 0;
816
- tunnel.url = xurl;
817
- tunnel.protocol = 0;
818
- tunnel.soptions = data.soptions;
819
- tunnel.tcpaddr = data.tcpaddr;
820
- tunnel.tcpport = data.tcpport;
821
- tunnel.udpaddr = data.udpaddr;
822
- tunnel.udpport = data.udpport;
823
- tunnel.end();
824
- // Put the tunnel in the tunnels list
825
- var index = nextTunnelIndex++;
826
- tunnel.index = index;
827
- tunnels[index] = tunnel;
828
-
829
- //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
830
- }
831
- }
832
- break;
833
- }
834
- case 'messagebox': {
835
- // Display a message box
836
- if (data.title && data.msg) {
837
- MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
838
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
839
- try { require('message-box').create(data.title, data.msg, 120); } catch (e) { }
840
- }
841
- break;
842
- }
843
- case 'ps': {
844
- // Return the list of running processes
845
- if (data.sessionid) {
846
- processManager.getProcesses(function (plist) {
847
- mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
848
- });
849
- }
850
- break;
851
- }
852
- case 'pskill': {
853
- // Kill a process
854
- if (data.value) {
855
- MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
856
- try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
857
- }
858
- break;
859
- }
860
- case 'services': {
861
- // Return the list of installed services
862
- var services = null;
863
- try { services = require('service-manager').manager.enumerateService(); } catch (e) { }
864
- if (services != null) { mesh.SendCommand({ action: 'msg', type: 'services', value: JSON.stringify(services), sessionid: data.sessionid }); }
865
- break;
866
- }
867
- case 'serviceStop': {
868
- // Stop a service
869
- try {
870
- var service = require('service-manager').manager.getService(data.serviceName);
871
- if (service != null) { service.stop(); }
872
- } catch (e) { }
873
- break;
874
- }
875
- case 'serviceStart': {
876
- // Start a service
877
- try {
878
- var service = require('service-manager').manager.getService(data.serviceName);
879
- if (service != null) { service.start(); }
880
- } catch (e) { }
881
- break;
882
- }
883
- case 'serviceRestart': {
884
- // Restart a service
885
- try {
886
- var service = require('service-manager').manager.getService(data.serviceName);
887
- if (service != null) { service.restart(); }
888
- } catch (e) { }
889
- break;
890
- }
891
- case 'deskBackground':
892
- {
893
- // Toggle desktop background
894
- try {
895
- if (process.platform == 'win32') {
896
- var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
897
- var sid = undefined;
898
- if (stype == 1) {
899
- if (require('MeshAgent')._tsid != null) {
900
- stype = 5;
901
- sid = require('MeshAgent')._tsid;
902
- }
903
- }
904
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
905
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: stype, uid: sid });
906
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
907
- child.stderr.on('data', function () { });
908
- child.waitExit();
909
- var current = child.stdout.str.trim();
910
- if (current != '') { require('MeshAgent')._wallpaper = current; }
911
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: stype, uid: sid });
912
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
913
- child.stderr.on('data', function () { });
914
- child.waitExit();
915
- } else {
916
- var id = require('user-sessions').consoleUid();
917
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
918
- if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
919
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
920
- }
921
- } catch (e) {
922
- sendConsoleText(e);
923
- }
924
- break;
925
- }
926
- case 'openUrl': {
927
- // Open a local web browser and return success/fail
928
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
929
- sendConsoleText("OpenURL: " + data.url);
930
- if (data.url) { mesh.SendCommand({ action: 'msg', type: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
931
- break;
932
- }
933
- case 'getclip': {
934
- // Send the load clipboard back to the user
935
- //sendConsoleText('getClip: ' + JSON.stringify(data));
936
- if (require('MeshAgent').isService) {
937
- require('clipboard').dispatchRead().then(function (str) {
938
- if (str) {
939
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
940
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
941
- }
942
- });
943
- } else {
944
- require("clipboard").read().then(function (str) {
945
- if (str) {
946
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
947
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
948
- }
949
- });
950
- }
951
- break;
952
- }
953
- case 'setclip': {
954
- // Set the load clipboard to a user value
955
- //sendConsoleText('setClip: ' + JSON.stringify(data));
956
- if (typeof data.data == 'string') {
957
- MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
958
- if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
959
- mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
960
- }
961
- break;
962
- }
963
- case 'userSessions': {
964
- // Send back current user sessions list, this is Windows only.
965
- //sendConsoleText('userSessions: ' + JSON.stringify(data));
966
- if (process.platform != 'win32') break;
967
- var p = require('user-sessions').enumerateUsers();
968
- p.sessionid = data.sessionid;
969
- p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u, tag: data.tag }); });
970
- break;
971
- }
972
- default:
973
- // Unknown action, ignore it.
974
- break;
975
- }
976
- break;
977
- }
978
- case 'acmactivate': {
979
- if (amt != null) {
980
- MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
981
- amt.setAcmResponse(data);
982
- }
983
- break;
984
- }
985
- case 'wakeonlan': {
986
- // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
987
- sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
988
- for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
989
- break;
990
- }
991
- case 'runcommands': {
992
- if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; }
993
- sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds);
994
-
995
- // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
996
- var options = {};
997
- if (data.runAsUser > 0) {
998
- try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
999
- options.type = require('child_process').SpawnTypes.TERM;
1000
- }
1001
- if (data.runAsUser == 2) {
1002
- if (options.uid == null) break;
1003
- if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1004
- }
1005
-
1006
- if (process.platform == 'win32') {
1007
- if (data.type == 1) {
1008
- // Windows command shell
1009
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1010
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1011
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1012
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1013
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1014
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1015
- } else if (data.type == 2) {
1016
- // Windows Powershell
1017
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1018
- mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
1019
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1020
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1021
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1022
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1023
- }
1024
- } else if (data.type == 3) {
1025
- // Linux shell
1026
- mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1027
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1028
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1029
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1030
- mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
1031
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1032
- }
1033
- break;
1034
- }
1035
- case 'uninstallagent':
1036
- // Uninstall this agent
1037
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1038
- if (require('service-manager').manager.getService(agentName).isMe()) {
1039
- try { diagnosticAgent_uninstall(); } catch (e) { }
1040
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1041
- 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 });
1042
- }
1043
- break;
1044
- case 'poweraction': {
1045
- // Server telling us to execute a power action
1046
- if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
1047
- var forced = 0;
1048
- if (data.forced == 1) { forced = 1; }
1049
- data.actiontype = parseInt(data.actiontype);
1050
- MeshServerLogEx(25, [data.actiontype, forced], "Performing power action=" + data.actiontype + ", forced=" + forced, data);
1051
- sendConsoleText("Performing power action=" + data.actiontype + ", forced=" + forced + '.');
1052
- var r = mesh.ExecPowerState(data.actiontype, forced);
1053
- sendConsoleText("ExecPowerState returned code: " + r);
1054
- }
1055
- break;
1056
- }
1057
- case 'iplocation': {
1058
- // 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
1059
- getIpLocationData(function (location) { mesh.SendCommand({ action: 'iplocation', type: 'publicip', value: location }); });
1060
- break;
1061
- }
1062
- case 'toast': {
1063
- // Display a toast message
1064
- if (data.title && data.msg) {
1065
- MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1066
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1067
- try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
1068
- }
1069
- break;
1070
- }
1071
- case 'openUrl': {
1072
- // Open a local web browser and return success/fail
1073
- //sendConsoleText('OpenURL: ' + data.url);
1074
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1075
- if (data.url) { mesh.SendCommand({ action: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1076
- break;
1077
- }
1078
- case 'amtPolicy': {
1079
- // Store the latest Intel AMT policy
1080
- amtPolicy = data.amtPolicy;
1081
- if (data.amtPolicy != null) { db.Put('amtPolicy', JSON.stringify(data.amtPolicy)); } else { db.Put('amtPolicy', null); }
1082
- if (amt != null) { amt.setPolicy(amtPolicy, true); }
1083
- break;
1084
- }
1085
- case 'getScript': {
1086
- // Received a configuration script from the server
1087
- sendConsoleText('getScript: ' + JSON.stringify(data));
1088
- break;
1089
- }
1090
- case 'sysinfo': {
1091
- // Fetch system information
1092
- getSystemInformation(function (results) {
1093
- if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1094
- });
1095
- break;
1096
- }
1097
- case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
1098
- case 'pong': { break; }
1099
- case 'plugin': {
1100
- try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; }
1101
- break;
1102
- }
1103
- case 'coredump':
1104
- // Set the current agent coredump situation.
1105
- if (data.value === true) {
1106
- // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1107
- process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
1108
- } else if (data.value === false) {
1109
- process.coreDumpLocation = null;
1110
- }
1111
- break;
1112
- case 'getcoredump':
1113
- // Ask the agent if a core dump is currently available, if yes, also return the hash of the agent.
1114
- var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1115
- var coreDumpPath = null;
1116
- if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1117
- if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath))) { r.exists = (db.Get('CoreDumpTime') != require('fs').statSync(coreDumpPath).mtime); }
1118
- if (r.exists == true) { r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); }
1119
- mesh.SendCommand(JSON.stringify(r));
1120
- default:
1121
- // Unknown action, ignore it.
1122
- break;
1123
- }
1124
- }
1125
- }
1126
-
1127
- // Called when a file changed in the file system
1128
- /*
1129
- function onFileWatcher(a, b) {
1130
- console.log('onFileWatcher', a, b, this.path);
1131
- var response = getDirectoryInfo(this.path);
1132
- if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
1133
- }
1134
- */
1135
-
1136
- function getSystemInformation(func) {
1137
- try {
1138
- var results = { hardware: require('identifiers').get() }; // Hardware info
1139
- if (results.hardware && results.hardware.windows) {
1140
- // Remove extra entries and things that change quickly
1141
- var x = results.hardware.windows.osinfo;
1142
- try { delete x.FreePhysicalMemory; } catch (e) { }
1143
- try { delete x.FreeSpaceInPagingFiles; } catch (e) { }
1144
- try { delete x.FreeVirtualMemory; } catch (e) { }
1145
- try { delete x.LocalDateTime; } catch (e) { }
1146
- try { delete x.MaxProcessMemorySize; } catch (e) { }
1147
- try { delete x.TotalVirtualMemorySize; } catch (e) { }
1148
- try { delete x.TotalVisibleMemorySize; } catch (e) { }
1149
- try {
1150
- if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1151
- if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1152
- if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1153
- } catch (e) { }
1154
- }
1155
- if (process.platform == 'win32') { results.pendingReboot = require('win-info').pendingReboot(); } // Pending reboot
1156
- /*
1157
- if (process.platform == 'win32') {
1158
- var defragResult = function (r) {
1159
- if (typeof r == 'object') { results[this.callname] = r; }
1160
- if (this.callname == 'defrag') {
1161
- var pr = require('win-info').installedApps(); // Installed apps
1162
- pr.callname = 'installedApps';
1163
- pr.sessionid = data.sessionid;
1164
- pr.then(defragResult, defragResult);
1165
- }
1166
- else {
1167
- results.winpatches = require('win-info').qfe(); // Windows patches
1168
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1169
- func(results);
1170
- }
1171
- }
1172
- var pr = require('win-info').defrag({ volume: 'C:' }); // Defrag TODO
1173
- pr.callname = 'defrag';
1174
- pr.sessionid = data.sessionid;
1175
- pr.then(defragResult, defragResult);
1176
- } else {
1177
- */
1178
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1179
- func(results);
1180
- //}
1181
- } catch (e) { func(null, e); }
1182
- }
1183
-
1184
- // Get a formated response for a given directory path
1185
- function getDirectoryInfo(reqpath) {
1186
- var response = { path: reqpath, dir: [] };
1187
- if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
1188
- // List all the drives in the root, or the root itself
1189
- var results = null;
1190
- try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1191
- if (results != null) {
1192
- for (var i = 0; i < results.length; ++i) {
1193
- var drive = { n: results[i].name, t: 1 };
1194
- if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1195
- response.dir.push(drive);
1196
- }
1197
- }
1198
- } else {
1199
- // List all the files and folders in this path
1200
- if (reqpath == '') { reqpath = '/'; }
1201
- var results = null, xpath = obj.path.join(reqpath, '*');
1202
- //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1203
- try { results = fs.readdirSync(xpath); } catch (e) { }
1204
- if (results != null) {
1205
- for (var i = 0; i < results.length; ++i) {
1206
- if ((results[i] != '.') && (results[i] != '..')) {
1207
- var stat = null, p = obj.path.join(reqpath, results[i]);
1208
- //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1209
- try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1210
- if ((stat != null) && (stat != undefined)) {
1211
- if (stat.isDirectory() == true) {
1212
- response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1213
- } else {
1214
- response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1215
- }
1216
- }
1217
- }
1218
- }
1219
- }
1220
- }
1221
- return response;
1222
- }
1223
-
1224
- // Tunnel callback operations
1225
- function onTunnelUpgrade(response, s, head) {
1226
- this.s = s;
1227
- s.httprequest = this;
1228
- s.end = onTunnelClosed;
1229
- s.tunnel = this;
1230
- s.descriptorMetadata = "MeshAgent_relayTunnel";
1231
-
1232
- if (require('MeshAgent').idleTimeout != null)
1233
- {
1234
- s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1235
- s.on('timeout', function ()
1236
- {
1237
- this.ping();
1238
- this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1239
- });
1240
- }
1241
-
1242
- //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1243
-
1244
- if (this.tcpport != null) {
1245
- // This is a TCP relay connection, pause now and try to connect to the target.
1246
- s.pause();
1247
- s.data = onTcpRelayServerTunnelData;
1248
- var connectionOptions = { port: parseInt(this.tcpport) };
1249
- if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
1250
- s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
1251
- s.tcprelay.peerindex = this.index;
1252
-
1253
- // Add the TCP session to the count and update the server
1254
- if (s.httprequest.userid != null) {
1255
- if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
1256
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1257
- broadcastSessionsToRegisteredApps();
1258
- }
1259
- } if (this.udpport != null) {
1260
- // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1261
- s.data = onUdpRelayServerTunnelData;
1262
- s.udprelay = require('dgram').createSocket({ type: 'udp4' });
1263
- s.udprelay.bind({ port: 0 });
1264
- s.udprelay.peerindex = this.index;
1265
- s.udprelay.on('message', onUdpRelayTargetTunnelConnect);
1266
- s.udprelay.udpport = this.udpport;
1267
- s.udprelay.udpaddr = this.udpaddr;
1268
- s.udprelay.first = true;
1269
-
1270
- // Add the UDP session to the count and update the server
1271
- if (s.httprequest.userid != null) {
1272
- if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
1273
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1274
- broadcastSessionsToRegisteredApps();
1275
- }
1276
- } else {
1277
- // This is a normal connect for KVM/Terminal/Files
1278
- s.data = onTunnelData;
1279
- }
1280
- }
1281
-
1282
- // Called when UDP relay data is received // TODO****
1283
- function onUdpRelayTargetTunnelConnect(data) {
1284
- var peerTunnel = tunnels[this.peerindex];
1285
- peerTunnel.s.write(data);
1286
- }
1287
-
1288
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1289
- function onUdpRelayServerTunnelData(data) {
1290
- if (this.udprelay.first === true) {
1291
- delete this.udprelay.first; // Skip the first 'c' that is received.
1292
- } else {
1293
- this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1294
- }
1295
- }
1296
-
1297
- // Called when the TCP relay target is connected
1298
- function onTcpRelayTargetTunnelConnect() {
1299
- var peerTunnel = tunnels[this.peerindex];
1300
- this.pipe(peerTunnel.s); // Pipe Target --> Server
1301
- peerTunnel.s.first = true;
1302
- peerTunnel.s.resume();
1303
- }
1304
-
1305
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1306
- function onTcpRelayServerTunnelData(data) {
1307
- if (this.first == true) {
1308
- this.first = false;
1309
- this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1310
- }
1311
- }
1312
-
1313
- function onTunnelClosed() {
1314
- var tunnel = tunnels[this.httprequest.index];
1315
- if (tunnel == null) return; // Stop duplicate calls.
1316
-
1317
- // If this is a routing session, clean up and send the new session counts.
1318
- if (this.httprequest.userid != null) {
1319
- if (this.httprequest.tcpport != null) {
1320
- if (tunnelUserCount.tcp[this.httprequest.userid] != null) { tunnelUserCount.tcp[this.httprequest.userid]--; if (tunnelUserCount.tcp[this.httprequest.userid] <= 0) { delete tunnelUserCount.tcp[this.httprequest.userid]; } }
1321
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1322
- broadcastSessionsToRegisteredApps();
1323
- } else if (this.httprequest.udpport != null) {
1324
- if (tunnelUserCount.udp[this.httprequest.userid] != null) { tunnelUserCount.udp[this.httprequest.userid]--; if (tunnelUserCount.udp[this.httprequest.userid] <= 0) { delete tunnelUserCount.udp[this.httprequest.userid]; } }
1325
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1326
- broadcastSessionsToRegisteredApps();
1327
- }
1328
- }
1329
-
1330
- // Sent tunnel statistics to the server, only send this if compression was used.
1331
- if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString())) {
1332
- mesh.SendCommand({
1333
- action: 'tunnelCloseStats',
1334
- url: tunnel.url,
1335
- userid: tunnel.userid,
1336
- protocol: tunnel.protocol,
1337
- sessionid: tunnel.sessionid,
1338
- sent: this.bytesSent_uncompressed.toString(),
1339
- sentActual: this.bytesSent_actual.toString(),
1340
- sentRatio: this.bytesSent_ratio,
1341
- received: this.bytesReceived_uncompressed.toString(),
1342
- receivedActual: this.bytesReceived_actual.toString(),
1343
- receivedRatio: this.bytesReceived_ratio
1344
- });
1345
- }
1346
-
1347
- //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1348
- if (this.httprequest.index) { delete tunnels[this.httprequest.index]; }
1349
-
1350
- /*
1351
- // Close the watcher if required
1352
- if (this.httprequest.watcher != undefined) {
1353
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
1354
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
1355
- delete this.httprequest.watcher;
1356
- }
1357
- */
1358
-
1359
- // If there is a upload or download active on this connection, close the file
1360
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
1361
- if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1362
-
1363
- // Clean up WebRTC
1364
- if (this.webrtc != null) {
1365
- 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; }
1366
- if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1367
- try { this.webrtc.close(); } catch (e) { }
1368
- this.webrtc.removeAllListeners('connected');
1369
- this.webrtc.removeAllListeners('disconnected');
1370
- this.webrtc.removeAllListeners('dataChannel');
1371
- delete this.webrtc;
1372
- }
1373
-
1374
- // Clean up WebSocket
1375
- this.removeAllListeners('data');
1376
- }
1377
- function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1378
- function onTunnelData(data) {
1379
- //console.log("OnTunnelData");
1380
- //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1381
-
1382
- // If this is upload data, save it to file
1383
- if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
1384
- // Save the data to file being uploaded.
1385
- if (data[0] == 0) {
1386
- // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1387
- 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.
1388
- } else {
1389
- // If data does not start with zero, save as-is.
1390
- 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.
1391
- }
1392
- this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
1393
- return;
1394
- }
1395
-
1396
- if (this.httprequest.state == 0) {
1397
- // Check if this is a relay connection
1398
- if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1399
- }
1400
- else
1401
- {
1402
- // Handle tunnel data
1403
- 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
1404
- // Take a look at the protocol
1405
- if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1406
- this.httprequest.protocol = parseInt(data);
1407
- if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1408
- if (this.httprequest.protocol == 10) {
1409
- //
1410
- // Basic file transfer
1411
- //
1412
- var stats = null;
1413
- if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1414
- try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1415
- try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1416
- if (this.httprequest.downloadFile) {
1417
- //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1418
- this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1419
- this.httprequest.downloadFile.pipe(this);
1420
- this.httprequest.downloadFile.end = function () { }
1421
- } else {
1422
- //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1423
- this.write(JSON.stringify({ op: 'cancel' }));
1424
- }
1425
- }
1426
- else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
1427
- {
1428
- //
1429
- // Remote Terminal
1430
- //
1431
-
1432
- // Check user access rights for terminal
1433
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1434
- // Disengage this tunnel, user does not have the rights to do this!!
1435
- this.httprequest.protocol = 999999;
1436
- this.httprequest.s.end();
1437
- sendConsoleText("Error: No Terminal Control Rights.");
1438
- return;
1439
- }
1440
-
1441
- this.descriptorMetadata = "Remote Terminal";
1442
-
1443
- if (process.platform == 'win32')
1444
- {
1445
- if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
1446
- {
1447
- this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1448
- this.httprequest.s.end();
1449
- return;
1450
- }
1451
- }
1452
-
1453
- var prom = require('promise');
1454
- this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1455
- this.httprequest.tpromise.that = this;
1456
- this.httprequest.tpromise.httprequest = this.httprequest;
1457
-
1458
- this.end = function ()
1459
- {
1460
- if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1461
- if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
1462
-
1463
- // Remove the terminal session to the count to update the server
1464
- if (this.httprequest.userid != null)
1465
- {
1466
- if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } }
1467
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1468
- broadcastSessionsToRegisteredApps();
1469
- }
1470
-
1471
- if (process.platform == 'win32')
1472
- {
1473
- // Unpipe the web socket
1474
- this.unpipe(this.httprequest._term);
1475
- if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1476
-
1477
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1478
- if (this.rtcchannel)
1479
- {
1480
- this.rtcchannel.unpipe(this.httprequest._term);
1481
- if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1482
- }
1483
-
1484
- // Clean up
1485
- if (this.httprequest._term) { this.httprequest._term.end(); }
1486
- this.httprequest._term = null;
1487
- }
1488
- };
1489
-
1490
- // Perform User-Consent if needed.
1491
- if (this.httprequest.consent && (this.httprequest.consent & 16))
1492
- {
1493
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1494
- var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
1495
- if (this.httprequest.soptions != null) {
1496
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1497
- if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1498
- }
1499
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
1500
- this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1501
- this.httprequest.tpromise._consent.then(
1502
- function ()
1503
- {
1504
- // Success
1505
- MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1506
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1507
- this.retPromise._consent = null;
1508
- this.retPromise._res();
1509
- },
1510
- function (e)
1511
- {
1512
- // Denied
1513
- MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1514
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1515
- this.retPromise._rej(e.toString());
1516
- });
1517
- }
1518
- else
1519
- {
1520
- // User-Consent is not required, so just resolve this promise
1521
- this.httprequest.tpromise._res();
1522
- }
1523
-
1524
-
1525
- this.httprequest.tpromise.then(
1526
- function ()
1527
- {
1528
- this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1529
- this.httprequest.connectionPromise.ws = this.that;
1530
-
1531
- // Start Terminal
1532
- if(process.platform == 'win32')
1533
- {
1534
- try
1535
- {
1536
- var cols = 80, rows = 25;
1537
- if (this.httprequest.xoptions)
1538
- {
1539
- if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1540
- if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1541
- }
1542
-
1543
- if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1544
- {
1545
- // Admin Terminal
1546
- if (require('win-virtual-terminal').supported)
1547
- {
1548
- // ConPTY PseudoTerminal
1549
- // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1550
-
1551
- // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1552
- 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] } });
1553
- this.httprequest._dispatcher.httprequest = this.httprequest;
1554
- this.httprequest._dispatcher.on('connection', function (c)
1555
- {
1556
- if (this.httprequest.connectionPromise.completed)
1557
- {
1558
- c.end();
1559
- }
1560
- else
1561
- {
1562
- this.httprequest.connectionPromise._res(c);
1563
- }
1564
- });
1565
- }
1566
- else
1567
- {
1568
- // Legacy Terminal
1569
- this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1570
- }
1571
- }
1572
- else
1573
- {
1574
- // Logged in user
1575
- var userPromise = require('user-sessions').enumerateUsers();
1576
- userPromise.that = this;
1577
- userPromise.then(function (u)
1578
- {
1579
- var that = this.that;
1580
- if (u.Active.length > 0)
1581
- {
1582
- var username = u.Active[0].Username;
1583
- if (require('win-virtual-terminal').supported)
1584
- {
1585
- // ConPTY PseudoTerminal
1586
- 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] } });
1587
- }
1588
- else
1589
- {
1590
- // Legacy Terminal
1591
- 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] } });
1592
- }
1593
- that.httprequest._dispatcher.ws = that;
1594
- that.httprequest._dispatcher.on('connection', function (c)
1595
- {
1596
- if (this.ws.httprequest.connectionPromise.completed)
1597
- {
1598
- c.end();
1599
- }
1600
- else
1601
- {
1602
- this.ws.httprequest.connectionPromise._res(c);
1603
- }
1604
- });
1605
- }
1606
- });
1607
- }
1608
- }
1609
- catch (e)
1610
- {
1611
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1612
- }
1613
- }
1614
- else
1615
- {
1616
- try
1617
- {
1618
- var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1619
- var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1620
- var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1621
-
1622
- var env = { HISTCONTROL: 'ignoreboth' };
1623
- if (this.httprequest.xoptions)
1624
- {
1625
- if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1626
- if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1627
- }
1628
- var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1629
- if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1630
- {
1631
- if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1632
- this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1633
- }
1634
- else if (bash)
1635
- {
1636
- var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1637
- // Spaces at the beginning of lines are needed to hide commands from the command history
1638
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1639
- this.httprequest.connectionPromise._res(p);
1640
- }
1641
- else if (sh)
1642
- {
1643
- var p = childProcess.execFile(sh, ['sh'], options); // Start sh
1644
- // Spaces at the beginning of lines are needed to hide commands from the command history
1645
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1646
- this.httprequest.connectionPromise._res(p);
1647
- }
1648
- else
1649
- {
1650
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
1651
- }
1652
- }
1653
- catch (e)
1654
- {
1655
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1656
- }
1657
- }
1658
-
1659
- this.httprequest.connectionPromise.then(
1660
- function (term)
1661
- {
1662
- // SUCCESS
1663
- var stdoutstream;
1664
- var stdinstream;
1665
- if (process.platform == 'win32')
1666
- {
1667
- this.ws.httprequest._term = term;
1668
- this.ws.httprequest._term.tunnel = this.ws;
1669
- stdoutstream = stdinstream = term;
1670
- }
1671
- else
1672
- {
1673
- term.descriptorMetadata = 'Remote Terminal';
1674
- this.ws.httprequest.process = term;
1675
- this.ws.httprequest.process.tunnel = this.ws;
1676
- term.stderr.stdout = term.stdout;
1677
- term.stderr.on('data', function (c) { this.stdout.write(c); });
1678
- stdoutstream = term.stdout;
1679
- stdinstream = term.stdin;
1680
- this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
1681
- term.prependListener('exit', function () { this.tunnel.end(); });
1682
- }
1683
-
1684
- this.ws.removeAllListeners('data');
1685
- this.ws.on('data', onTunnelControlData);
1686
-
1687
- stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
1688
- this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
1689
-
1690
- // Add the terminal session to the count to update the server
1691
- if (this.ws.httprequest.userid != null)
1692
- {
1693
- if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
1694
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1695
- broadcastSessionsToRegisteredApps();
1696
- }
1697
-
1698
- // Toast Notification, if required
1699
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
1700
- {
1701
- // User Notifications is required
1702
- var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
1703
- if (this.ws.httprequest.soptions != null) {
1704
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1705
- 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); }
1706
- }
1707
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
1708
- }
1709
- },
1710
- function (e)
1711
- {
1712
- // FAILED to connect terminal
1713
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1714
- this.ws.end();
1715
- });
1716
- },
1717
- function (e)
1718
- {
1719
- // DO NOT start terminal
1720
- this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1721
- this.that.end();
1722
- });
1723
- }
1724
- else if (this.httprequest.protocol == 2)
1725
- {
1726
- //
1727
- // Remote KVM
1728
- //
1729
-
1730
- // Check user access rights for desktop
1731
- if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
1732
- // Disengage this tunnel, user does not have the rights to do this!!
1733
- this.httprequest.protocol = 999999;
1734
- this.httprequest.s.end();
1735
- sendConsoleText("Error: No Desktop Control Rights.");
1736
- return;
1737
- }
1738
-
1739
- this.descriptorMetadata = "Remote KVM";
1740
-
1741
- // Look for a TSID
1742
- var tsid = null;
1743
- if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
1744
- require('MeshAgent')._tsid = tsid;
1745
-
1746
- // Remote desktop using native pipes
1747
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this };
1748
- this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
1749
- this.desktop = this.httprequest.desktop;
1750
-
1751
- // Add ourself to the list of remote desktop sessions
1752
- if (this.httprequest.desktop.kvm.tunnels == null) { this.httprequest.desktop.kvm.tunnels = []; }
1753
- this.httprequest.desktop.kvm.tunnels.push(this);
1754
-
1755
- // Send a metadata update to all desktop sessions
1756
- var users = {};
1757
- if (this.httprequest.desktop.kvm.tunnels != null) {
1758
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1759
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1760
- tunnelUserCount.desktop = users;
1761
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
1762
- broadcastSessionsToRegisteredApps();
1763
- }
1764
-
1765
- this.end = function () {
1766
- --this.desktop.kvm.connectionCount;
1767
-
1768
- // Remove ourself from the list of remote desktop session
1769
- var i = this.desktop.kvm.tunnels.indexOf(this);
1770
- if (i >= 0) { this.desktop.kvm.tunnels.splice(i, 1); }
1771
-
1772
- // Send a metadata update to all desktop sessions
1773
- var users = {};
1774
- if (this.httprequest.desktop.kvm.tunnels != null) {
1775
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1776
- for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1777
- tunnelUserCount.desktop = users;
1778
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
1779
- broadcastSessionsToRegisteredApps();
1780
- }
1781
-
1782
- // Unpipe the web socket
1783
- try
1784
- {
1785
- this.unpipe(this.httprequest.desktop.kvm);
1786
- this.httprequest.desktop.kvm.unpipe(this);
1787
- }
1788
- catch(e) { }
1789
-
1790
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1791
- if (this.rtcchannel)
1792
- {
1793
- try
1794
- {
1795
- this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
1796
- this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
1797
- }
1798
- catch(e) { }
1799
- }
1800
-
1801
- // Place wallpaper back if needed
1802
- // TODO
1803
-
1804
- if (this.desktop.kvm.connectionCount == 0) {
1805
- // Display a toast message. This may not be supported on all platforms.
1806
- // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
1807
-
1808
- this.httprequest.desktop.kvm.end();
1809
- if (this.httprequest.desktop.kvm.connectionBar) {
1810
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1811
- this.httprequest.desktop.kvm.connectionBar.close();
1812
- this.httprequest.desktop.kvm.connectionBar = null;
1813
- }
1814
- } else {
1815
- for (var i in this.httprequest.desktop.kvm.users) {
1816
- if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar) {
1817
- 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; } }
1818
- this.httprequest.desktop.kvm.users.splice(i, 1);
1819
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1820
- this.httprequest.desktop.kvm.connectionBar.close();
1821
- this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1822
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
1823
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1824
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1825
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1826
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1827
- }
1828
- this.httprequest.desktop.kvm.end();
1829
- });
1830
- break;
1831
- }
1832
- }
1833
- }
1834
- };
1835
- if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
1836
- this.httprequest.desktop.kvm.connectionCount++;
1837
- this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
1838
- this.httprequest.desktop.kvm.users.push(this.httprequest.username);
1839
- this.httprequest.desktop.kvm.rusers.sort();
1840
- this.httprequest.desktop.kvm.users.sort();
1841
- } else {
1842
- this.httprequest.desktop.kvm.connectionCount = 1;
1843
- this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
1844
- this.httprequest.desktop.kvm.users = [this.httprequest.username];
1845
- }
1846
-
1847
- if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
1848
- // If we have remote control rights, pipe the KVM input
1849
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
1850
- } else {
1851
- // We need to only pipe non-mouse & non-keyboard inputs.
1852
- //sendConsoleText('Warning: No Remote Desktop Input Rights.');
1853
- // TODO!!!
1854
- }
1855
-
1856
- // Perform notification if needed. Toast messages may not be supported on all platforms.
1857
- if (this.httprequest.consent && (this.httprequest.consent & 8))
1858
- {
1859
- // User Consent Prompt is required
1860
- // Send a console message back using the console channel, "\n" is supported.
1861
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1862
- var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
1863
- if (this.httprequest.soptions != null) {
1864
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1865
- if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1866
- }
1867
- var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
1868
- pr.ws = this;
1869
- this.pause();
1870
- this._consentpromise = pr;
1871
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }});
1872
- pr.then(
1873
- function ()
1874
- {
1875
- // Success
1876
- this.ws._consentpromise = null;
1877
- MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1878
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1879
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
1880
- // User Notifications is required
1881
- var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1882
- if (this.ws.httprequest.soptions != null) {
1883
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1884
- 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); }
1885
- }
1886
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
1887
- }
1888
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40)) {
1889
- // Connection Bar is required
1890
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
1891
- this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1892
- this.ws.httprequest.desktop.kvm.connectionBar.close();
1893
- }
1894
- try {
1895
- this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1896
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1897
- }
1898
- catch (e) {
1899
- if (process.platform != 'darwin') {
1900
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1901
- }
1902
- }
1903
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
1904
- this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
1905
- this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
1906
- MeshServerLogEx(33, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1907
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1908
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1909
- }
1910
- this.httprequest.desktop.kvm.end();
1911
- });
1912
- }
1913
- }
1914
- this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
1915
- this.ws.resume();
1916
- },
1917
- function (e)
1918
- {
1919
- // User Consent Denied/Failed
1920
- this.ws._consentpromise = null;
1921
- MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1922
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1923
- });
1924
- } else {
1925
- // User Consent Prompt is not required
1926
- if (this.httprequest.consent && (this.httprequest.consent & 1)) {
1927
- // User Notifications is required
1928
- MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1929
- var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1930
- if (this.httprequest.soptions != null) {
1931
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
1932
- if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1933
- }
1934
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
1935
- } else {
1936
- MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1937
- }
1938
- if (this.httprequest.consent && (this.httprequest.consent & 0x40)) {
1939
- // Connection Bar is required
1940
- if (this.httprequest.desktop.kvm.connectionBar) {
1941
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1942
- this.httprequest.desktop.kvm.connectionBar.close();
1943
- }
1944
- try {
1945
- 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);
1946
- MeshServerLogEx(37, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
1947
- }
1948
- catch (e) {
1949
- MeshServerLogEx(38, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
1950
- }
1951
- if (this.httprequest.desktop.kvm.connectionBar) {
1952
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
1953
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1954
- MeshServerLogEx(39, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
1955
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1956
- this.httprequest.desktop.kvm._pipedStreams[i].end();
1957
- }
1958
- this.httprequest.desktop.kvm.end();
1959
- });
1960
- }
1961
- }
1962
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
1963
- }
1964
-
1965
- this.removeAllListeners('data');
1966
- this.on('data', onTunnelControlData);
1967
- //this.write('MeshCore KVM Hello!1');
1968
-
1969
- } else if (this.httprequest.protocol == 5) {
1970
- //
1971
- // Remote Files
1972
- //
1973
-
1974
- // Check user access rights for files
1975
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
1976
- // Disengage this tunnel, user does not have the rights to do this!!
1977
- this.httprequest.protocol = 999999;
1978
- this.httprequest.s.end();
1979
- sendConsoleText("Error: No files control rights.");
1980
- return;
1981
- }
1982
-
1983
- this.descriptorMetadata = "Remote Files";
1984
-
1985
- // Add the files session to the count to update the server
1986
- if (this.httprequest.userid != null) {
1987
- if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
1988
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
1989
- broadcastSessionsToRegisteredApps();
1990
- }
1991
-
1992
- this.end = function () {
1993
- // Remove the files session from the count to update the server
1994
- if (this.httprequest.userid != null) {
1995
- if (tunnelUserCount.files[this.httprequest.userid] != null) { tunnelUserCount.files[this.httprequest.userid]--; if (tunnelUserCount.files[this.httprequest.userid] <= 0) { delete tunnelUserCount.files[this.httprequest.userid]; } }
1996
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
1997
- broadcastSessionsToRegisteredApps();
1998
- }
1999
- };
2000
-
2001
- // Perform notification if needed. Toast messages may not be supported on all platforms.
2002
- if (this.httprequest.consent && (this.httprequest.consent & 32)) {
2003
- // User Consent Prompt is required
2004
- // Send a console message back using the console channel, "\n" is supported.
2005
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2006
- var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
2007
- if (this.httprequest.soptions != null) {
2008
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2009
- if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2010
- }
2011
- var pr = require('message-box').create(consentTitle, consentMessage, 30);
2012
- pr.ws = this;
2013
- this.pause();
2014
- this._consentpromise = pr;
2015
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2016
- pr.then(
2017
- function ()
2018
- {
2019
- // Success
2020
- this.ws._consentpromise = null;
2021
- MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2022
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2023
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
2024
- // User Notifications is required
2025
- var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2026
- if (this.ws.httprequest.soptions != null) {
2027
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2028
- 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); }
2029
- }
2030
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2031
- }
2032
- this.ws.resume();
2033
- },
2034
- function (e)
2035
- {
2036
- // User Consent Denied/Failed
2037
- this.ws._consentpromise = null;
2038
- MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2039
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2040
- });
2041
- } else {
2042
- // User Consent Prompt is not required
2043
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
2044
- // User Notifications is required
2045
- MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2046
- var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2047
- if (this.httprequest.soptions != null) {
2048
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2049
- if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2050
- }
2051
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2052
- } else {
2053
- MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2054
- }
2055
- this.resume();
2056
- }
2057
-
2058
- // Setup files
2059
- // NOP
2060
- }
2061
- } else if (this.httprequest.protocol == 1) {
2062
- // Send data into terminal stdin
2063
- //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2064
- } else if (this.httprequest.protocol == 2) {
2065
- // Send data into remote desktop
2066
- if (this.httprequest.desktop.state == 0) {
2067
- this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2068
- this.httprequest.desktop.state = 1;
2069
- } else {
2070
- this.httprequest.desktop.write(data);
2071
- }
2072
- } else if (this.httprequest.protocol == 5) {
2073
- // Process files commands
2074
- var cmd = null;
2075
- try { cmd = JSON.parse(data); } catch (e) { };
2076
- if (cmd == null) { return; }
2077
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2078
- if (cmd.action == undefined) { return; }
2079
- //sendConsoleText('CMD: ' + JSON.stringify(cmd));
2080
-
2081
- if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2082
- //console.log(objToString(cmd, 0, ' '));
2083
- switch (cmd.action) {
2084
- case 'ls': {
2085
- /*
2086
- // Close the watcher if required
2087
- var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
2088
- if ((this.httprequest.watcher != undefined) && (samepath == false)) {
2089
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
2090
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
2091
- delete this.httprequest.watcher;
2092
- }
2093
- */
2094
-
2095
- // Send the folder content to the browser
2096
- var response = getDirectoryInfo(cmd.path);
2097
- if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
2098
- this.write(Buffer.from(JSON.stringify(response)));
2099
-
2100
- /*
2101
- // Start the directory watcher
2102
- if ((cmd.path != '') && (samepath == false)) {
2103
- var watcher = fs.watch(cmd.path, onFileWatcher);
2104
- watcher.tunnel = this.httprequest;
2105
- watcher.path = cmd.path;
2106
- this.httprequest.watcher = watcher;
2107
- //console.log('Starting watcher: ' + this.httprequest.watcher.path);
2108
- }
2109
- */
2110
- break;
2111
- }
2112
- case 'mkdir': {
2113
- // Create a new empty folder
2114
- fs.mkdirSync(cmd.path);
2115
- MeshServerLogEx(44, [cmd.path], "Create folder: \"" + cmd.path + "\"", this.httprequest);
2116
- break;
2117
- }
2118
- case 'rm': {
2119
- // Delete, possibly recursive delete
2120
- for (var i in cmd.delfiles) {
2121
- var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2122
- try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2123
- if ((delcount == 1) && !cmd.rec) {
2124
- MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2125
- } else {
2126
- if (cmd.rec) {
2127
- MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2128
- } else {
2129
- MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2130
- }
2131
- }
2132
- }
2133
- break;
2134
- }
2135
- case 'markcoredump': {
2136
- // If we are asking for the coredump file, set the right path.
2137
- var coreDumpPath = null;
2138
- if (process.platform == 'win32') {
2139
- if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2140
- } else {
2141
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2142
- }
2143
- if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
2144
- break;
2145
- }
2146
- case 'rename': {
2147
- // Rename a file or folder
2148
- var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
2149
- var newfullpath = obj.path.join(cmd.path, cmd.newname);
2150
- MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
2151
- try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
2152
- break;
2153
- }
2154
- case 'download': {
2155
- // Download a file
2156
- var sendNextBlock = 0;
2157
- if (cmd.sub == 'start') { // Setup the download
2158
- if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
2159
- if (process.platform == 'win32') {
2160
- if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2161
- } else {
2162
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2163
- }
2164
- }
2165
- MeshServerLogEx(49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
2166
- if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2167
- this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2168
- 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; }
2169
- if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2170
- } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
2171
- 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; }
2172
- }
2173
- // Send the next download block(s)
2174
- while (sendNextBlock > 0) {
2175
- sendNextBlock--;
2176
- var buf = Buffer.alloc(16384);
2177
- var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
2178
- this.filedownload.ptr += len;
2179
- if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
2180
- this.write(buf.slice(0, len + 4)); // Write as binary
2181
- }
2182
- break;
2183
- }
2184
- /*
2185
- case 'download': {
2186
- // Packet download of a file, agent to browser
2187
- if (cmd.path == undefined) break;
2188
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2189
- //console.log('Download: ' + filepath);
2190
- try { this.httprequest.downloadFile = fs.openSync(filepath, 'rbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'downloaderror', reqid: cmd.reqid }))); break; }
2191
- this.httprequest.downloadFileId = cmd.reqid;
2192
- this.httprequest.downloadFilePtr = 0;
2193
- if (this.httprequest.downloadFile) { this.write(Buffer.from(JSON.stringify({ action: 'downloadstart', reqid: this.httprequest.downloadFileId }))); }
2194
- break;
2195
- }
2196
- case 'download2': {
2197
- // Stream download of a file, agent to browser
2198
- if (cmd.path == undefined) break;
2199
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2200
- try { this.httprequest.downloadFile = fs.createReadStream(filepath, { flags: 'rbN' }); } catch (e) { console.log(e); }
2201
- this.httprequest.downloadFile.pipe(this);
2202
- this.httprequest.downloadFile.end = function () { }
2203
- break;
2204
- }
2205
- */
2206
- case 'upload': {
2207
- // Upload a file, browser to agent
2208
- if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
2209
- if (cmd.path == undefined) break;
2210
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2211
- this.httprequest.uploadFilePath = filepath;
2212
- MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
2213
- try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
2214
- this.httprequest.uploadFileid = cmd.reqid;
2215
- if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
2216
- break;
2217
- }
2218
- case 'uploaddone': {
2219
- // Indicates that an upload is done
2220
- if (this.httprequest.uploadFile) {
2221
- fs.closeSync(this.httprequest.uploadFile);
2222
- this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2223
- delete this.httprequest.uploadFile;
2224
- delete this.httprequest.uploadFileid;
2225
- delete this.httprequest.uploadFilePath;
2226
- }
2227
- break;
2228
- }
2229
- case 'uploadcancel': {
2230
- // Indicates that an upload is canceled
2231
- if (this.httprequest.uploadFile) {
2232
- fs.closeSync(this.httprequest.uploadFile);
2233
- fs.unlinkSync(this.httprequest.uploadFilePath);
2234
- this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2235
- delete this.httprequest.uploadFile;
2236
- delete this.httprequest.uploadFileid;
2237
- delete this.httprequest.uploadFilePath;
2238
- }
2239
- break;
2240
- }
2241
- case 'copy': {
2242
- // Copy a bunch of files from scpath to dspath
2243
- for (var i in cmd.names) {
2244
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2245
- MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2246
- if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
2247
- }
2248
- break;
2249
- }
2250
- case 'move': {
2251
- // Move a bunch of files from scpath to dspath
2252
- for (var i in cmd.names) {
2253
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2254
- MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2255
- if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
2256
- }
2257
- break;
2258
- }
2259
- case 'zip':
2260
- // Zip a bunch of files
2261
- if (this.zip != null) return; // Zip operating is currently running, exit now.
2262
-
2263
- // Check that the specified files exist & build full paths
2264
- var fp, stat, p = [];
2265
- 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); } }
2266
- if (p.length == 0) return; // No files, quit now.
2267
-
2268
- // Setup file compression
2269
- var ofile = cmd.path + '/' + cmd.output;
2270
- this.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zipping' })));
2271
- this.zipfile = ofile;
2272
- delete this.zipcancel;
2273
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2274
- out.xws = this;
2275
- out.on('close', function () {
2276
- this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2277
- this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2278
- if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
2279
- delete this.xws.zipcancel;
2280
- delete this.xws.zipfile;
2281
- delete this.xws.zip;
2282
- });
2283
- this.zip = require('zip-writer').write({ files: p, basePath: cmd.path });
2284
- this.zip.xws = this;
2285
- 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));
2286
- this.zip.pipe(out);
2287
- break;
2288
- case 'cancel':
2289
- // Cancel zip operation if present
2290
- try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (e) { }
2291
- this.zip = null;
2292
- break;
2293
- default:
2294
- // Unknown action, ignore it.
2295
- break;
2296
- }
2297
- } else if (this.httprequest.protocol == 7) { // Plugin data exchange
2298
- var cmd = null;
2299
- try { cmd = JSON.parse(data); } catch (e) { };
2300
- if (cmd == null) { return; }
2301
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2302
- if (cmd.action == undefined) return;
2303
-
2304
- switch (cmd.action) {
2305
- case 'plugin': {
2306
- try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2307
- break;
2308
- }
2309
- default: {
2310
- // probably shouldn't happen, but just in case this feature is expanded
2311
- }
2312
- }
2313
-
2314
- }
2315
- //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
2316
- }
2317
- }
2318
-
2319
- // Delete a directory with a files and directories within it
2320
- function deleteFolderRecursive(path, rec) {
2321
- var count = 0;
2322
- if (fs.existsSync(path)) {
2323
- if (rec == true) {
2324
- fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
2325
- var curPath = obj.path.join(path, file);
2326
- if (fs.statSync(curPath).isDirectory()) { // recurse
2327
- count += deleteFolderRecursive(curPath, true);
2328
- } else { // delete file
2329
- fs.unlinkSync(curPath);
2330
- count++;
2331
- }
2332
- });
2333
- }
2334
- fs.unlinkSync(path);
2335
- count++;
2336
- }
2337
- return count;
2338
- };
2339
-
2340
- // Called when receiving control data on WebRTC
2341
- function onTunnelWebRTCControlData(data) {
2342
- if (typeof data != 'string') return;
2343
- var obj;
2344
- try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2345
- if (obj.type == 'close') {
2346
- //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2347
- try { this.close(); } catch (e) { }
2348
- try { this.xrtc.close(); } catch (e) { }
2349
- }
2350
- }
2351
-
2352
- // Called when receiving control data on websocket
2353
- function onTunnelControlData(data, ws) {
2354
- var obj;
2355
- if (ws == null) { ws = this; }
2356
- if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
2357
- else if (typeof data == 'object') { obj = data; } else { return; }
2358
- //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2359
- //console.log('onTunnelControlData: ' + JSON.stringify(data));
2360
-
2361
- if (obj.action) {
2362
- switch (obj.action) {
2363
- case 'lock': {
2364
- // Lock the current user out of the desktop
2365
- try {
2366
- if (process.platform == 'win32') {
2367
- MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
2368
- var child = require('child_process');
2369
- child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
2370
- }
2371
- } catch (e) { }
2372
- break;
2373
- }
2374
- default:
2375
- // Unknown action, ignore it.
2376
- break;
2377
- }
2378
- return;
2379
- }
2380
-
2381
- switch (obj.type) {
2382
- case 'options': {
2383
- // These are additional connection options passed in the control channel.
2384
- //sendConsoleText('options: ' + JSON.stringify(obj));
2385
- delete obj.type;
2386
- ws.httprequest.xoptions = obj;
2387
-
2388
- // Set additional user consent options if present
2389
- if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
2390
-
2391
- break;
2392
- }
2393
- case 'close': {
2394
- // We received the close on the websocket
2395
- //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
2396
- try { ws.close(); } catch (e) { }
2397
- break;
2398
- }
2399
- case 'termsize': {
2400
- // Indicates a change in terminal size
2401
- if (process.platform == 'win32')
2402
- {
2403
- if (ws.httprequest._dispatcher == null) return;
2404
- //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
2405
- if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
2406
- } else
2407
- {
2408
- if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
2409
- //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
2410
-
2411
- if (ws.httprequest.process.tcsetsize) { ws.httprequest.process.tcsetsize(obj.rows, obj.cols); }
2412
- }
2413
- break;
2414
- }
2415
- case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
2416
- if (ws.httprequest.protocol == 1) { // Terminal
2417
- // 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
2418
- if (process.platform == 'win32') {
2419
- ws.httprequest._term.unpipe(ws);
2420
- } else {
2421
- ws.httprequest.process.stdout.unpipe(ws);
2422
- ws.httprequest.process.stderr.unpipe(ws);
2423
- }
2424
- } else if (ws.httprequest.protocol == 2) { // Desktop
2425
- // 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
2426
- ws.httprequest.desktop.kvm.unpipe(ws);
2427
- } else {
2428
- // Switch things around so all WebRTC data goes to onTunnelData().
2429
- ws.rtcchannel.httprequest = ws.httprequest;
2430
- ws.rtcchannel.removeAllListeners('data');
2431
- ws.rtcchannel.on('data', onTunnelData);
2432
- }
2433
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // End of data marker
2434
- break;
2435
- }
2436
- case 'webrtc1': {
2437
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2438
- // Switch the user input from websocket to webrtc at this point.
2439
- if (process.platform == 'win32') {
2440
- ws.unpipe(ws.httprequest._term);
2441
- ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2442
- } else {
2443
- ws.unpipe(ws.httprequest.process.stdin);
2444
- ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2445
- }
2446
- ws.resume(); // Resume the websocket to keep receiving control data
2447
- } else if (ws.httprequest.protocol == 2) { // Desktop
2448
- // Switch the user input from websocket to webrtc at this point.
2449
- ws.unpipe(ws.httprequest.desktop.kvm);
2450
- try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
2451
- ws.resume(); // Resume the websocket to keep receiving control data
2452
- }
2453
- ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
2454
- break;
2455
- }
2456
- case 'webrtc2': {
2457
- // Other side received websocket end of data marker, start sending data on WebRTC channel
2458
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2459
- if (process.platform == 'win32') {
2460
- ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2461
- } else {
2462
- ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2463
- ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2464
- }
2465
- } else if (ws.httprequest.protocol == 2) { // Desktop
2466
- ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2467
- }
2468
- break;
2469
- }
2470
- case 'offer': {
2471
- // This is a WebRTC offer.
2472
- if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) return; // TODO: Terminal is currently broken with WebRTC. Reject WebRTC upgrade for now.
2473
- ws.webrtc = rtc.createConnection();
2474
- ws.webrtc.websocket = ws;
2475
- ws.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
2476
- ws.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
2477
- ws.webrtc.on('dataChannel', function (rtcchannel) {
2478
- //sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
2479
- rtcchannel.maxFragmentSize = 32768;
2480
- rtcchannel.xrtc = this;
2481
- rtcchannel.websocket = this.websocket;
2482
- this.rtcchannel = rtcchannel;
2483
- this.websocket.rtcchannel = rtcchannel;
2484
- this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
2485
- this.websocket.rtcchannel.on('end', function () {
2486
- // The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes.
2487
- //sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');
2488
- if (this.websocket.desktop && this.websocket.desktop.kvm)
2489
- {
2490
- try
2491
- {
2492
- this.unpipe(this.websocket.desktop.kvm);
2493
- this.websocket.httprequest.desktop.kvm.unpipe(this);
2494
- }
2495
- catch (e) { }
2496
- }
2497
- });
2498
- this.websocket.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc0\"}'); // Indicate we are ready for WebRTC switch-over.
2499
- });
2500
- var sdp = null;
2501
- try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (e) { }
2502
- if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
2503
- break;
2504
- }
2505
- case 'ping': {
2506
- ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"pong\"}"); // Send pong response
2507
- break;
2508
- }
2509
- case 'pong': { // NOP
2510
- break;
2511
- }
2512
- case 'rtt': {
2513
- ws.write({ type: 'rtt', ctrlChannel: '102938', time: obj.time });
2514
- break;
2515
- }
2516
- }
2517
- }
2518
-
2519
- // Console state
2520
- var consoleWebSockets = {};
2521
- var consoleHttpRequest = null;
2522
-
2523
- // Console HTTP response
2524
- function consoleHttpResponse(response) {
2525
- response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
2526
- response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; }
2527
- };
2528
-
2529
- // Open a web browser to a specified URL on current user's desktop
2530
- function openUserDesktopUrl(url) {
2531
- if ((url.toLowerCase().startsWith('http://') == false) && (url.toLowerCase().startsWith('https://') == false)) { return null; }
2532
- var child = null;
2533
- try {
2534
- switch (process.platform) {
2535
- case 'win32':
2536
- var user = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2537
- child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd']);
2538
- child.stderr.on('data', function () { });
2539
- child.stdout.on('data', function () { });
2540
- child.stdin.write('SCHTASKS /CREATE /F /TN MeshChatTask /SC ONCE /ST 00:00 /RU ' + user + ' /TR "' + process.env['windir'] + '\\system32\\cmd.exe /C START ' + url + '"\r\n');
2541
- child.stdin.write('SCHTASKS /RUN /TN MeshChatTask\r\n');
2542
- child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\n');
2543
- child.stdin.write('exit\r\n');
2544
- child.waitExit();
2545
- break;
2546
- case 'linux':
2547
- child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { uid: require('user-sessions').consoleUid() });
2548
- break;
2549
- case 'darwin':
2550
- child = require('child_process').execFile('/usr/bin/open', ['open', url], { uid: require('user-sessions').consoleUid() });
2551
- break;
2552
- default:
2553
- // Unknown platform, ignore this command.
2554
- break;
2555
- }
2556
- } catch (e) { }
2557
- return child;
2558
- }
2559
-
2560
- // Process a mesh agent console command
2561
- function processConsoleCommand(cmd, args, rights, sessionid) {
2562
- try {
2563
- var response = null;
2564
- switch (cmd) {
2565
- case 'help': { // Displays available commands
2566
- var fin = '', f = '', availcommands = 'amtconfig,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg';
2567
- if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
2568
- if (process.platform != 'freebsd') { availcommands += ',vm';}
2569
- if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
2570
- try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { }
2571
-
2572
- availcommands = availcommands.split(',').sort();
2573
- while (availcommands.length > 0) {
2574
- if (f.length > 90) { fin += (f + ',\r\n'); f = ''; }
2575
- f += (((f != '') ? ', ' : ' ') + availcommands.shift());
2576
- }
2577
- if (f != '') { fin += f; }
2578
- response = "Available commands: \r\n" + fin + ".";
2579
- break;
2580
- }
2581
- case 'agentmsg': {
2582
- if (args['_'].length == 0) {
2583
- response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage
2584
- } else {
2585
- if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
2586
- var msgIndex = 1, iconIndex = 0;
2587
- while (tunnelUserCount.msg[msgIndex] != null) { msgIndex++; }
2588
- if (args['_'].length >= 3) { try { iconIndex = parseInt(args['_'][2]); } catch (e) { } }
2589
- if (typeof iconIndex != 'number') { iconIndex = 0; }
2590
- tunnelUserCount.msg[msgIndex] = { msg: args['_'][1], icon: iconIndex };
2591
- response = 'Agent message ' + msgIndex + ' added.';
2592
- } else if ((args['_'][0] == 'remove') && (args['_'].length > 1)) {
2593
- var msgIndex = 0;
2594
- try { msgIndex = parseInt(args['_'][1]); } catch (x) { }
2595
- if (tunnelUserCount.msg[msgIndex] == null) { response = "Message not found."; } else { delete tunnelUserCount.msg[msgIndex]; response = "Message removed."; }
2596
- } else if (args['_'][0] == 'list') {
2597
- response = JSON.stringify(tunnelUserCount.msg, null, 2);
2598
- }
2599
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
2600
- broadcastSessionsToRegisteredApps();
2601
- }
2602
- break;
2603
- }
2604
- case 'clearagentmsg': {
2605
- tunnelUserCount.msg = {};
2606
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
2607
- broadcastSessionsToRegisteredApps();
2608
- break;
2609
- }
2610
- case 'coredump':
2611
- if (args['_'].length != 1) {
2612
- response = "Proper usage: coredump on|off|status|clear"; // Display usage
2613
- } else {
2614
- switch (args['_'][0].toLowerCase())
2615
- {
2616
- case 'on':
2617
- process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
2618
- response = 'coredump is now on';
2619
- break;
2620
- case 'off':
2621
- process.coreDumpLocation = null;
2622
- response = 'coredump is now off';
2623
- break;
2624
- case 'status':
2625
- response = 'coredump is: ' + ((process.coreDumpLocation == null) ? 'off' : 'on');
2626
- if (process.coreDumpLocation != null) {
2627
- if (process.platform == 'win32') {
2628
- if (fs.existsSync(process.coreDumpLocation)) { response += '\r\n CoreDump present at: ' + process.coreDumpLocation; }
2629
- } else {
2630
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { response += '\r\n CoreDump present at: ' + process.cwd() + 'core'; }
2631
- }
2632
- }
2633
- break;
2634
- case 'clear':
2635
- db.Put('CoreDumpTime', null);
2636
- response = 'coredump db cleared';
2637
- break;
2638
- default:
2639
- response = "Proper usage: coredump on|off|status"; // Display usage
2640
- break;
2641
- }
2642
- }
2643
- break;
2644
- case 'service':
2645
- if (args['_'].length != 1)
2646
- {
2647
- response = "Proper usage: service status|restart"; // Display usage
2648
- }
2649
- else
2650
- {
2651
- var s = require('service-manager').manager.getService(process.platform == 'win32' ? 'Mesh Agent' : 'meshagent');
2652
- switch(args['_'][0].toLowerCase())
2653
- {
2654
- case 'status':
2655
- response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]'));
2656
- break;
2657
- case 'restart':
2658
- if (s.isMe())
2659
- {
2660
- s.restart();
2661
- }
2662
- else
2663
- {
2664
- response = 'Restarting another agent instance is not allowed';
2665
- }
2666
- break;
2667
- default:
2668
- response = "Proper usage: service status|restart"; // Display usage
2669
- break;
2670
- }
2671
- if (process.platform == 'win32') { s.close(); }
2672
- }
2673
- break;
2674
- case 'zip':
2675
- if (args['_'].length == 0) {
2676
- response = "Proper usage: zip (output file name), input1 [, input n]"; // Display usage
2677
- } else {
2678
- var p = args['_'].join(' ').split(',');
2679
- var ofile = p.shift();
2680
- sendConsoleText('Writing ' + ofile + '...');
2681
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2682
- out.fname = ofile;
2683
- out.sessionid = sessionid;
2684
- out.on('close', function () { sendConsoleText('DONE writing ' + this.fname, this.sessionid); });
2685
- var zip = require('zip-writer').write({ files: p });
2686
- zip.pipe(out);
2687
- }
2688
- break;
2689
- case 'unzip':
2690
- if (args['_'].length == 0) {
2691
- response = "Proper usage: unzip input, destination"; // Display usage
2692
- } else {
2693
- var p = args['_'].join(' ').split(',');
2694
- if (p.length != 2) { response = "Proper usage: unzip input, destination"; break; } // Display usage
2695
- var prom = require('zip-reader').read(p[0]);
2696
- prom._dest = p[1];
2697
- prom.self = this;
2698
- prom.sessionid = sessionid;
2699
- prom.then(function (zipped) {
2700
- sendConsoleText('Extracting to ' + this._dest + '...', this.sessionid);
2701
- zipped.extractAll(this._dest).then(function () { sendConsoleText('finished unzipping', this.sessionid); }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); }).parentPromise.sessionid = this.sessionid;
2702
- }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); });
2703
- }
2704
- break;
2705
- case 'setbattery':
2706
- // require('MeshAgent').SendCommand({ action: 'battery', state: 'dc', level: 55 });
2707
- if ((args['_'].length > 0) && ((args['_'][0] == 'ac') || (args['_'][0] == 'dc'))) {
2708
- var b = { action: 'battery', state: args['_'][0] };
2709
- if (args['_'].length == 2) { b.level = parseInt(args['_'][1]); }
2710
- require('MeshAgent').SendCommand(b);
2711
- } else {
2712
- require('MeshAgent').SendCommand({ action: 'battery' });
2713
- }
2714
- break;
2715
- case 'fdsnapshot':
2716
- require('ChainViewer').getSnapshot().then(function (c) { sendConsoleText(c, this.sessionid); }).parentPromise.sessionid = sessionid;
2717
- break;
2718
- case 'fdcount':
2719
- require('DescriptorEvents').getDescriptorCount().then(
2720
- function (c)
2721
- {
2722
- sendConsoleText('Descriptor Count: ' + c, this.sessionid);
2723
- }, function (e)
2724
- {
2725
- sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid);
2726
- }).parentPromise.sessionid = sessionid;
2727
- break;
2728
- case 'uac':
2729
- if (process.platform != 'win32')
2730
- {
2731
- response = 'Unknown command "uac", type "help" for list of avaialble commands.';
2732
- break;
2733
- }
2734
- if (args['_'].length != 1)
2735
- {
2736
- response = 'Proper usage: uac [get|interactive|secure]';
2737
- }
2738
- else
2739
- {
2740
- switch(args['_'][0].toUpperCase())
2741
- {
2742
- case 'GET':
2743
- var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop');
2744
- response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop");
2745
- break;
2746
- case 'INTERACTIVE':
2747
- try
2748
- {
2749
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0);
2750
- response = 'UAC mode changed to: Interactive Desktop';
2751
- }
2752
- catch (e)
2753
- {
2754
- response = "Unable to change UAC Mode";
2755
- }
2756
- break;
2757
- case 'SECURE':
2758
- try
2759
- {
2760
- require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1);
2761
- response = 'UAC mode changed to: Secure Desktop';
2762
- }
2763
- catch(e)
2764
- {
2765
- response = "Unable to change UAC Mode";
2766
- }
2767
- break;
2768
- default:
2769
- response = 'Proper usage: uac [get|interactive|secure]';
2770
- break;
2771
- }
2772
- }
2773
- break;
2774
- case 'vm':
2775
- response = 'Virtual Machine = ' + require('identifiers').isVM();
2776
- break;
2777
- case 'startupoptions':
2778
- response = JSON.stringify(require('MeshAgent').getStartupOptions());
2779
- break;
2780
- case 'kvmmode':
2781
- if (require('MeshAgent').maxKvmTileSize == null)
2782
- {
2783
- response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands.";
2784
- }
2785
- else
2786
- {
2787
- if(require('MeshAgent').maxKvmTileSize == 0)
2788
- {
2789
- response = 'KVM Mode: Full JUMBO';
2790
- }
2791
- else
2792
- {
2793
- response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO');
2794
- response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize/1024) + ' Kbytes')));
2795
- }
2796
- }
2797
- break;
2798
- case 'alert':
2799
- if (args['_'].length == 0)
2800
- {
2801
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2802
- }
2803
- else
2804
- {
2805
- var p = args['_'].join(' ').split(',');
2806
- if(p.length<2)
2807
- {
2808
- response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2809
- }
2810
- else
2811
- {
2812
- this._alert = require('message-box').create(p[0], p[1], p.length==3?parseInt(p[2]):9999,1);
2813
- }
2814
- }
2815
- break;
2816
- case 'agentsize':
2817
- var actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
2818
- if (process.platform == 'win32') {
2819
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
2820
- var writtenSize = 0;
2821
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { response = e; }
2822
- if (writtenSize != actualSize) {
2823
- response = "Size updated from: " + writtenSize + " to: " + actualSize;
2824
- try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { response = e; }
2825
- } else { response = "Agent Size: " + actualSize + " kb"; }
2826
- } else { response = "Agent Size: " + actualSize + " kb"; }
2827
- break;
2828
- case 'versions':
2829
- response = JSON.stringify(process.versions, null, ' ');
2830
- break;
2831
- case 'wpfhwacceleration':
2832
- if (process.platform != 'win32') { throw ("wpfhwacceleration setting is only supported on Windows"); }
2833
- if (args['_'].length != 1) {
2834
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS)"; // Display usage
2835
- }
2836
- else {
2837
- var reg = require('win-registry');
2838
- var uname = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2839
- var key = reg.usernameToUserKey(uname);
2840
-
2841
- switch (args['_'][0].toUpperCase()) {
2842
- default:
2843
- response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS|DEFAULT)"; // Display usage
2844
- break;
2845
- case 'ON':
2846
- try {
2847
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 0);
2848
- response = "OK";
2849
- } catch (e) { response = "FAILED"; }
2850
- break;
2851
- case 'OFF':
2852
- try {
2853
- reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 1);
2854
- response = 'OK';
2855
- } catch (e) { response = 'FAILED'; }
2856
- break;
2857
- case 'STATUS':
2858
- var s;
2859
- try { s = reg.QueryKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration') == 1 ? 'DISABLED' : 'ENABLED'; } catch (e) { s = 'DEFAULT'; }
2860
- response = "WPF Hardware Acceleration: " + s;
2861
- break;
2862
- case 'DEFAULT':
2863
- try { reg.DeleteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration'); } catch (e) { }
2864
- response = 'OK';
2865
- break;
2866
- }
2867
- }
2868
- break;
2869
- case 'tsid':
2870
- if (process.platform == 'win32') {
2871
- if (args['_'].length != 1) {
2872
- response = "TSID: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
2873
- } else {
2874
- var i = parseInt(args['_'][0]);
2875
- require('MeshAgent')._tsid = (isNaN(i) ? null : i);
2876
- response = "TSID set to: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
2877
- }
2878
- } else { response = "TSID command only supported on Windows"; }
2879
- break;
2880
- case 'activeusers':
2881
- if (process.platform == 'win32') {
2882
- var p = require('user-sessions').enumerateUsers();
2883
- p.sessionid = sessionid;
2884
- p.then(function (u) {
2885
- var v = [];
2886
- for (var i in u) {
2887
- if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
2888
- }
2889
- sendConsoleText(JSON.stringify(v, null, 1), this.sessionid);
2890
- });
2891
- } else { response = "activeusers command only supported on Windows"; }
2892
- break;
2893
- case 'wallpaper':
2894
- if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available)) {
2895
- response = "wallpaper command not supported on this platform";
2896
- }
2897
- else {
2898
- if (args['_'].length != 1) {
2899
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
2900
- }
2901
- else {
2902
- switch (args['_'][0].toUpperCase()) {
2903
- default:
2904
- response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
2905
- break;
2906
- case 'GET':
2907
- case 'TOGGLE':
2908
- if (process.platform == 'win32') {
2909
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
2910
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: id });
2911
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
2912
- child.stderr.on('data', function () { });
2913
- child.waitExit();
2914
- var current = child.stdout.str.trim();
2915
- if (args['_'][0].toUpperCase() == 'GET') {
2916
- response = current;
2917
- break;
2918
- }
2919
- if (current != '') {
2920
- require('MeshAgent')._wallpaper = current;
2921
- response = 'Wallpaper cleared';
2922
- } else {
2923
- response = 'Wallpaper restored';
2924
- }
2925
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: id });
2926
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
2927
- child.stderr.on('data', function () { });
2928
- child.waitExit();
2929
- }
2930
- else {
2931
- var id = require('user-sessions').consoleUid();
2932
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
2933
- if (args['_'][0].toUpperCase() == 'GET') {
2934
- response = current;
2935
- break;
2936
- }
2937
- if (current != '/dev/null') {
2938
- require('MeshAgent')._wallpaper = current;
2939
- response = 'Wallpaper cleared';
2940
- } else {
2941
- response = 'Wallpaper restored';
2942
- }
2943
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
2944
- }
2945
- break;
2946
- }
2947
- }
2948
- }
2949
- break;
2950
- case 'safemode':
2951
- if (process.platform != 'win32') {
2952
- response = 'safemode only supported on Windows Platforms'
2953
- }
2954
- else {
2955
- if (args['_'].length != 1) {
2956
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
2957
- }
2958
- else {
2959
- switch (args['_'][0].toUpperCase()) {
2960
- default:
2961
- response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
2962
- break;
2963
- case 'ON':
2964
- require('win-bcd').setKey('safeboot', 'Network');
2965
- require('win-bcd').enableSafeModeService('Mesh Agent');
2966
- break;
2967
- case 'OFF':
2968
- require('win-bcd').deleteKey('safeboot');
2969
- break;
2970
- case 'STATUS':
2971
- var nextboot = require('win-bcd').getKey('safeboot');
2972
- if (nextboot) {
2973
- switch (nextboot) {
2974
- case 'Network':
2975
- case 'network':
2976
- nextboot = 'SAFE_MODE_NETWORK';
2977
- break;
2978
- default:
2979
- nextboot = 'SAFE_MODE';
2980
- break;
2981
- }
2982
- }
2983
- response = 'Current: ' + require('win-bcd').bootMode + ', NextBoot: ' + (nextboot ? nextboot : 'NORMAL');
2984
- break;
2985
- }
2986
- }
2987
- }
2988
- break;
2989
- /*
2990
- case 'border':
2991
- {
2992
- if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
2993
- if (meshCoreObj.users.length > 0) {
2994
- obj.borderManager.Start(meshCoreObj.users[0]);
2995
- response = 'Border blinking is on.';
2996
- } else {
2997
- response = 'Cannot turn on border blinking, no logged in users.';
2998
- }
2999
- } else if ((args['_'].length == 1) && (args['_'][0] == 'off')) {
3000
- obj.borderManager.Stop();
3001
- response = 'Border blinking is off.';
3002
- } else {
3003
- response = 'Proper usage: border "on|off"'; // Display correct command usage
3004
- }
3005
- }
3006
- break;
3007
- */
3008
- case 'av':
3009
- if (process.platform == 'win32') {
3010
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3011
- response = JSON.stringify(require('win-info').av(), null, 1);
3012
- } else {
3013
- response = 'Not supported on the platform';
3014
- }
3015
- break;
3016
- case 'log':
3017
- if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
3018
- break;
3019
- case 'getclip':
3020
- if (require('MeshAgent').isService) {
3021
- require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });
3022
- } else {
3023
- require("clipboard").read().then(function (str) { sendConsoleText(str, sessionid); });
3024
- }
3025
- break;
3026
- case 'setclip': {
3027
- if (args['_'].length != 1) {
3028
- response = 'Proper usage: setclip "sample text"';
3029
- } else {
3030
- if (require('MeshAgent').isService) {
3031
- require('clipboard').dispatchWrite(args['_'][0]);
3032
- response = 'Setting clipboard to: "' + args['_'][0] + '"';
3033
- }
3034
- else {
3035
- require("clipboard")(args['_'][0]); response = 'Setting clipboard to: "' + args['_'][0] + '"';
3036
- }
3037
- }
3038
- break;
3039
- }
3040
- case 'amtreset': {
3041
- if (amt != null) { amt.reset(); response = 'Done.'; }
3042
- break;
3043
- }
3044
- case 'amtlmsreset': {
3045
- if (amt != null) { amt.lmsreset(); response = 'Done.'; }
3046
- break;
3047
- }
3048
- case 'amtccm': {
3049
- if (amt == null) { response = 'Intel AMT not supported.'; } else {
3050
- if (args['_'].length != 1) { response = 'Proper usage: amtccm (adminPassword)'; } // Display usage
3051
- else { amt.setPolicy({ type: 0 }); amt.activeToCCM(args['_'][0]); }
3052
- }
3053
- break;
3054
- }
3055
- case 'amtacm': {
3056
- if (amt == null) { response = 'Intel AMT not supported.'; } else {
3057
- amt.setPolicy({ type: 0 });
3058
- amt.getAmtInfo(function (meinfo) { amt.activeToACM(meinfo); });
3059
- }
3060
- break;
3061
- }
3062
- case 'amtdeactivate': {
3063
- if (amt == null) { response = 'Intel AMT not supported.'; } else { amt.setPolicy({ type: 0 }); amt.deactivateCCM(); }
3064
- break;
3065
- }
3066
- case 'amtpolicy': {
3067
- if (amtPolicy == null) {
3068
- response = 'No Intel(R) AMT policy.';
3069
- } else {
3070
- response = JSON.stringify(amtPolicy);
3071
- }
3072
- break;
3073
- }
3074
- case 'openurl': {
3075
- if (args['_'].length != 1) { response = 'Proper usage: openurl (url)'; } // Display usage
3076
- else { if (openUserDesktopUrl(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } }
3077
- break;
3078
- }
3079
- case 'users': {
3080
- if (meshCoreObj.users == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + meshCoreObj.users.join(', ') + '.'; }
3081
- require('user-sessions').enumerateUsers().then(function (u) { for (var i in u) { sendConsoleText(u[i]); } });
3082
- break;
3083
- }
3084
- case 'toast': {
3085
- if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
3086
- if (require('MeshAgent')._tsid == null) {
3087
- require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
3088
- }
3089
- else {
3090
- require('toaster').Toast('MeshCentral', args['_'][0], require('MeshAgent')._tsid).then(sendConsoleText, sendConsoleText);
3091
- }
3092
- }
3093
- break;
3094
- }
3095
- case 'setdebug': {
3096
- if (args['_'].length < 1) { response = 'Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile'; } // Display usage
3097
- else { if (args['_'][0] == '*') { console.setDestination(2); } else { console.setDestination(parseInt(args['_'][0]), sessionid); } }
3098
- break;
3099
- }
3100
- case 'ps': {
3101
- processManager.getProcesses(function (plist) {
3102
- var x = '';
3103
- for (var i in plist) { x += i + ((plist[i].user) ? (', ' + plist[i].user) : '') + ', ' + plist[i].cmd + '\r\n'; }
3104
- sendConsoleText(x, sessionid);
3105
- });
3106
- break;
3107
- }
3108
- case 'kill': {
3109
- if ((args['_'].length < 1)) {
3110
- response = 'Proper usage: kill [pid]'; // Display correct command usage
3111
- } else {
3112
- process.kill(parseInt(args['_'][0]));
3113
- response = 'Killed process ' + args['_'][0] + '.';
3114
- }
3115
- break;
3116
- }
3117
- case 'smbios': {
3118
- if (SMBiosTables == null) { response = 'SMBios tables not available.'; } else { response = objToString(SMBiosTables, 0, ' ', true); }
3119
- break;
3120
- }
3121
- case 'rawsmbios': {
3122
- if (SMBiosTablesRaw == null) { response = 'SMBios tables not available.'; } else {
3123
- response = '';
3124
- for (var i in SMBiosTablesRaw) {
3125
- var header = false;
3126
- for (var j in SMBiosTablesRaw[i]) {
3127
- if (SMBiosTablesRaw[i][j].length > 0) {
3128
- if (header == false) { response += ('Table type #' + i + ((require('smbios').smTableTypes[i] == null) ? '' : (', ' + require('smbios').smTableTypes[i]))) + '\r\n'; header = true; }
3129
- response += (' ' + SMBiosTablesRaw[i][j].toString('hex')) + '\r\n';
3130
- }
3131
- }
3132
- }
3133
- }
3134
- break;
3135
- }
3136
- case 'eval': { // Eval JavaScript
3137
- if (args['_'].length < 1) {
3138
- response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
3139
- } else {
3140
- response = JSON.stringify(mesh.eval(args['_'][0])); // This can only be run by trusted administrator.
3141
- }
3142
- break;
3143
- }
3144
- case 'uninstallagent': // Uninstall this agent
3145
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3146
- if (!require('service-manager').manager.getService(agentName).isMe()) {
3147
- response = 'Uininstall failed, this instance is not the service instance';
3148
- } else {
3149
- try { diagnosticAgent_uninstall(); } catch (e) { }
3150
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
3151
- 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 });
3152
- }
3153
- break;
3154
- case 'notify': { // Send a notification message to the mesh
3155
- if (args['_'].length != 1) {
3156
- response = 'Proper usage: notify "message" [--session]'; // Display correct command usage
3157
- } else {
3158
- var notification = { action: 'msg', type: 'notify', value: args['_'][0], tag: 'console' };
3159
- if (args.session) { notification.sessionid = sessionid; } // If "--session" is specified, notify only this session, if not, the server will notify the mesh
3160
- mesh.SendCommand(notification); // no sessionid or userid specified, notification will go to the entire mesh
3161
- response = "ok";
3162
- }
3163
- break;
3164
- }
3165
- case 'cpuinfo': { // Return system information
3166
- // CPU & memory utilization
3167
- pr = require('sysinfo').cpuUtilization();
3168
- pr.sessionid = sessionid;
3169
- pr.then(function (data) {
3170
- sendConsoleText(JSON.stringify({ cpu: data, memory: require('sysinfo').memUtilization() }, null, 1), this.sessionid);
3171
- }, function (e) {
3172
- sendConsoleText(e);
3173
- });
3174
- break;
3175
- }
3176
- case 'sysinfo': { // Return system information
3177
- getSystemInformation(function (results, err) {
3178
- if (results == null) { sendConsoleText(err, this.sessionid); } else {
3179
- sendConsoleText(JSON.stringify(results, null, 1), this.sessionid);
3180
- }
3181
- });
3182
- break;
3183
- }
3184
- case 'info': { // Return information about the agent and agent core module
3185
- 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 + '.';
3186
- if (amt != null) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amt.lmsstate] + '.'; }
3187
- if (meshCoreObj.osdesc) { response += '\r\nOS: ' + meshCoreObj.osdesc + '.'; }
3188
- response += '\r\nModules: ' + addedModules.join(', ') + '.';
3189
- response += '\r\nServer Connection: ' + mesh.isControlChannelConnected + ', State: ' + meshServerConnectionState + '.';
3190
- response += '\r\lastMeInfo: ' + lastMeInfo + '.';
3191
- var oldNodeId = db.Get('OldNodeId');
3192
- if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
3193
- if (process.platform == 'linux' || process.platform == 'freebsd') { response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.'; }
3194
- break;
3195
- }
3196
- case 'osinfo': { // Return the operating system information
3197
- var i = 1;
3198
- if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; }
3199
- for (var j = 0; j < i; j++) {
3200
- var pr = require('os').name();
3201
- pr.sessionid = sessionid;
3202
- pr.then(function (v) {
3203
- sendConsoleText("OS: " + v + (process.platform == 'win32' ? (require('win-virtual-terminal').supported ? ' [ConPTY: YES]' : ' [ConPTY: NO]') : ''), this.sessionid);
3204
- });
3205
- }
3206
- break;
3207
- }
3208
- case 'sendcaps': { // Send capability flags to the server
3209
- if (args['_'].length == 0) {
3210
- response = 'Proper usage: sendcaps (number)'; // Display correct command usage
3211
- } else {
3212
- meshCoreObj.caps = parseInt(args['_'][0]);
3213
- mesh.SendCommand(meshCoreObj);
3214
- response = JSON.stringify(meshCoreObj);
3215
- }
3216
- break;
3217
- }
3218
- case 'sendosdesc': { // Send OS description
3219
- if (args['_'].length > 0) {
3220
- meshCoreObj.osdesc = args['_'][0];
3221
- mesh.SendCommand(meshCoreObj);
3222
- response = JSON.stringify(meshCoreObj);
3223
- } else {
3224
- response = 'Proper usage: sendosdesc [os description]'; // Display correct command usage
3225
- }
3226
- break;
3227
- }
3228
- case 'args': { // Displays parsed command arguments
3229
- response = 'args ' + objToString(args, 0, ' ', true);
3230
- break;
3231
- }
3232
- case 'print': { // Print a message on the mesh agent console, does nothing when running in the background
3233
- var r = [];
3234
- for (var i in args['_']) { r.push(args['_'][i]); }
3235
- console.log(r.join(' '));
3236
- response = 'Message printed on agent console.';
3237
- break;
3238
- }
3239
- case 'type': { // Returns the content of a file
3240
- if (args['_'].length == 0) {
3241
- response = 'Proper usage: type (filepath) [maxlength]'; // Display correct command usage
3242
- } else {
3243
- var max = 4096;
3244
- if ((args['_'].length > 1) && (typeof args['_'][1] == 'number')) { max = args['_'][1]; }
3245
- if (max > 4096) max = 4096;
3246
- var buf = Buffer.alloc(max), fd = fs.openSync(args['_'][0], "r"), r = fs.readSync(fd, buf, 0, max); // Read the file content
3247
- response = buf.toString();
3248
- var i = response.indexOf('\n');
3249
- if ((i > 0) && (response[i - 1] != '\r')) { response = response.split('\n').join('\r\n'); }
3250
- if (r == max) response += '...';
3251
- fs.closeSync(fd);
3252
- }
3253
- break;
3254
- }
3255
- case 'dbkeys': { // Return all data store keys
3256
- response = JSON.stringify(db.Keys);
3257
- break;
3258
- }
3259
- case 'dbget': { // Return the data store value for a given key
3260
- if (db == null) { response = 'Database not accessible.'; break; }
3261
- if (args['_'].length != 1) {
3262
- response = 'Proper usage: dbget (key)'; // Display the value for a given database key
3263
- } else {
3264
- response = db.Get(args['_'][0]);
3265
- }
3266
- break;
3267
- }
3268
- case 'dbset': { // Set a data store key and value pair
3269
- if (db == null) { response = 'Database not accessible.'; break; }
3270
- if (args['_'].length != 2) {
3271
- response = 'Proper usage: dbset (key) (value)'; // Set a database key
3272
- } else {
3273
- var r = db.Put(args['_'][0], args['_'][1]);
3274
- response = 'Key set: ' + r;
3275
- }
3276
- break;
3277
- }
3278
- case 'dbcompact': { // Compact the data store
3279
- if (db == null) { response = 'Database not accessible.'; break; }
3280
- var r = db.Compact();
3281
- response = 'Database compacted: ' + r;
3282
- break;
3283
- }
3284
- case 'httpget': {
3285
- if (consoleHttpRequest != null) {
3286
- response = 'HTTP operation already in progress.';
3287
- } else {
3288
- if (args['_'].length != 1) {
3289
- response = 'Proper usage: httpget (url)';
3290
- } else {
3291
- var options = http.parseUri(args['_'][0]);
3292
- options.method = 'GET';
3293
- if (options == null) {
3294
- response = 'Invalid url.';
3295
- } else {
3296
- try { consoleHttpRequest = http.request(options, consoleHttpResponse); } catch (e) { response = 'Invalid HTTP GET request'; }
3297
- consoleHttpRequest.sessionid = sessionid;
3298
- if (consoleHttpRequest != null) {
3299
- consoleHttpRequest.end();
3300
- response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
3301
- }
3302
- }
3303
- }
3304
- }
3305
- break;
3306
- }
3307
- case 'wslist': { // List all web sockets
3308
- response = '';
3309
- for (var i in consoleWebSockets) {
3310
- var httprequest = consoleWebSockets[i];
3311
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3312
- }
3313
- if (response == '') { response = 'no websocket sessions.'; }
3314
- break;
3315
- }
3316
- case 'wsconnect': { // Setup a web socket
3317
- if (args['_'].length == 0) {
3318
- response = 'Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc'; // Display correct command usage
3319
- } else {
3320
- var httprequest = null;
3321
- try {
3322
- var options = http.parseUri(args['_'][0].split('$').join('%24').split('@').join('%40')); // Escape the $ and @ characters in the URL
3323
- options.rejectUnauthorized = 0;
3324
- httprequest = http.request(options);
3325
- } catch (e) { response = 'Invalid HTTP websocket request'; }
3326
- if (httprequest != null) {
3327
- httprequest.upgrade = onWebSocketUpgrade;
3328
- httprequest.on('error', function (e) { sendConsoleText("ERROR: Unable to connect to: " + this.url + ", " + JSON.stringify(e)); });
3329
-
3330
- var index = 1;
3331
- while (consoleWebSockets[index]) { index++; }
3332
- httprequest.sessionid = sessionid;
3333
- httprequest.index = index;
3334
- httprequest.url = args['_'][0];
3335
- consoleWebSockets[index] = httprequest;
3336
- response = 'New websocket session #' + index;
3337
- }
3338
- }
3339
- break;
3340
- }
3341
- case 'wssend': { // Send data on a web socket
3342
- if (args['_'].length == 0) {
3343
- response = 'Proper usage: wssend (socketnumber)\r\n'; // Display correct command usage
3344
- for (var i in consoleWebSockets) {
3345
- var httprequest = consoleWebSockets[i];
3346
- response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3347
- }
3348
- } else {
3349
- var i = parseInt(args['_'][0]);
3350
- var httprequest = consoleWebSockets[i];
3351
- if (httprequest != undefined) {
3352
- httprequest.s.write(args['_'][1]);
3353
- response = 'ok';
3354
- } else {
3355
- response = 'Invalid web socket number';
3356
- }
3357
- }
3358
- break;
3359
- }
3360
- case 'wsclose': { // Close a websocket
3361
- if (args['_'].length == 0) {
3362
- response = 'Proper usage: wsclose (socketnumber)'; // Display correct command usage
3363
- } else {
3364
- var i = parseInt(args['_'][0]);
3365
- var httprequest = consoleWebSockets[i];
3366
- if (httprequest != undefined) {
3367
- if (httprequest.s != null) { httprequest.s.end(); } else { httprequest.end(); }
3368
- response = 'ok';
3369
- } else {
3370
- response = 'Invalid web socket number';
3371
- }
3372
- }
3373
- break;
3374
- }
3375
- case 'tunnels': { // Show the list of current tunnels
3376
- response = '';
3377
- for (var i in tunnels) { response += 'Tunnel #' + i + ', ' + tunnels[i].url + '\r\n'; }
3378
- if (response == '') { response = 'No websocket sessions.'; }
3379
- break;
3380
- }
3381
- case 'ls': { // Show list of files and folders
3382
- response = '';
3383
- var xpath = '*';
3384
- if (args['_'].length > 0) { xpath = obj.path.join(args['_'][0], '*'); }
3385
- response = 'List of ' + xpath + '\r\n';
3386
- var results = fs.readdirSync(xpath);
3387
- for (var i = 0; i < results.length; ++i) {
3388
- var stat = null, p = obj.path.join(args['_'][0], results[i]);
3389
- try { stat = fs.statSync(p); } catch (e) { }
3390
- if ((stat == null) || (stat == undefined)) {
3391
- response += (results[i] + "\r\n");
3392
- } else {
3393
- response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
3394
- }
3395
- }
3396
- break;
3397
- }
3398
- case 'lsx': { // Show list of files and folders
3399
- response = objToString(getDirectoryInfo(args['_'][0]), 0, ' ', true);
3400
- break;
3401
- }
3402
- case 'lock': { // Lock the current user out of the desktop
3403
- if (process.platform == 'win32') { var child = require('child_process'); child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 }); response = 'Ok'; }
3404
- else { response = 'Not supported on the platform'; }
3405
- break;
3406
- }
3407
- case 'amt': { // Show Intel AMT status
3408
- if (amt != null) {
3409
- amt.getAmtInfo(function (state) {
3410
- var resp = 'Intel AMT not detected.';
3411
- if (state != null) { resp = objToString(state, 0, ' ', true); }
3412
- sendConsoleText(resp, sessionid);
3413
- });
3414
- } else {
3415
- response = 'Intel AMT not detected.';
3416
- }
3417
- break;
3418
- }
3419
- case 'netinfo': { // Show network interface information
3420
- var interfaces = require('os').networkInterfaces();
3421
- response = objToString(interfaces, 0, ' ', true);
3422
- break;
3423
- }
3424
- case 'wakeonlan': { // Send wake-on-lan
3425
- if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
3426
- response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
3427
- } else {
3428
- var count = sendWakeOnLan(args['_'][0]);
3429
- response = 'Sent wake-on-lan on ' + count + ' interface(s).';
3430
- }
3431
- break;
3432
- }
3433
- case 'sendall': { // Send a message to all consoles on this mesh
3434
- sendConsoleText(args['_'].join(' '));
3435
- break;
3436
- }
3437
- case 'power': { // Execute a power action on this computer
3438
- if (mesh.ExecPowerState == undefined) {
3439
- response = 'Power command not supported on this agent.';
3440
- } else {
3441
- if ((args['_'].length == 0) || isNaN(Number(args['_'][0]))) {
3442
- 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
3443
- } else {
3444
- var r = mesh.ExecPowerState(Number(args['_'][0]), Number(args['_'][1]));
3445
- response = 'Power action executed with return code: ' + r + '.';
3446
- }
3447
- }
3448
- break;
3449
- }
3450
- case 'location': {
3451
- getIpLocationData(function (location) {
3452
- sendConsoleText(objToString({ action: 'iplocation', type: 'publicip', value: location }, 0, ' '));
3453
- });
3454
- break;
3455
- }
3456
- case 'parseuri': {
3457
- response = JSON.stringify(http.parseUri(args['_'][0]));
3458
- break;
3459
- }
3460
- case 'scanwifi': {
3461
- if (wifiScanner != null) {
3462
- var wifiPresent = wifiScanner.hasWireless;
3463
- if (wifiPresent) { response = "Perfoming Wifi scan..."; wifiScanner.Scan(); } else { response = "Wifi absent."; }
3464
- } else { response = "Wifi module not present."; }
3465
- break;
3466
- }
3467
- case 'scanamt': {
3468
- if (amtscanner != null) {
3469
- if (args['_'].length != 1) {
3470
- response = 'Usage examples:\r\n scanamt 1.2.3.4\r\n scanamt 1.2.3.0-1.2.3.255\r\n scanamt 1.2.3.0/24\r\n'; // Display correct command usage
3471
- } else {
3472
- response = 'Scanning: ' + args['_'][0] + '...';
3473
- amtscanner.scan(args['_'][0], 2000, function (data) {
3474
- if (data.length > 0) {
3475
- var r = '', pstates = ['NotActivated', 'InActivation', 'Activated'];
3476
- for (var i in data) {
3477
- var x = data[i];
3478
- if (r != '') { r += '\r\n'; }
3479
- r += x.address + ' - Intel AMT v' + x.majorVersion + '.' + x.minorVersion;
3480
- if (x.provisioningState < 3) { r += (', ' + pstates[x.provisioningState]); }
3481
- if (x.provisioningState == 2) { r += (', ' + x.openPorts.join(', ')); }
3482
- r += '.';
3483
- }
3484
- } else {
3485
- r = 'No Intel AMT found.';
3486
- }
3487
- sendConsoleText(r);
3488
- });
3489
- }
3490
- } else { response = "Intel AMT scanner module not present."; }
3491
- break;
3492
- }
3493
- case 'modules': {
3494
- response = JSON.stringify(addedModules);
3495
- break;
3496
- }
3497
- case 'listservices': {
3498
- var services = require('service-manager').manager.enumerateService();
3499
- response = JSON.stringify(services, null, 1);
3500
- break;
3501
- }
3502
- case 'getscript': {
3503
- if (args['_'].length != 1) {
3504
- response = "Proper usage: getscript [scriptNumber].";
3505
- } else {
3506
- mesh.SendCommand({ action: 'getScript', type: args['_'][0] });
3507
- }
3508
- break;
3509
- }
3510
- case 'diagnostic':
3511
- {
3512
- if (!mesh.DAIPC.listening) {
3513
- response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
3514
- break;
3515
- }
3516
- var diag = diagnosticAgent_installCheck();
3517
- if (diag) {
3518
- if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
3519
- diagnosticAgent_uninstall();
3520
- response = 'Diagnostic Agent uninstalled';
3521
- }
3522
- else {
3523
- response = 'Diagnostic Agent installed at: ' + diag.appLocation();
3524
- }
3525
- }
3526
- else {
3527
- if (args['_'].length == 1 && args['_'][0] == 'install') {
3528
- diag = diagnosticAgent_installCheck(true);
3529
- if (diag) {
3530
- response = 'Diagnostic agent was installed at: ' + diag.appLocation();
3531
- }
3532
- else {
3533
- response = 'Diagnostic agent installation failed';
3534
- }
3535
- }
3536
- else {
3537
- response = 'Diagnostic Agent Not installed. To install: diagnostic install';
3538
- }
3539
- }
3540
- if (diag) { diag.close(); diag = null; }
3541
- break;
3542
- }
3543
- case 'amtconfig': {
3544
- if (apftunnel != null) { response = "Intel AMT server tunnel already active"; break; }
3545
- if (amt == null) { response = "No Intel AMT support delected"; break; }
3546
- getMeiState(15, function (state) {
3547
- var rx = '';
3548
- if ((state == null) || (state.ProvisioningState == null)) { rx = "Intel AMT not ready for configuration."; } else {
3549
- var apfarg = {
3550
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3551
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3552
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3553
- mpskeepalive: 60000,
3554
- clientname: state.OsHostname,
3555
- clientaddress: '127.0.0.1',
3556
- clientuuid: state.UUID,
3557
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3558
- meiState: state // MEI state will be passed to MPS server
3559
- };
3560
- if ((state.UUID == null) || (state.UUID.length != 36)) {
3561
- rx = "Unable to get Intel AMT UUID";
3562
- } else {
3563
- apftunnel = require('apfclient')({ debug: false }, apfarg);
3564
- apftunnel.onJsonControl = function (data) {
3565
- if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); } // Display a console message
3566
- if (data.action == 'mestate') { getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
3567
- if (data.action == 'deactivate') { // Request CCM deactivation
3568
- var amtMeiModule, amtMei;
3569
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { apftunnel.sendMeiDeactivationState(1); return; }
3570
- amtMei.on('error', function (e) { apftunnel.sendMeiDeactivationState(1); });
3571
- amtMei.unprovision(1, function (status) { apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
3572
- }
3573
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
3574
- }
3575
- apftunnel.onChannelClosed = function () { apftunnel = null; }
3576
- try {
3577
- apftunnel.connect();
3578
- rx = "Started Intel AMT configuration";
3579
- } catch (ex) {
3580
- rx = JSON.stringify(ex);
3581
- }
3582
- }
3583
- }
3584
- if (rx != '') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: rx }); }
3585
- });
3586
- break;
3587
- }
3588
- case 'apf': {
3589
- if (meshCoreObj.intelamt !== null) {
3590
- if (args['_'].length == 1) {
3591
- var connType = -1, connTypeStr = args['_'][0].toLowerCase();
3592
- if (connTypeStr == 'lms') { connType = 2; }
3593
- if (connTypeStr == 'relay') { connType = 1; }
3594
- if (connTypeStr == 'cira') { connType = 0; }
3595
- if (connTypeStr == 'off') { connType = -2; }
3596
- if (connType >= 0) { // Connect
3597
- var apfarg = {
3598
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3599
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3600
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3601
- mpskeepalive: 60000,
3602
- clientname: require('os').hostname(),
3603
- clientaddress: '127.0.0.1',
3604
- clientuuid: meshCoreObj.intelamt.uuid,
3605
- conntype: connType // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3606
- };
3607
- if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
3608
- response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
3609
- } else {
3610
- apftunnel = require('apfclient')({ debug: false }, apfarg);
3611
- apftunnel.onJsonControl = function (data) {
3612
- if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
3613
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
3614
- }
3615
- apftunnel.onChannelClosed = function () { apftunnel = null; }
3616
- try {
3617
- apftunnel.connect();
3618
- response = "Started APF tunnel";
3619
- } catch (e) {
3620
- response = JSON.stringify(e);
3621
- }
3622
- }
3623
- } else if (connType == -2) { // Disconnect
3624
- try {
3625
- apftunnel.disconnect();
3626
- response = "Stopped APF tunnel";
3627
- } catch (e) {
3628
- response = JSON.stringify(e);
3629
- }
3630
- apftunnel = null;
3631
- } else {
3632
- response = "Invalid command.\r\nUse: apf lms|relay|cira|off";
3633
- }
3634
- } else {
3635
- response = "APF tunnel is " + (apftunnel == null ? "off" : "on") + "\r\nUse: apf lms|relay|cira|off";
3636
- }
3637
- } else {
3638
- response = "APF tunnel requires Intel AMT";
3639
- }
3640
- break;
3641
- }
3642
- case 'plugin': {
3643
- if (typeof args['_'][0] == 'string') {
3644
- try {
3645
- // Pass off the action to the plugin
3646
- // for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
3647
- // to control the output / actions here.
3648
- response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
3649
- } catch (e) {
3650
- response = "There was an error in the plugin (" + e + ")";
3651
- }
3652
- } else {
3653
- response = "Proper usage: plugin [pluginName] [args].";
3654
- }
3655
- break;
3656
- }
3657
- default: { // This is an unknown command, return an error message
3658
- response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands.";
3659
- break;
3660
- }
3661
- }
3662
- } catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
3663
- if (response != null) { sendConsoleText(response, sessionid); }
3664
- }
3665
-
3666
- // Send a mesh agent console command
3667
- function sendConsoleText(text, sessionid) {
3668
- if (typeof text == 'object') { text = JSON.stringify(text); }
3669
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: text, sessionid: sessionid });
3670
- }
3671
-
3672
- // Called before the process exits
3673
- //process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
3674
-
3675
- // Called when the server connection state changes
3676
- function handleServerConnection(state) {
3677
- meshServerConnectionState = state;
3678
- if (meshServerConnectionState == 0) {
3679
- // Server disconnected
3680
- if (selfInfoUpdateTimer != null) { clearInterval(selfInfoUpdateTimer); selfInfoUpdateTimer = null; }
3681
- lastSelfInfo = null;
3682
- } else {
3683
- // Server connected, send mesh core information
3684
- var oldNodeId = db.Get('OldNodeId');
3685
- if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); }
3686
-
3687
- // Update the server with basic info, logged in users and more.
3688
- mesh.SendCommand(meshCoreObj);
3689
-
3690
- // Send SMBios tables if present
3691
- if (SMBiosTablesRaw != null) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
3692
-
3693
- // Update the server on more advanced stuff, like Intel ME and Network Settings
3694
- meInfoStr = null;
3695
- sendPeriodicServerUpdate();
3696
- if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); } // 20 minutes
3697
-
3698
- // Send any state messages
3699
- if (Object.keys(tunnelUserCount.msg).length > 0) {
3700
- try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (e) { }
3701
- broadcastSessionsToRegisteredApps();
3702
- }
3703
-
3704
- // Send update of registered applications to the server
3705
- updateRegisteredAppsToServer();
3706
- }
3707
-
3708
- // Send server state update to registered applications
3709
- broadcastToRegisteredApps({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer });
3710
- }
3711
-
3712
- // Update the server with the latest network interface information
3713
- var sendNetworkUpdateNagleTimer = null;
3714
- function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
3715
- function sendNetworkUpdate(force) {
3716
- sendNetworkUpdateNagleTimer = null;
3717
-
3718
- // Update the network interfaces information data
3719
- var netInfo = { netif2: require('os').networkInterfaces() };
3720
- if (netInfo.netif2) {
3721
- netInfo.action = 'netinfo';
3722
- var netInfoStr = JSON.stringify(netInfo);
3723
- if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
3724
- }
3725
- }
3726
-
3727
- // Called periodically to check if we need to send updates to the server
3728
- function sendPeriodicServerUpdate(flags) {
3729
- if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
3730
- if (!flags) { flags = 0xFFFFFFFF; }
3731
-
3732
- if ((flags & 1) && (amt != null)) {
3733
- // If we have a connected MEI, get Intel ME information
3734
- amt.getAmtInfo(function (meinfo) {
3735
- try {
3736
- if (meinfo == null) return;
3737
- var intelamt = {};
3738
- if (amt != null)
3739
- {
3740
- switch(amt.lmsstate)
3741
- {
3742
- case 0: intelamt.microlms = 'DISABLED'; break;
3743
- case 1: intelamt.microlms = 'CONNECTING'; break;
3744
- case 2: intelamt.microlms = 'CONNECTED'; break;
3745
- default: intelamt.microlms = 'unknown'; break;
3746
- }
3747
- }
3748
- var p = false;
3749
- if ((meinfo.Versions != null) && (meinfo.Versions.AMT != null)) { intelamt.ver = meinfo.Versions.AMT; p = true; if (meinfo.Versions.Sku != null) { intelamt.sku = parseInt(meinfo.Versions.Sku); } }
3750
- if (meinfo.ProvisioningState != null) { intelamt.state = meinfo.ProvisioningState; p = true; }
3751
- if (meinfo.Flags != null) { intelamt.flags = meinfo.Flags; p = true; }
3752
- if (meinfo.OsHostname != null) { intelamt.host = meinfo.OsHostname; p = true; }
3753
- if (meinfo.UUID != null) { intelamt.uuid = meinfo.UUID; p = true; }
3754
- if ((meinfo.ProvisioningState == 0) && (meinfo.net0 != null) && (meinfo.net0.enabled == 1)) { // If not activated, look to see if we have wired net working.
3755
- // Not activated and we have wired ethernet, look for the trusted DNS
3756
- var dns = meinfo.DNS;
3757
- if (dns == null) {
3758
- // Trusted DNS not set, let's look for the OS network DNS suffix
3759
- var interfaces = require('os').networkInterfaces();
3760
- for (var i in interfaces) {
3761
- for (var j in interfaces[i]) {
3762
- if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { dns = interfaces[i][j].fqdn; }
3763
- }
3764
- }
3765
- }
3766
- if (intelamt.dns != dns) { intelamt.dns = dns; p = true; }
3767
- } else { if (intelamt.dns != null) { delete intelamt.dns; p = true; } }
3768
- if (p == true) {
3769
- var meInfoStr = JSON.stringify(intelamt);
3770
- if (meInfoStr != lastMeInfo) {
3771
- meshCoreObj.intelamt = intelamt;
3772
- mesh.SendCommand(meshCoreObj);
3773
- lastMeInfo = meInfoStr;
3774
- }
3775
- }
3776
- } catch (e) { }
3777
- });
3778
- }
3779
-
3780
- if (flags & 2) {
3781
- // Update network information
3782
- sendNetworkUpdateNagle(false);
3783
- }
3784
-
3785
- if ((flags & 4) && (process.platform == 'win32')) {
3786
- // Update anti-virus information
3787
- // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3788
- var av, pr;
3789
- try { av = require('win-info').av(); } catch (e) { av = null; } // Antivirus
3790
- //if (process.platform == 'win32') { try { pr = require('win-info').pendingReboot(); } catch (e) { pr = null; } } // Pending reboot
3791
- if ((meshCoreObj.av == null) || (JSON.stringify(meshCoreObj.av) != JSON.stringify(av))) { meshCoreObj.av = av; mesh.SendCommand(meshCoreObj); }
3792
- }
3793
- }
3794
-
3795
- // Starting function
3796
- obj.start = function () {
3797
- // Setup the mesh agent event handlers
3798
- mesh.AddCommandHandler(handleServerCommand);
3799
- mesh.AddConnectHandler(handleServerConnection);
3800
-
3801
- // Parse input arguments
3802
- //var args = parseArgs(process.argv);
3803
- //console.log(args);
3804
-
3805
- //resetMicroLms();
3806
-
3807
- // Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
3808
- try {
3809
- var userSession = require('user-sessions');
3810
- userSession.on('changed', function onUserSessionChanged() {
3811
- userSession.enumerateUsers().then(function (users) {
3812
- var u = [], a = users.Active;
3813
- for (var i = 0; i < a.length; i++) {
3814
- var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
3815
- if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
3816
- }
3817
- meshCoreObj.users = u;
3818
- mesh.SendCommand(meshCoreObj);
3819
- });
3820
- });
3821
- userSession.emit('changed');
3822
- //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
3823
- //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
3824
- } catch (e) { }
3825
- }
3826
-
3827
- obj.stop = function () {
3828
- mesh.AddCommandHandler(null);
3829
- mesh.AddConnectHandler(null);
3830
- }
3831
-
3832
- function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
3833
- function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
3834
- function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
3835
-
3836
- function onWebSocketUpgrade(response, s, head) {
3837
- sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
3838
- this.s = s;
3839
- s.httprequest = this;
3840
- s.end = onWebSocketClosed;
3841
- s.data = onWebSocketData;
3842
- }
3843
-
3844
- // Get Intel MEI State in a flexible way
3845
- // Flags: 1 = Versions, 2 = OsAdmin, 4 = Hashes, 8 = Network
3846
- function getMeiState(flags, func) {
3847
- var amtMeiModule, amtMei;
3848
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { func(null); return; }
3849
- amtMei.on('error', function (e) { func(null); return; });
3850
- try {
3851
- var amtMeiTmpState = { OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
3852
- amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
3853
- if ((flags & 1) != 0) { amtMei.getVersion(function (result) { if (result) { amtMeiTmpState.Versions = {}; for (var version in result.Versions) { amtMeiTmpState.Versions[result.Versions[version].Description] = result.Versions[version].Version; } } }); }
3854
- amtMei.getProvisioningMode(function (result) { if (result) { amtMeiTmpState.ProvisioningMode = result.mode; } });
3855
- amtMei.getProvisioningState(function (result) { if (result) { amtMeiTmpState.ProvisioningState = result.state; } }); // 0: "Not Activated (Pre)", 1: "Not Activated (In)", 2: "Activated"
3856
- amtMei.getEHBCState(function (result) { if ((result != null) && (result.EHBC == true)) { amtMeiTmpState.Flags += 1; } });
3857
- amtMei.getControlMode(function (result) { if (result != null) { if (result.controlMode == 1) { amtMeiTmpState.Flags += 2; } if (result.controlMode == 2) { amtMeiTmpState.Flags += 4; } } }); // Flag 2 = CCM, 4 = ACM
3858
- //amtMei.getMACAddresses(function (result) { if (result) { amtMeiTmpState.mac = result; } });
3859
- if ((flags & 8) != 0) {
3860
- amtMei.getLanInterfaceSettings(0, function (result) {
3861
- if (result) {
3862
- amtMeiTmpState.net0 = result;
3863
- var fqdn = null, interfaces = require('os').networkInterfaces(); // Look for the DNS suffix for the Intel AMT Ethernet interface
3864
- for (var i in interfaces) { for (var j in interfaces[i]) { if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { amtMeiTmpState.OsDnsSuffix = interfaces[i][j].fqdn; } } }
3865
- }
3866
- });
3867
- amtMei.getLanInterfaceSettings(1, function (result) { if (result) { amtMeiTmpState.net1 = result; } });
3868
- }
3869
- amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { amtMeiTmpState.UUID = result.uuid; } });
3870
- if ((flags & 2) != 0) { amtMei.getLocalSystemAccount(function (x) { if ((x != null) && x.user && x.pass) { amtMeiTmpState.OsAdmin = { user: x.user, pass: x.pass }; } }); }
3871
- amtMei.getDnsSuffix(function (result) { if (result != null) { amtMeiTmpState.DnsSuffix = result; } if ((flags & 4) == 0) { if (func != null) { func(amtMeiTmpState); } } });
3872
- if ((flags & 4) != 0) {
3873
- amtMei.getHashHandles(function (handles) {
3874
- if ((handles != null) && (handles.length > 0)) { amtMeiTmpState.Hashes = []; } else { func(amtMeiTmpState); }
3875
- var exitOnCount = handles.length;
3876
- for (var i = 0; i < handles.length; ++i) { this.getCertHashEntry(handles[i], function (hashresult) { amtMeiTmpState.Hashes.push(hashresult); if (--exitOnCount == 0) { if (func != null) { func(amtMeiTmpState); } } }); }
3877
- });
3878
- }
3879
- } catch (e) { if (func != null) { func(null); } return; }
3880
- }
3881
-
3882
- return obj;
3883
-}
3884
-
3885
-//
3886
-// Module startup
3887
-//
3888
-
3889
-try {
3890
- var xexports = null, mainMeshCore = null;
3891
- try { xexports = module.exports; } catch (e) { }
3892
-
3893
- if (xexports != null) {
3894
- // If we are running within NodeJS, export the core
3895
- module.exports.createMeshCore = createMeshCore;
3896
- } else {
3897
- // If we are not running in NodeJS, launch the core
3898
- mainMeshCore = createMeshCore();
3899
- mainMeshCore.start(null);
3900
- }
3901
-} catch (e) {
3902
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException2: " + ex });
3903
-}