Added workaround for platforms where /var/run/utmp is touched too frequently Fixed Global/Function scope problems
Added workaround for platforms where /var/run/utmp is touched too frequently Fixed Global/Function scope problems
Bryan Roe committed
Jan 24, 2021 at 15:19 UTC
1a65fd5ab68139773c851dfe0eaaf24963af4d82
1 file changed
+4216
-3661
agents/meshcore.js
+4216
-3661
@@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
-process.on('uncaughtException', function (ex) {
17
+process.on('uncaughtException', function (ex)
18
+{
19
require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException1: " + ex });
20
});
21
@@ -41,9 +42,11 @@ var MESHRIGHT_CHATNOTIFY = 16384;
42
var MESHRIGHT_UNINSTALL = 32768;
43
var MESHRIGHT_NODESKTOP = 65536;
44
44
-if (require('MeshAgent').ARCHID == null) {
45
+if (require('MeshAgent').ARCHID == null)
46
+{
47
var id = null;
46
- switch (process.platform) {
48
+ switch (process.platform)
49
+ {
50
case 'win32':
51
id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
52
break;
@@ -51,10 +54,12 @@ if (require('MeshAgent').ARCHID == null) {
54
id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
55
break;
56
case 'darwin':
54
- try {
57
+ try
58
+ {
59
id = require('os').arch() == 'x64' ? 16 : 29;
60
}
57
- catch (xx) {
61
+ catch (xx)
62
+ {
63
id = 16;
64
}
65
break; break;
@@ -62,609 +67,685 @@ if (require('MeshAgent').ARCHID == null) {
67
if (id != null) { Object.defineProperty(require('MeshAgent'), 'ARCHID', { value: id }); }
68
}
69
65
-function createMeshCore(agent) {
66
- var obj = {};
67
- var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests from the server.
68
- var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server.
69
- var debugConsole = (_MSH().debugConsole == 1);
70
-
71
- if (process.platform == 'win32' && require('user-sessions').isRoot()) {
72
- // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
73
- try {
74
- var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
75
- try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
76
- if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
77
- } catch (x) { }
78
-
79
- // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
80
- var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
81
- try {
82
- svcname = require('MeshAgent').serviceName;
83
- }
84
- catch (x) {
85
- }
70
+var obj = {};
71
+var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests from the server.
72
+var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server.
73
+var debugConsole = (_MSH().debugConsole == 1);
74
87
- try {
88
- var meshCheck = false;
89
- try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (e) { }
90
- if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
91
- } catch (e) { }
75
+if (process.platform == 'win32' && require('user-sessions').isRoot())
76
+{
77
+ // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
78
+ try
79
+ {
80
+ var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
81
+ try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
82
+ if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
83
+ } catch (x) { }
84
+
85
+ // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
86
+ var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
87
+ try
88
+ {
89
+ svcname = require('MeshAgent').serviceName;
90
}
91
+ catch (x)
92
+ {
93
+ }
94
+
95
+ try
96
+ {
97
+ var meshCheck = false;
98
+ try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (e) { }
99
+ if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
100
+ } catch (e) { }
101
+}
102
94
- if (process.platform == 'darwin' && !process.versions) {
95
- // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
96
- var child = require('child_process').execFile('/bin/sh', ['sh']);
103
+if (process.platform == 'darwin' && !process.versions)
104
+{
105
+ // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
106
+ var child = require('child_process').execFile('/bin/sh', ['sh']);
107
+ child.stdout.str = '';
108
+ child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
109
+ 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, \">\"); ");
110
+ 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]; } }");
111
+ child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
112
+ child.waitExit();
113
+ if (child.stdout.str.trim() == 'Crashed')
114
+ {
115
+ child = require('child_process').execFile('/bin/sh', ['sh']);
116
child.stdout.str = '';
117
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
99
- 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, \">\"); ");
100
- 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]; } }");
101
- child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
118
+ child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
119
child.waitExit();
103
- if (child.stdout.str.trim() == 'Crashed') {
104
- child = require('child_process').execFile('/bin/sh', ['sh']);
105
- child.stdout.str = '';
106
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
107
- child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
108
- child.waitExit();
109
-
110
- if (parseInt(child.stdout.str.trim()) == process.pid) {
111
- // The currently running MeshAgent is us, so we can continue with the update
112
- var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
113
- var tokens = plist.split('<key>KeepAlive</key>');
114
- if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
115
- var tmp = tokens[1].split('</dict>');
116
- tmp.shift();
117
- tokens[1] = '\n <true/>' + tmp.join('</dict>');
118
- tokens = tokens.join('<key>KeepAlive</key>');
119
-
120
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
121
-
122
- var fix = '';
123
- fix += ("function macosRepair()\n");
124
- fix += ("{\n");
125
- fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
126
- fix += (" child.stdout.str = '';\n");
127
- fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
128
- fix += (" child.stderr.on('data', function (chunk) { });\n");
129
- fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
130
- fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
131
- fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
132
- fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
133
- fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
134
- fix += (" child.waitExit();\n");
135
- fix += ("}\n");
136
- fix += ("macosRepair();\n");
137
- fix += ("process.exit();\n");
138
- require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
139
-
140
- var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
141
- plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
142
- plist += '<plist version="1.0">\n';
143
- plist += ' <dict>\n';
144
- plist += ' <key>Label</key>\n';
145
- plist += (' <string>meshagentRepair</string>\n');
146
- plist += ' <key>ProgramArguments</key>\n';
147
- plist += ' <array>\n';
148
- plist += (' <string>' + process.execPath + '</string>\n');
149
- plist += ' <string>macosRepair.js</string>\n';
150
- plist += ' </array>\n';
151
- plist += ' <key>WorkingDirectory</key>\n';
152
- plist += (' <string>' + process.cwd() + '</string>\n');
153
- plist += ' <key>RunAtLoad</key>\n';
154
- plist += ' <true/>\n';
155
- plist += ' </dict>\n';
156
- plist += '</plist>';
157
- require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
158
-
159
- child = require('child_process').execFile('/bin/sh', ['sh']);
160
- child.stdout.str = '';
161
- child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
162
- child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
163
- child.waitExit();
164
- }
120
+
121
+ if (parseInt(child.stdout.str.trim()) == process.pid)
122
+ {
123
+ // The currently running MeshAgent is us, so we can continue with the update
124
+ var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
125
+ var tokens = plist.split('<key>KeepAlive</key>');
126
+ if (tokens[1].split('>')[0].split('<')[1] == 'dict')
127
+ {
128
+ var tmp = tokens[1].split('</dict>');
129
+ tmp.shift();
130
+ tokens[1] = '\n <true/>' + tmp.join('</dict>');
131
+ tokens = tokens.join('<key>KeepAlive</key>');
132
+
133
+ require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
134
+
135
+ var fix = '';
136
+ fix += ("function macosRepair()\n");
137
+ fix += ("{\n");
138
+ fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
139
+ fix += (" child.stdout.str = '';\n");
140
+ fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
141
+ fix += (" child.stderr.on('data', function (chunk) { });\n");
142
+ fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
143
+ fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
144
+ fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
145
+ fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
146
+ fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
147
+ fix += (" child.waitExit();\n");
148
+ fix += ("}\n");
149
+ fix += ("macosRepair();\n");
150
+ fix += ("process.exit();\n");
151
+ require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
152
+
153
+ var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
154
+ plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
155
+ plist += '<plist version="1.0">\n';
156
+ plist += ' <dict>\n';
157
+ plist += ' <key>Label</key>\n';
158
+ plist += (' <string>meshagentRepair</string>\n');
159
+ plist += ' <key>ProgramArguments</key>\n';
160
+ plist += ' <array>\n';
161
+ plist += (' <string>' + process.execPath + '</string>\n');
162
+ plist += ' <string>macosRepair.js</string>\n';
163
+ plist += ' </array>\n';
164
+ plist += ' <key>WorkingDirectory</key>\n';
165
+ plist += (' <string>' + process.cwd() + '</string>\n');
166
+ plist += ' <key>RunAtLoad</key>\n';
167
+ plist += ' <true/>\n';
168
+ plist += ' </dict>\n';
169
+ plist += '</plist>';
170
+ require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
171
+
172
+ child = require('child_process').execFile('/bin/sh', ['sh']);
173
+ child.stdout.str = '';
174
+ child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
175
+ child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
176
+ child.waitExit();
177
}
178
}
179
}
180
+}
181
169
- // Add an Intel AMT event to the log
170
- function addAmtEvent(msg) {
171
- if (obj.amtevents == null) { obj.amtevents = []; }
172
- var d = new Date();
173
- obj.amtevents.push(zeroPad(d.getHours(), 2) + ':' + zeroPad(d.getMinutes(), 2) + ':' + zeroPad(d.getSeconds(), 2) + ', ' + msg);
174
- if (obj.amtevents.length > 100) { obj.amtevents.splice(0, obj.amtevents.length - 100); }
175
- }
176
- function zeroPad(num, size) { var s = '000000000' + num; return s.substr(s.length - size); }
177
-
178
-
179
- // Create Secure IPC for Diagnostic Agent Communications
180
- obj.DAIPC = require('net').createServer();
181
- if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
182
- obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
183
- try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
184
- obj.DAIPC._daipc = [];
185
- obj.DAIPC.on('connection', function (c) {
186
- c._send = function (j) {
187
- var data = JSON.stringify(j);
188
- var packet = Buffer.alloc(data.length + 4);
189
- packet.writeUInt32LE(data.length + 4, 0);
190
- Buffer.from(data).copy(packet, 4);
191
- this.write(packet);
192
- };
193
- this._daipc.push(c);
194
- c.parent = this;
195
- c.on('end', function () { removeRegisteredApp(this); });
196
- c.on('data', function (chunk) {
197
- if (chunk.length < 4) { this.unshift(chunk); return; }
198
- var len = chunk.readUInt32LE(0);
199
- if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
200
- if (chunk.length < len) { this.unshift(chunk); return; }
201
-
202
- var data = chunk.slice(4, len);
203
- try { data = JSON.parse(data.toString()); } catch (e) { }
204
- if ((data == null) || (typeof data.cmd != 'string')) return;
205
-
206
- try {
207
- switch (data.cmd) {
208
- case 'requesthelp':
209
- if (this._registered == null) return;
210
- sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
211
- var help = {};
212
- help[this._registered] = data.value;
213
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (e) { }
214
- MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
215
- break;
216
- case 'cancelhelp':
217
- if (this._registered == null) return;
218
- sendConsoleText('Cancel Help (' + this._registered + ')');
219
- try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
220
- break;
221
- case 'register':
222
- if (typeof data.value == 'string') {
223
- this._registered = data.value;
224
- var apps = {};
225
- apps[data.value] = 1;
226
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
227
- this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
228
- }
229
- break;
230
- case 'query':
231
- switch (data.value) {
232
- case 'connection':
233
- data.result = require('MeshAgent').ConnectedServer;
234
- this._send(data);
235
- break;
236
- case 'descriptors':
237
- require('ChainViewer').getSnapshot().then(function (f) {
238
- this.tag.payload.result = f;
239
- this.tag.ipc._send(this.tag.payload);
240
- }).parentPromise.tag = { ipc: this, payload: data };
241
- break;
242
- case 'timerinfo':
243
- data.result = require('ChainViewer').getTimerInfo();
244
- this._send(data);
245
- break;
246
- }
247
- break;
248
- case 'amtstate':
249
- if (amt == null) return;
250
- var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
251
- func.pipe = this;
252
- amt.getMeiState(11, func);
253
- break;
254
- case 'sessions':
255
- this._send({ cmd: 'sessions', sessions: tunnelUserCount });
256
- break;
257
- case 'meshToolInfo':
258
- try { mesh.SendCommand({ action: 'meshToolInfo', name: data.name, hash: data.hash, cookie: data.cookie ? true : false, pipe: true }); } catch (e) { }
259
- break;
260
- case 'console':
261
- if (debugConsole) {
262
- var args = splitArgs(data.value);
263
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), 0, 'pipe');
264
- }
265
- break;
266
- }
182
+// Add an Intel AMT event to the log
183
+function addAmtEvent(msg)
184
+{
185
+ if (obj.amtevents == null) { obj.amtevents = []; }
186
+ var d = new Date();
187
+ obj.amtevents.push(zeroPad(d.getHours(), 2) + ':' + zeroPad(d.getMinutes(), 2) + ':' + zeroPad(d.getSeconds(), 2) + ', ' + msg);
188
+ if (obj.amtevents.length > 100) { obj.amtevents.splice(0, obj.amtevents.length - 100); }
189
+}
190
+function zeroPad(num, size) { var s = '000000000' + num; return s.substr(s.length - size); }
191
+
192
+
193
+// Create Secure IPC for Diagnostic Agent Communications
194
+obj.DAIPC = require('net').createServer();
195
+if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
196
+obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
197
+try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
198
+obj.DAIPC._daipc = [];
199
+obj.DAIPC.on('connection', function (c)
200
+{
201
+ c._send = function (j)
202
+ {
203
+ var data = JSON.stringify(j);
204
+ var packet = Buffer.alloc(data.length + 4);
205
+ packet.writeUInt32LE(data.length + 4, 0);
206
+ Buffer.from(data).copy(packet, 4);
207
+ this.write(packet);
208
+ };
209
+ this._daipc.push(c);
210
+ c.parent = this;
211
+ c.on('end', function () { removeRegisteredApp(this); });
212
+ c.on('data', function (chunk)
213
+ {
214
+ if (chunk.length < 4) { this.unshift(chunk); return; }
215
+ var len = chunk.readUInt32LE(0);
216
+ if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
217
+ if (chunk.length < len) { this.unshift(chunk); return; }
218
+
219
+ var data = chunk.slice(4, len);
220
+ try { data = JSON.parse(data.toString()); } catch (e) { }
221
+ if ((data == null) || (typeof data.cmd != 'string')) return;
222
+
223
+ try
224
+ {
225
+ switch (data.cmd)
226
+ {
227
+ case 'requesthelp':
228
+ if (this._registered == null) return;
229
+ sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
230
+ var help = {};
231
+ help[this._registered] = data.value;
232
+ try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (e) { }
233
+ MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
234
+ break;
235
+ case 'cancelhelp':
236
+ if (this._registered == null) return;
237
+ sendConsoleText('Cancel Help (' + this._registered + ')');
238
+ try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
239
+ break;
240
+ case 'register':
241
+ if (typeof data.value == 'string')
242
+ {
243
+ this._registered = data.value;
244
+ var apps = {};
245
+ apps[data.value] = 1;
246
+ try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
247
+ this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
248
+ }
249
+ break;
250
+ case 'query':
251
+ switch (data.value)
252
+ {
253
+ case 'connection':
254
+ data.result = require('MeshAgent').ConnectedServer;
255
+ this._send(data);
256
+ break;
257
+ case 'descriptors':
258
+ require('ChainViewer').getSnapshot().then(function (f)
259
+ {
260
+ this.tag.payload.result = f;
261
+ this.tag.ipc._send(this.tag.payload);
262
+ }).parentPromise.tag = { ipc: this, payload: data };
263
+ break;
264
+ case 'timerinfo':
265
+ data.result = require('ChainViewer').getTimerInfo();
266
+ this._send(data);
267
+ break;
268
+ }
269
+ break;
270
+ case 'amtstate':
271
+ if (amt == null) return;
272
+ var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
273
+ func.pipe = this;
274
+ amt.getMeiState(11, func);
275
+ break;
276
+ case 'sessions':
277
+ this._send({ cmd: 'sessions', sessions: tunnelUserCount });
278
+ break;
279
+ case 'meshToolInfo':
280
+ try { mesh.SendCommand({ action: 'meshToolInfo', name: data.name, hash: data.hash, cookie: data.cookie ? true : false, pipe: true }); } catch (e) { }
281
+ break;
282
+ case 'console':
283
+ if (debugConsole)
284
+ {
285
+ var args = splitArgs(data.value);
286
+ processConsoleCommand(args[0].toLowerCase(), parseArgs(args), 0, 'pipe');
287
+ }
288
+ break;
289
}
268
- catch (e) { removeRegisteredApp(this); this.end(); return; }
269
- });
290
+ }
291
+ catch (e) { removeRegisteredApp(this); this.end(); return; }
292
});
293
+});
294
272
- // Send current sessions to registered apps
273
- function broadcastSessionsToRegisteredApps(x) {
274
- broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
275
- }
295
+// Send current sessions to registered apps
296
+function broadcastSessionsToRegisteredApps(x)
297
+{
298
+ broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
299
+}
300
277
- // Send this object to all registered local applications
278
- function broadcastToRegisteredApps(x) {
279
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
280
- for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); } }
281
- }
301
+// Send this object to all registered local applications
302
+function broadcastToRegisteredApps(x)
303
+{
304
+ if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
305
+ for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); } }
306
+}
307
283
- // Send this object to a specific registered local applications
284
- function sendToRegisteredApp(appid, x) {
285
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
286
- for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered == appid) { obj.DAIPC._daipc[i]._send(x); } }
287
- }
308
+// Send this object to a specific registered local applications
309
+function sendToRegisteredApp(appid, x)
310
+{
311
+ if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
312
+ for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered == appid) { obj.DAIPC._daipc[i]._send(x); } }
313
+}
314
289
- // Send list of registered apps to the server
290
- function updateRegisteredAppsToServer() {
291
- if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
292
- var apps = {};
293
- 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]++; } }
294
- try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
295
- }
315
+// Send list of registered apps to the server
316
+function updateRegisteredAppsToServer()
317
+{
318
+ if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
319
+ var apps = {};
320
+ 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]++; } }
321
+ try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
322
+}
323
+
324
+// Remove a registered app
325
+function removeRegisteredApp(pipe)
326
+{
327
+ for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
328
+ if (pipe._registered != null) updateRegisteredAppsToServer();
329
+}
330
297
- // Remove a registered app
298
- function removeRegisteredApp(pipe) {
299
- for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
300
- if (pipe._registered != null) updateRegisteredAppsToServer();
331
+function diagnosticAgent_uninstall()
332
+{
333
+ require('service-manager').manager.uninstallService('meshagentDiagnostic');
334
+ require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
335
+}
336
+function diagnosticAgent_installCheck(install)
337
+{
338
+ try
339
+ {
340
+ var diag = require('service-manager').manager.getService('meshagentDiagnostic');
341
+ return (diag);
342
+ }
343
+ catch (e)
344
+ {
345
}
346
+ if (!install) { return (null); }
347
303
- function diagnosticAgent_uninstall() {
304
- require('service-manager').manager.uninstallService('meshagentDiagnostic');
305
- require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
306
- };
307
- function diagnosticAgent_installCheck(install) {
308
- try {
309
- var diag = require('service-manager').manager.getService('meshagentDiagnostic');
310
- return (diag);
311
- }
312
- catch (e) {
313
- }
314
- if (!install) { return (null); }
315
-
316
- var svc = null;
317
- try {
318
- require('service-manager').manager.installService(
319
- {
320
- name: 'meshagentDiagnostic',
321
- displayName: "Mesh Agent Diagnostic Service",
322
- description: "Mesh Agent Diagnostic Service",
323
- servicePath: process.execPath,
324
- parameters: ['-recovery']
325
- //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
326
- });
327
- svc = require('service-manager').manager.getService('meshagentDiagnostic');
328
- }
329
- catch (e) {
330
- return (null);
331
- }
332
- var proxyConfig = require('global-tunnel').proxyConfig;
333
- var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
334
- var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
335
- ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
336
- ddb.Put('disableUpdate', '1');
337
- ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
338
- ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
339
- ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
340
- if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
341
- if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
342
- if (proxyConfig) {
343
- ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
344
- } else {
345
- ddb.Put('ignoreProxyFile', '1');
346
- }
348
+ var svc = null;
349
+ try
350
+ {
351
+ require('service-manager').manager.installService(
352
+ {
353
+ name: 'meshagentDiagnostic',
354
+ displayName: "Mesh Agent Diagnostic Service",
355
+ description: "Mesh Agent Diagnostic Service",
356
+ servicePath: process.execPath,
357
+ parameters: ['-recovery']
358
+ //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
359
+ });
360
+ svc = require('service-manager').manager.getService('meshagentDiagnostic');
361
+ }
362
+ catch (e)
363
+ {
364
+ return (null);
365
+ }
366
+ var proxyConfig = require('global-tunnel').proxyConfig;
367
+ var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
368
+ var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
369
+ ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
370
+ ddb.Put('disableUpdate', '1');
371
+ ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
372
+ ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
373
+ ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
374
+ if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
375
+ if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
376
+ if (proxyConfig)
377
+ {
378
+ ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
379
+ }
380
+ else
381
+ {
382
+ ddb.Put('ignoreProxyFile', '1');
383
+ }
384
348
- require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
349
- require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
385
+ require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
386
+ require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
387
351
- delete ddb;
388
+ delete ddb;
389
353
- // Set a recurrent task, to run the Diagnostic Agent every 2 days
354
- 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' });
355
- //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
390
+ // Set a recurrent task, to run the Diagnostic Agent every 2 days
391
+ 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' });
392
+ //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
393
357
- return (svc);
358
- }
394
+ return (svc);
395
+}
396
360
- // Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
361
- if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
362
- // Setup manual battery monitoring
363
- require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
364
- if (require('MeshAgent')._batteryFileTimer != null) return;
365
- require('MeshAgent')._batteryFileTimer = setTimeout(function () {
366
- try {
367
- require('MeshAgent')._batteryFileTimer = null;
368
- var data = null;
369
- try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
370
- if ((data != null) && (data.length < 10)) {
371
- data = data.split(',');
372
- if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
373
- var level = parseInt(data[1]);
374
- if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
375
- }
397
+// Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
398
+if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null))
399
+{
400
+ // Setup manual battery monitoring
401
+ require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function ()
402
+ {
403
+ if (require('MeshAgent')._batteryFileTimer != null) return;
404
+ require('MeshAgent')._batteryFileTimer = setTimeout(function ()
405
+ {
406
+ try
407
+ {
408
+ require('MeshAgent')._batteryFileTimer = null;
409
+ var data = null;
410
+ try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
411
+ if ((data != null) && (data.length < 10))
412
+ {
413
+ data = data.split(',');
414
+ if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc')))
415
+ {
416
+ var level = parseInt(data[1]);
417
+ if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
418
}
377
- } catch (e) { }
378
- }, 1000);
379
- });
380
- } else {
381
- // Setup normal battery monitoring
382
- if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) {
383
- require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
384
- _battLevelChanged.self._currentBatteryLevel = val;
385
- _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
386
- };
387
- require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
388
- require('MeshAgent')._powerChanged = function _powerChanged(val) {
389
- _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
390
- _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
391
- };
392
- require('MeshAgent')._powerChanged.self = require('MeshAgent');
393
- require('MeshAgent').on('Connected', function (status) {
394
- if (status == 0) {
395
- require('power-monitor').removeListener('acdc', this._powerChanged);
396
- require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
397
- } else {
398
- require('power-monitor').on('acdc', this._powerChanged);
399
- require('power-monitor').on('batteryLevel', this._battLevelChanged);
419
}
401
- });
402
- }
420
+ } catch (e) { }
421
+ }, 1000);
422
+ });
423
+}
424
+else
425
+{
426
+ // Setup normal battery monitoring
427
+ if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered())
428
+ {
429
+ require('MeshAgent')._battLevelChanged = function _battLevelChanged(val)
430
+ {
431
+ _battLevelChanged.self._currentBatteryLevel = val;
432
+ _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
433
+ };
434
+ require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
435
+ require('MeshAgent')._powerChanged = function _powerChanged(val)
436
+ {
437
+ _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
438
+ _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
439
+ };
440
+ require('MeshAgent')._powerChanged.self = require('MeshAgent');
441
+ require('MeshAgent').on('Connected', function (status)
442
+ {
443
+ if (status == 0)
444
+ {
445
+ require('power-monitor').removeListener('acdc', this._powerChanged);
446
+ require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
447
+ } else
448
+ {
449
+ require('power-monitor').on('acdc', this._powerChanged);
450
+ require('power-monitor').on('batteryLevel', this._battLevelChanged);
451
+ }
452
+ });
453
}
454
+}
455
456
406
- /*
407
- function borderController() {
408
- this.container = null;
409
- this.Start = function Start(user) {
410
- if (this.container == null) {
411
- if (process.platform == 'win32') {
412
- try {
413
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.SessionId });
414
- } catch (e) {
415
- this.container = require('ScriptContainer').Create({ processIsolation: 1 });
416
- }
417
- } else {
418
- this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.uid });
457
+// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
458
+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
459
+
460
+// Get the operating system description string
461
+try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (e) { }
462
+
463
+
464
+// Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
465
+try
466
+{
467
+ var userSession = require('user-sessions');
468
+ userSession.on('changed', function onUserSessionChanged()
469
+ {
470
+ userSession.enumerateUsers().then(function (users)
471
+ {
472
+ if (process.platform == 'linux')
473
+ {
474
+ if (userSession._startTime == null)
475
+ {
476
+ userSession._startTime = Date.now();
477
+ userSession._count = users.length;
478
+ }
479
+ else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count)
480
+ {
481
+ userSession.removeAllListeners('changed');
482
+ return;
483
}
420
- this.container.parent = this;
421
- this.container.addModule('monitor-info', getJSModule('monitor-info'));
422
- this.container.addModule('monitor-border', getJSModule('monitor-border'));
423
- this.container.addModule('promise', getJSModule('promise'));
424
- this.container.once('exit', function (code) { sendConsoleText('Border Process Exited with code: ' + code); this.parent.container = this.parent._container = null; });
425
- this.container.ExecuteString("var border = require('monitor-border'); border.Start();");
426
- }
427
- }
428
- this.Stop = function Stop() {
429
- if (this.container != null) {
430
- this._container = this.container;
431
- this._container.parent = this;
432
- this.container = null;
433
- this._container.exit();
484
}
435
- }
436
- }
437
- obj.borderManager = new borderController();
438
- */
485
440
- // MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
441
- 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
442
-
443
- // Get the operating system description string
444
- try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (e) { }
445
-
446
- // Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
447
- try {
448
- var userSession = require('user-sessions');
449
- userSession.on('changed', function onUserSessionChanged() {
450
- userSession.enumerateUsers().then(function (users) {
451
- var u = [], a = users.Active;
452
- for (var i = 0; i < a.length; i++) {
453
- var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
454
- if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
455
- }
456
- meshCoreObj.users = u;
457
- meshCoreObjChanged();
458
- });
486
+ var u = [], a = users.Active;
487
+ for (var i = 0; i < a.length; i++)
488
+ {
489
+ var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
490
+ if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
491
+ }
492
+ meshCoreObj.users = u;
493
+ meshCoreObjChanged();
494
});
460
- userSession.emit('changed');
461
- //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
462
- //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
463
- } catch (e) { }
495
+ });
496
+ userSession.emit('changed');
497
+ //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
498
+ //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
499
+} catch (e) { }
500
+
501
+var meshServerConnectionState = 0;
502
+var tunnels = {};
503
+var lastNetworkInfo = null;
504
+var lastPublicLocationInfo = null;
505
+var selfInfoUpdateTimer = null;
506
+var http = require('http');
507
+var net = require('net');
508
+var fs = require('fs');
509
+var rtc = require('ILibWebRTC');
510
+var amt = null;
511
+var processManager = require('process-manager');
512
+var wifiScannerLib = null;
513
+var wifiScanner = null;
514
+var networkMonitor = null;
515
+var nextTunnelIndex = 1;
516
+var apftunnel = null;
517
+var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
518
+
519
+// Add to the server event log
520
+function MeshServerLog(msg, state)
521
+{
522
+ if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
523
+ if (state)
524
+ {
525
+ if (state.userid) { msg.userid = state.userid; }
526
+ if (state.username) { msg.username = state.username; }
527
+ if (state.sessionid) { msg.sessionid = state.sessionid; }
528
+ if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
529
+ }
530
+ mesh.SendCommand(msg);
531
+}
532
465
- var meshServerConnectionState = 0;
466
- var tunnels = {};
467
- var lastNetworkInfo = null;
468
- var lastPublicLocationInfo = null;
469
- var selfInfoUpdateTimer = null;
470
- var http = require('http');
471
- var net = require('net');
472
- var fs = require('fs');
473
- var rtc = require('ILibWebRTC');
474
- var amt = null;
475
- var processManager = require('process-manager');
476
- var wifiScannerLib = null;
477
- var wifiScanner = null;
478
- var networkMonitor = null;
479
- var nextTunnelIndex = 1;
480
- var apftunnel = null;
481
- var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
482
-
483
- // Add to the server event log
484
- function MeshServerLog(msg, state) {
485
- if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
486
- if (state) {
487
- if (state.userid) { msg.userid = state.userid; }
488
- if (state.username) { msg.username = state.username; }
489
- if (state.sessionid) { msg.sessionid = state.sessionid; }
490
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
491
- }
492
- mesh.SendCommand(msg);
533
+// Add to the server event log, use internationalized events
534
+function MeshServerLogEx(id, args, msg, state)
535
+{
536
+ var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
537
+ if (state)
538
+ {
539
+ if (state.userid) { msg.userid = state.userid; }
540
+ if (state.username) { msg.username = state.username; }
541
+ if (state.sessionid) { msg.sessionid = state.sessionid; }
542
+ if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
543
}
544
+ mesh.SendCommand(msg);
545
+}
546
495
- // Add to the server event log, use internationalized events
496
- function MeshServerLogEx(id, args, msg, state) {
497
- var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
498
- if (state) {
499
- if (state.userid) { msg.userid = state.userid; }
500
- if (state.username) { msg.username = state.username; }
501
- if (state.sessionid) { msg.sessionid = state.sessionid; }
502
- if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
547
+// Import libraries
548
+db = require('SimpleDataStore').Shared();
549
+sha = require('SHA256Stream');
550
+mesh = require('MeshAgent');
551
+childProcess = require('child_process');
552
+
553
+if (mesh.hasKVM == 1)
554
+{ // if the agent is compiled with KVM support
555
+ // Check if this computer supports a desktop
556
+ try
557
+ {
558
+ if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support))
559
+ {
560
+ meshCoreObj.caps |= 1; meshCoreObjChanged();
561
+ } else if (process.platform == 'linux' || process.platform == 'freebsd')
562
+ {
563
+ require('monitor-info').on('kvmSupportDetected', function (value) { meshCoreObj.caps |= 1; meshCoreObjChanged(); });
564
}
504
- mesh.SendCommand(msg);
505
- }
565
+ } catch (e) { }
566
+}
567
+mesh.DAIPC = obj.DAIPC;
568
507
- // Import libraries
508
- db = require('SimpleDataStore').Shared();
509
- sha = require('SHA256Stream');
510
- mesh = require('MeshAgent');
511
- childProcess = require('child_process');
512
- if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
513
- // Check if this computer supports a desktop
514
- try {
515
- if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) {
516
- meshCoreObj.caps |= 1; meshCoreObjChanged();
517
- } else if (process.platform == 'linux' || process.platform == 'freebsd') {
518
- require('monitor-info').on('kvmSupportDetected', function (value) { meshCoreObj.caps |= 1; meshCoreObjChanged(); });
519
- }
520
- } catch (e) { }
521
- }
522
- mesh.DAIPC = obj.DAIPC;
569
+/*
570
+// Try to load up the network monitor
571
+try {
572
+ networkMonitor = require('NetworkMonitor');
573
+ networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
574
+ networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
575
+ networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
576
+} catch (e) { networkMonitor = null; }
577
+*/
578
524
- /*
525
- // Try to load up the network monitor
526
- try {
527
- networkMonitor = require('NetworkMonitor');
528
- networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
529
- networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
530
- networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
531
- } catch (e) { networkMonitor = null; }
532
- */
579
+// Fetch the SMBios Tables
580
+var SMBiosTables = null;
581
+var SMBiosTablesRaw = null;
582
+try
583
+{
584
+ var SMBiosModule = null;
585
+ try { SMBiosModule = require('smbios'); } catch (e) { }
586
+ if (SMBiosModule != null)
587
+ {
588
+ SMBiosModule.get(function (data)
589
+ {
590
+ if (data != null)
591
+ {
592
+ SMBiosTablesRaw = data;
593
+ SMBiosTables = require('smbios').parse(data)
594
+ if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
595
534
- // Fetch the SMBios Tables
535
- var SMBiosTables = null;
536
- var SMBiosTablesRaw = null;
537
- try {
538
- var SMBiosModule = null;
539
- try { SMBiosModule = require('smbios'); } catch (e) { }
540
- if (SMBiosModule != null) {
541
- SMBiosModule.get(function (data) {
542
- if (data != null) {
543
- SMBiosTablesRaw = data;
544
- SMBiosTables = require('smbios').parse(data)
545
- if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
546
-
547
- // If SMBios tables say that Intel AMT is present, try to connect MEI
548
- if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true)) {
549
- var amtmodule = require('amt-manage');
550
- amt = new amtmodule(mesh, db, false);
551
- amt.on('portBinding_LMS', function (map) { mesh.SendCommand({ action: 'lmsinfo', value: { ports: map.keys() } }); });
552
- amt.on('stateChange_LMS', function (v) { if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; } meshCoreObj.intelamt.microlms = v; meshCoreObjChanged(); }); // 0 = Disabled, 1 = Connecting, 2 = Connected
553
- amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } } // MEI State
554
- amt.reset();
555
- }
596
+ // If SMBios tables say that Intel AMT is present, try to connect MEI
597
+ if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true))
598
+ {
599
+ var amtmodule = require('amt-manage');
600
+ amt = new amtmodule(mesh, db, false);
601
+ amt.on('portBinding_LMS', function (map) { mesh.SendCommand({ action: 'lmsinfo', value: { ports: map.keys() } }); });
602
+ amt.on('stateChange_LMS', function (v) { if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; } meshCoreObj.intelamt.microlms = v; meshCoreObjChanged(); }); // 0 = Disabled, 1 = Connecting, 2 = Connected
603
+ amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } } // MEI State
604
+ amt.reset();
605
}
557
- });
558
- }
559
- } catch (e) { sendConsoleText("ex1: " + e); }
560
-
561
- // Try to load up the WIFI scanner
562
- try {
563
- var wifiScannerLib = require('wifi-scanner');
564
- wifiScanner = new wifiScannerLib();
565
- wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
566
- } catch (e) { wifiScannerLib = null; wifiScanner = null; }
567
-
568
- // Get our location (lat/long) using our public IP address
569
- var getIpLocationDataExInProgress = false;
570
- var getIpLocationDataExCounts = [0, 0];
571
- function getIpLocationDataEx(func) {
572
- if (getIpLocationDataExInProgress == true) { return false; }
573
- try {
574
- getIpLocationDataExInProgress = true;
575
- getIpLocationDataExCounts[0]++;
576
- var options = http.parseUri("http://ipinfo.io/json");
577
- options.method = 'GET';
578
- http.request(options, function (resp) {
579
- if (resp.statusCode == 200) {
580
- var geoData = '';
581
- resp.data = function (geoipdata) { geoData += geoipdata; };
582
- resp.end = function () {
583
- var location = null;
584
- try {
585
- if (typeof geoData == 'string') {
586
- var result = JSON.parse(geoData);
587
- if (result.ip && result.loc) { location = result; }
588
- }
589
- } catch (e) { }
590
- if (func) { getIpLocationDataExCounts[1]++; func(location); }
591
- }
592
- } else
593
- { func(null); }
594
- getIpLocationDataExInProgress = false;
595
- }).end();
596
- return true;
597
- }
598
- catch (e) { return false; }
606
+ }
607
+ });
608
}
600
-
601
- // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
602
- function clearGatewayMac(str) {
603
- if (str == null) return null;
604
- var x = JSON.parse(str);
605
- for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
606
- return JSON.stringify(x);
609
+} catch (e) { sendConsoleText("ex1: " + e); }
610
+
611
+// Try to load up the WIFI scanner
612
+try
613
+{
614
+ var wifiScannerLib = require('wifi-scanner');
615
+ wifiScanner = new wifiScannerLib();
616
+ wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
617
+} catch (e) { wifiScannerLib = null; wifiScanner = null; }
618
+
619
+// Get our location (lat/long) using our public IP address
620
+var getIpLocationDataExInProgress = false;
621
+var getIpLocationDataExCounts = [0, 0];
622
+function getIpLocationDataEx(func)
623
+{
624
+ if (getIpLocationDataExInProgress == true) { return false; }
625
+ try
626
+ {
627
+ getIpLocationDataExInProgress = true;
628
+ getIpLocationDataExCounts[0]++;
629
+ var options = http.parseUri("http://ipinfo.io/json");
630
+ options.method = 'GET';
631
+ http.request(options, function (resp)
632
+ {
633
+ if (resp.statusCode == 200)
634
+ {
635
+ var geoData = '';
636
+ resp.data = function (geoipdata) { geoData += geoipdata; };
637
+ resp.end = function ()
638
+ {
639
+ var location = null;
640
+ try
641
+ {
642
+ if (typeof geoData == 'string')
643
+ {
644
+ var result = JSON.parse(geoData);
645
+ if (result.ip && result.loc) { location = result; }
646
+ }
647
+ } catch (e) { }
648
+ if (func) { getIpLocationDataExCounts[1]++; func(location); }
649
+ }
650
+ } else
651
+ { func(null); }
652
+ getIpLocationDataExInProgress = false;
653
+ }).end();
654
+ return true;
655
}
656
+ catch (e) { return false; }
657
+}
658
609
- function getIpLocationData(func) {
610
- // Get the location information for the cache if possible
611
- var publicLocationInfo = db.Get('publicLocationInfo');
612
- if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
613
- if (publicLocationInfo == null) {
614
- // Nothing in the cache, fetch the data
615
- getIpLocationDataEx(function (locationData) {
616
- if (locationData != null) {
659
+// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
660
+function clearGatewayMac(str)
661
+{
662
+ if (str == null) return null;
663
+ var x = JSON.parse(str);
664
+ for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
665
+ return JSON.stringify(x);
666
+}
667
+
668
+function getIpLocationData(func)
669
+{
670
+ // Get the location information for the cache if possible
671
+ var publicLocationInfo = db.Get('publicLocationInfo');
672
+ if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
673
+ if (publicLocationInfo == null)
674
+ {
675
+ // Nothing in the cache, fetch the data
676
+ getIpLocationDataEx(function (locationData)
677
+ {
678
+ if (locationData != null)
679
+ {
680
+ publicLocationInfo = {};
681
+ publicLocationInfo.netInfoStr = lastNetworkInfo;
682
+ publicLocationInfo.locationData = locationData;
683
+ var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
684
+ if (func) func(locationData); // Report the new location
685
+ }
686
+ else
687
+ {
688
+ if (func) func(null); // Report no location
689
+ }
690
+ });
691
+ }
692
+ else
693
+ {
694
+ // Check the cache
695
+ if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo))
696
+ {
697
+ // Cache match
698
+ if (func) func(publicLocationInfo.locationData);
699
+ }
700
+ else
701
+ {
702
+ // Cache mismatch
703
+ getIpLocationDataEx(function (locationData)
704
+ {
705
+ if (locationData != null)
706
+ {
707
publicLocationInfo = {};
708
publicLocationInfo.netInfoStr = lastNetworkInfo;
709
publicLocationInfo.locationData = locationData;
710
var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
711
if (func) func(locationData); // Report the new location
622
- } else {
623
- if (func) func(null); // Report no location
712
+ }
713
+ else
714
+ {
715
+ if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
716
}
717
});
626
- } else {
627
- // Check the cache
628
- if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
629
- // Cache match
630
- if (func) func(publicLocationInfo.locationData);
631
- } else {
632
- // Cache mismatch
633
- getIpLocationDataEx(function (locationData) {
634
- if (locationData != null) {
635
- publicLocationInfo = {};
636
- publicLocationInfo.netInfoStr = lastNetworkInfo;
637
- publicLocationInfo.locationData = locationData;
638
- var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
639
- if (func) func(locationData); // Report the new location
640
- } else {
641
- if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
642
- }
643
- });
644
- }
718
}
719
}
720
+}
721
648
- // Polyfill String.endsWith
649
- if (!String.prototype.endsWith) {
650
- String.prototype.endsWith = function (searchString, position) {
651
- var subjectString = this.toString();
652
- if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
653
- position -= searchString.length;
654
- var lastIndex = subjectString.lastIndexOf(searchString, position);
655
- return lastIndex !== -1 && lastIndex === position;
656
- };
657
- }
722
+// Polyfill String.endsWith
723
+if (!String.prototype.endsWith)
724
+{
725
+ String.prototype.endsWith = function (searchString, position)
726
+ {
727
+ var subjectString = this.toString();
728
+ if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
729
+ position -= searchString.length;
730
+ var lastIndex = subjectString.lastIndexOf(searchString, position);
731
+ return lastIndex !== -1 && lastIndex === position;
732
+ };
733
+}
734
659
- // Polyfill path.join
660
- obj.path = {
661
- join: function () {
735
+// Polyfill path.join
736
+obj.path =
737
+ {
738
+ join: function ()
739
+ {
740
var x = [];
663
- for (var i in arguments) {
741
+ for (var i in arguments)
742
+ {
743
var w = arguments[i];
665
- if (w != null) {
744
+ if (w != null)
745
+ {
746
while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
667
- if (i != 0) {
747
+ if (i != 0)
748
+ {
749
while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
750
}
751
x.push(w);
@@ -675,1198 +756,1385 @@ function createMeshCore(agent) {
756
}
757
};
758
678
- // Replace a string with a number if the string is an exact number
679
- function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
759
+// Replace a string with a number if the string is an exact number
760
+function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
761
681
- // Convert decimal to hex
682
- function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
762
+// Convert decimal to hex
763
+function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
764
684
- // Convert a raw string to a hex string
685
- function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
765
+// Convert a raw string to a hex string
766
+function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
767
687
- // Convert a buffer into a string
688
- function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
768
+// Convert a buffer into a string
769
+function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
770
690
- // Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
691
- function hex2rstr(d) {
692
- if (typeof d != "string" || d.length == 0) return '';
693
- var r = '', m = ('' + d).match(/../g), t;
694
- while (t = m.shift()) r += String.fromCharCode('0x' + t);
695
- return r
696
- }
771
+// Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
772
+function hex2rstr(d)
773
+{
774
+ if (typeof d != "string" || d.length == 0) return '';
775
+ var r = '', m = ('' + d).match(/../g), t;
776
+ while (t = m.shift()) r += String.fromCharCode('0x' + t);
777
+ return r
778
+}
779
698
- // Convert an object to string with all functions
699
- function objToString(x, p, pad, ret) {
700
- if (ret == undefined) ret = '';
701
- if (p == undefined) p = 0;
702
- if (x == null) { return '[null]'; }
703
- if (p > 8) { return '[...]'; }
704
- if (x == undefined) { return '[undefined]'; }
705
- if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; }
706
- if (typeof x == 'buffer') { return '[buffer]'; }
707
- if (typeof x != 'object') { return x; }
708
- var r = '{' + (ret ? '\r\n' : ' ');
709
- for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
710
- return r + addPad(p, pad) + '}';
711
- }
780
+// Convert an object to string with all functions
781
+function objToString(x, p, pad, ret)
782
+{
783
+ if (ret == undefined) ret = '';
784
+ if (p == undefined) p = 0;
785
+ if (x == null) { return '[null]'; }
786
+ if (p > 8) { return '[...]'; }
787
+ if (x == undefined) { return '[undefined]'; }
788
+ if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; }
789
+ if (typeof x == 'buffer') { return '[buffer]'; }
790
+ if (typeof x != 'object') { return x; }
791
+ var r = '{' + (ret ? '\r\n' : ' ');
792
+ for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
793
+ return r + addPad(p, pad) + '}';
794
+}
795
713
- // Return p number of spaces
714
- function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
796
+// Return p number of spaces
797
+function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
798
716
- // Split a string taking into account the quoats. Used for command line parsing
717
- function splitArgs(str) {
718
- var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
719
- do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
720
- return myArray;
721
- }
799
+// Split a string taking into account the quoats. Used for command line parsing
800
+function splitArgs(str)
801
+{
802
+ var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
803
+ do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
804
+ return myArray;
805
+}
806
723
- // Parse arguments string array into an object
724
- function parseArgs(argv) {
725
- var results = { '_': [] }, current = null;
726
- for (var i = 1, len = argv.length; i < len; i++) {
727
- var x = argv[i];
728
- if (x.length > 2 && x[0] == '-' && x[1] == '-') {
729
- if (current != null) { results[current] = true; }
730
- current = x.substring(2);
731
- } else {
732
- if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
733
- }
807
+// Parse arguments string array into an object
808
+function parseArgs(argv)
809
+{
810
+ var results = { '_': [] }, current = null;
811
+ for (var i = 1, len = argv.length; i < len; i++)
812
+ {
813
+ var x = argv[i];
814
+ if (x.length > 2 && x[0] == '-' && x[1] == '-')
815
+ {
816
+ if (current != null) { results[current] = true; }
817
+ current = x.substring(2);
818
+ } else
819
+ {
820
+ if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
821
}
735
- if (current != null) { results[current] = true; }
736
- return results;
822
}
823
+ if (current != null) { results[current] = true; }
824
+ return results;
825
+}
826
739
- // Get server target url with a custom path
740
- function getServerTargetUrl(path) {
741
- var x = mesh.ServerUrl;
742
- //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
743
- if (x == null) { return null; }
744
- if (path == null) { path = ''; }
745
- x = http.parseUri(x);
746
- if (x == null) return null;
747
- return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
748
- }
827
+// Get server target url with a custom path
828
+function getServerTargetUrl(path)
829
+{
830
+ var x = mesh.ServerUrl;
831
+ //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
832
+ if (x == null) { return null; }
833
+ if (path == null) { path = ''; }
834
+ x = http.parseUri(x);
835
+ if (x == null) return null;
836
+ return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
837
+}
838
750
- // Get server url. If the url starts with "*/..." change it, it not use the url as is.
751
- function getServerTargetUrlEx(url) {
752
- if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
753
- return url;
754
- }
839
+// Get server url. If the url starts with "*/..." change it, it not use the url as is.
840
+function getServerTargetUrlEx(url)
841
+{
842
+ if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
843
+ return url;
844
+}
845
756
- // Send a wake-on-lan packet
757
- function sendWakeOnLan(hexMac) {
758
- hexMac = hexMac.split(':').join('');
759
- var count = 0;
760
- try {
761
- var interfaces = require('os').networkInterfaces();
762
- var magic = 'FFFFFFFFFFFF';
763
- for (var x = 1; x <= 16; ++x) { magic += hexMac; }
764
- var magicbin = Buffer.from(magic, 'hex');
765
-
766
- for (var adapter in interfaces) {
767
- if (interfaces.hasOwnProperty(adapter)) {
768
- for (var i = 0; i < interfaces[adapter].length; ++i) {
769
- var addr = interfaces[adapter][i];
770
- if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
771
- try {
772
- var socket = require('dgram').createSocket({ type: 'udp4' });
773
- socket.bind({ address: addr.address });
774
- socket.setBroadcast(true);
775
- socket.setMulticastInterface(addr.address);
776
- socket.setMulticastTTL(1);
777
- socket.send(magicbin, 7, '255.255.255.255');
778
- socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')';
779
- count++;
780
- }
781
- catch (e) { }
846
+// Send a wake-on-lan packet
847
+function sendWakeOnLan(hexMac)
848
+{
849
+ hexMac = hexMac.split(':').join('');
850
+ var count = 0;
851
+ try
852
+ {
853
+ var interfaces = require('os').networkInterfaces();
854
+ var magic = 'FFFFFFFFFFFF';
855
+ for (var x = 1; x <= 16; ++x) { magic += hexMac; }
856
+ var magicbin = Buffer.from(magic, 'hex');
857
+
858
+ for (var adapter in interfaces)
859
+ {
860
+ if (interfaces.hasOwnProperty(adapter))
861
+ {
862
+ for (var i = 0; i < interfaces[adapter].length; ++i)
863
+ {
864
+ var addr = interfaces[adapter][i];
865
+ if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00'))
866
+ {
867
+ try
868
+ {
869
+ var socket = require('dgram').createSocket({ type: 'udp4' });
870
+ socket.bind({ address: addr.address });
871
+ socket.setBroadcast(true);
872
+ socket.setMulticastInterface(addr.address);
873
+ socket.setMulticastTTL(1);
874
+ socket.send(magicbin, 7, '255.255.255.255');
875
+ socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')';
876
+ count++;
877
}
878
+ catch (e) { }
879
}
880
}
881
}
786
- } catch (e) { }
787
- return count;
788
- }
882
+ }
883
+ } catch (e) { }
884
+ return count;
885
+}
886
790
- // Handle a mesh agent command
791
- function handleServerCommand(data) {
792
- if (typeof data == 'object') {
793
- // If this is a console command, parse it and call the console handler
794
- switch (data.action) {
795
- case 'agentupdate':
796
- agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
797
- break;
798
- case 'msg': {
799
- switch (data.type) {
800
- case 'console': { // Process a console command
801
- if (data.value && data.sessionid) {
802
- MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
803
- var args = splitArgs(data.value);
804
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
805
- }
806
- break;
887
+// Handle a mesh agent command
888
+function handleServerCommand(data)
889
+{
890
+ if (typeof data == 'object')
891
+ {
892
+ // If this is a console command, parse it and call the console handler
893
+ switch (data.action)
894
+ {
895
+ case 'agentupdate':
896
+ agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
897
+ break;
898
+ case 'msg': {
899
+ switch (data.type)
900
+ {
901
+ case 'console': { // Process a console command
902
+ if (data.value && data.sessionid)
903
+ {
904
+ MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
905
+ var args = splitArgs(data.value);
906
+ processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
907
}
808
- case 'tunnel': {
809
- if (data.value != null) { // Process a new tunnel connection request
810
- // Create a new tunnel object
811
- var xurl = getServerTargetUrlEx(data.value);
812
- if (xurl != null) {
813
- xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
814
- var woptions = http.parseUri(xurl);
815
- woptions.perMessageDeflate = false;
816
- if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
817
-
818
- // Perform manual server TLS certificate checking based on the certificate hash given by the server.
819
- woptions.rejectUnauthorized = 0;
820
- woptions.checkServerIdentity = function checkServerIdentity(certs) {
821
- // If the tunnel certificate matches the control channel certificate, accept the connection
822
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
823
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
824
- // Check that the certificate is the one expected by the server, fail if not.
825
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
826
- }
827
- woptions.checkServerIdentity.servertlshash = data.servertlshash;
828
-
829
- //sendConsoleText(JSON.stringify(woptions));
830
- //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
831
- var tunnel = http.request(woptions);
832
- tunnel.upgrade = onTunnelUpgrade;
833
- tunnel.on('error', function (e) { sendConsoleText("ERROR: Unable to connect relay tunnel to: " + this.url + ", " + JSON.stringify(e)); });
834
- tunnel.sessionid = data.sessionid;
835
- tunnel.rights = data.rights;
836
- tunnel.consent = data.consent;
837
- tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}";
838
- tunnel.username = data.username + (data.guestname ? (' - ' + data.guestname) : '');
839
- tunnel.realname = (data.realname ? data.realname : data.username) + (data.guestname ? (' - ' + data.guestname) : '');
840
- tunnel.userid = data.userid;
841
- tunnel.remoteaddr = data.remoteaddr;
842
- tunnel.state = 0;
843
- tunnel.url = xurl;
844
- tunnel.protocol = 0;
845
- tunnel.soptions = data.soptions;
846
- tunnel.tcpaddr = data.tcpaddr;
847
- tunnel.tcpport = data.tcpport;
848
- tunnel.udpaddr = data.udpaddr;
849
- tunnel.udpport = data.udpport;
850
- tunnel.end();
851
- // Put the tunnel in the tunnels list
852
- var index = nextTunnelIndex++;
853
- tunnel.index = index;
854
- tunnels[index] = tunnel;
855
-
856
- //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
908
+ break;
909
+ }
910
+ case 'tunnel': {
911
+ if (data.value != null)
912
+ { // Process a new tunnel connection request
913
+ // Create a new tunnel object
914
+ var xurl = getServerTargetUrlEx(data.value);
915
+ if (xurl != null)
916
+ {
917
+ xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
918
+ var woptions = http.parseUri(xurl);
919
+ woptions.perMessageDeflate = false;
920
+ if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
921
+
922
+ // Perform manual server TLS certificate checking based on the certificate hash given by the server.
923
+ woptions.rejectUnauthorized = 0;
924
+ woptions.checkServerIdentity = function checkServerIdentity(certs)
925
+ {
926
+ // If the tunnel certificate matches the control channel certificate, accept the connection
927
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
928
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
929
+ // Check that the certificate is the one expected by the server, fail if not.
930
+ if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
931
}
932
+ woptions.checkServerIdentity.servertlshash = data.servertlshash;
933
+
934
+ //sendConsoleText(JSON.stringify(woptions));
935
+ //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
936
+ var tunnel = http.request(woptions);
937
+ tunnel.upgrade = onTunnelUpgrade;
938
+ tunnel.on('error', function (e) { sendConsoleText("ERROR: Unable to connect relay tunnel to: " + this.url + ", " + JSON.stringify(e)); });
939
+ tunnel.sessionid = data.sessionid;
940
+ tunnel.rights = data.rights;
941
+ tunnel.consent = data.consent;
942
+ tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}";
943
+ tunnel.username = data.username + (data.guestname ? (' - ' + data.guestname) : '');
944
+ tunnel.realname = (data.realname ? data.realname : data.username) + (data.guestname ? (' - ' + data.guestname) : '');
945
+ tunnel.userid = data.userid;
946
+ tunnel.remoteaddr = data.remoteaddr;
947
+ tunnel.state = 0;
948
+ tunnel.url = xurl;
949
+ tunnel.protocol = 0;
950
+ tunnel.soptions = data.soptions;
951
+ tunnel.tcpaddr = data.tcpaddr;
952
+ tunnel.tcpport = data.tcpport;
953
+ tunnel.udpaddr = data.udpaddr;
954
+ tunnel.udpport = data.udpport;
955
+ tunnel.end();
956
+ // Put the tunnel in the tunnels list
957
+ var index = nextTunnelIndex++;
958
+ tunnel.index = index;
959
+ tunnels[index] = tunnel;
960
+
961
+ //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
962
}
859
- break;
860
- }
861
- case 'messagebox': {
862
- // Display a message box
863
- if (data.title && data.msg) {
864
- MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
865
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
866
- try { require('message-box').create(data.title, data.msg, 120); } catch (e) { }
867
- }
868
- break;
869
- }
870
- case 'ps': {
871
- // Return the list of running processes
872
- if (data.sessionid) {
873
- processManager.getProcesses(function (plist) {
874
- mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
875
- });
876
- }
877
- break;
878
- }
879
- case 'pskill': {
880
- // Kill a process
881
- if (data.value) {
882
- MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
883
- try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
884
- }
885
- break;
963
}
887
- case 'services': {
888
- // Return the list of installed services
889
- var services = null;
890
- try { services = require('service-manager').manager.enumerateService(); } catch (e) { }
891
- if (services != null) { mesh.SendCommand({ action: 'msg', type: 'services', value: JSON.stringify(services), sessionid: data.sessionid }); }
892
- break;
893
- }
894
- case 'serviceStop': {
895
- // Stop a service
896
- try {
897
- var service = require('service-manager').manager.getService(data.serviceName);
898
- if (service != null) { service.stop(); }
899
- } catch (e) { }
900
- break;
964
+ break;
965
+ }
966
+ case 'messagebox': {
967
+ // Display a message box
968
+ if (data.title && data.msg)
969
+ {
970
+ MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
971
+ data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
972
+ try { require('message-box').create(data.title, data.msg, 120); } catch (e) { }
973
}
902
- case 'serviceStart': {
903
- // Start a service
904
- try {
905
- var service = require('service-manager').manager.getService(data.serviceName);
906
- if (service != null) { service.start(); }
907
- } catch (e) { }
908
- break;
974
+ break;
975
+ }
976
+ case 'ps': {
977
+ // Return the list of running processes
978
+ if (data.sessionid)
979
+ {
980
+ processManager.getProcesses(function (plist)
981
+ {
982
+ mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
983
+ });
984
}
910
- case 'serviceRestart': {
911
- // Restart a service
912
- try {
913
- var service = require('service-manager').manager.getService(data.serviceName);
914
- if (service != null) { service.restart(); }
915
- } catch (e) { }
916
- break;
985
+ break;
986
+ }
987
+ case 'pskill': {
988
+ // Kill a process
989
+ if (data.value)
990
+ {
991
+ MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
992
+ try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
993
}
918
- case 'deskBackground':
994
+ break;
995
+ }
996
+ case 'services': {
997
+ // Return the list of installed services
998
+ var services = null;
999
+ try { services = require('service-manager').manager.enumerateService(); } catch (e) { }
1000
+ if (services != null) { mesh.SendCommand({ action: 'msg', type: 'services', value: JSON.stringify(services), sessionid: data.sessionid }); }
1001
+ break;
1002
+ }
1003
+ case 'serviceStop': {
1004
+ // Stop a service
1005
+ try
1006
+ {
1007
+ var service = require('service-manager').manager.getService(data.serviceName);
1008
+ if (service != null) { service.stop(); }
1009
+ } catch (e) { }
1010
+ break;
1011
+ }
1012
+ case 'serviceStart': {
1013
+ // Start a service
1014
+ try
1015
+ {
1016
+ var service = require('service-manager').manager.getService(data.serviceName);
1017
+ if (service != null) { service.start(); }
1018
+ } catch (e) { }
1019
+ break;
1020
+ }
1021
+ case 'serviceRestart': {
1022
+ // Restart a service
1023
+ try
1024
+ {
1025
+ var service = require('service-manager').manager.getService(data.serviceName);
1026
+ if (service != null) { service.restart(); }
1027
+ } catch (e) { }
1028
+ break;
1029
+ }
1030
+ case 'deskBackground':
1031
+ {
1032
+ // Toggle desktop background
1033
+ try
1034
{
920
- // Toggle desktop background
921
- try {
922
- if (process.platform == 'win32') {
923
- var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
924
- var sid = undefined;
925
- if (stype == 1) {
926
- if (require('MeshAgent')._tsid != null) {
927
- stype = 5;
928
- sid = require('MeshAgent')._tsid;
929
- }
1035
+ if (process.platform == 'win32')
1036
+ {
1037
+ var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
1038
+ var sid = undefined;
1039
+ if (stype == 1)
1040
+ {
1041
+ if (require('MeshAgent')._tsid != null)
1042
+ {
1043
+ stype = 5;
1044
+ sid = require('MeshAgent')._tsid;
1045
}
931
- var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
932
- var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: stype, uid: sid });
933
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
934
- child.stderr.on('data', function () { });
935
- child.waitExit();
936
- var current = child.stdout.str.trim();
937
- if (current != '') { require('MeshAgent')._wallpaper = current; }
938
- child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: stype, uid: sid });
939
- child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
940
- child.stderr.on('data', function () { });
941
- child.waitExit();
942
- } else {
943
- var id = require('user-sessions').consoleUid();
944
- var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
945
- if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
946
- require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
1046
}
948
- } catch (e) {
949
- sendConsoleText(e);
1047
+ var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
1048
+ var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: stype, uid: sid });
1049
+ child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
1050
+ child.stderr.on('data', function () { });
1051
+ child.waitExit();
1052
+ var current = child.stdout.str.trim();
1053
+ if (current != '') { require('MeshAgent')._wallpaper = current; }
1054
+ child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: stype, uid: sid });
1055
+ child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
1056
+ child.stderr.on('data', function () { });
1057
+ child.waitExit();
1058
+ } else
1059
+ {
1060
+ var id = require('user-sessions').consoleUid();
1061
+ var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
1062
+ if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
1063
+ require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
1064
}
951
- break;
952
- }
953
- case 'openUrl': {
954
- // Open a local web browser and return success/fail
955
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
956
- sendConsoleText("OpenURL: " + data.url);
957
- if (data.url) { mesh.SendCommand({ action: 'msg', type: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
958
- break;
959
- }
960
- case 'getclip': {
961
- // Send the load clipboard back to the user
962
- //sendConsoleText('getClip: ' + JSON.stringify(data));
963
- if (require('MeshAgent').isService) {
964
- require('clipboard').dispatchRead().then(function (str) {
965
- if (str) {
966
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
967
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
968
- }
969
- });
970
- } else {
971
- require("clipboard").read().then(function (str) {
972
- if (str) {
973
- MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
974
- mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
975
- }
976
- });
1065
+ } catch (e)
1066
+ {
1067
+ sendConsoleText(e);
1068
}
1069
break;
1070
}
980
- case 'setclip': {
981
- // Set the load clipboard to a user value
982
- sendConsoleText('setClip: ' + JSON.stringify(data));
983
- if (typeof data.data == 'string') {
984
- MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
985
- if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
986
- mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
987
- }
988
- break;
1071
+ case 'openUrl': {
1072
+ // Open a local web browser and return success/fail
1073
+ MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1074
+ sendConsoleText("OpenURL: " + data.url);
1075
+ if (data.url) { mesh.SendCommand({ action: 'msg', type: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1076
+ break;
1077
+ }
1078
+ case 'getclip': {
1079
+ // Send the load clipboard back to the user
1080
+ //sendConsoleText('getClip: ' + JSON.stringify(data));
1081
+ if (require('MeshAgent').isService)
1082
+ {
1083
+ require('clipboard').dispatchRead().then(function (str)
1084
+ {
1085
+ if (str)
1086
+ {
1087
+ MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
1088
+ mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
1089
+ }
1090
+ });
1091
+ } else
1092
+ {
1093
+ require("clipboard").read().then(function (str)
1094
+ {
1095
+ if (str)
1096
+ {
1097
+ MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
1098
+ mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
1099
+ }
1100
+ });
1101
}
990
- case 'userSessions': {
991
- // Send back current user sessions list, this is Windows only.
992
- //sendConsoleText('userSessions: ' + JSON.stringify(data));
993
- if (process.platform != 'win32') break;
994
- var p = require('user-sessions').enumerateUsers();
995
- p.sessionid = data.sessionid;
996
- p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u, tag: data.tag }); });
997
- break;
1102
+ break;
1103
+ }
1104
+ case 'setclip': {
1105
+ // Set the load clipboard to a user value
1106
+ sendConsoleText('setClip: ' + JSON.stringify(data));
1107
+ if (typeof data.data == 'string')
1108
+ {
1109
+ MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
1110
+ if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
1111
+ mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
1112
}
999
- case 'cpuinfo':
1000
- // CPU & memory utilization
1001
- var cpuuse = require('sysinfo').cpuUtilization();
1002
- cpuuse.sessionid = data.sessionid;
1003
- cpuuse.tag = data.tag;
1004
- cpuuse.then(function (data)
1005
- {
1006
- mesh.SendCommand(JSON.stringify(
1007
- {
1008
- action: 'msg',
1009
- type: 'cpuinfo',
1010
- cpu: data,
1011
- memory: require('sysinfo').memUtilization(),
1012
- thermals: require('sysinfo').thermals==null?[]:require('sysinfo').thermals(),
1013
- sessionid: this.sessionid,
1014
- tag: this.tag
1015
- }));
1016
- }, function (ex) { });
1017
- break;
1018
- case 'localapp':
1019
- // Send a message to a local application
1020
- sendConsoleText('localappMsg: ' + data.appid + ', ' + JSON.stringify(data.value));
1021
- if (data.appid != null) { sendToRegisteredApp(data.appid, data.value); } else { broadcastToRegisteredApps(data.value); }
1022
- break;
1023
- default:
1024
- // Unknown action, ignore it.
1025
- break;
1113
+ break;
1114
}
1027
- break;
1028
- }
1029
- case 'acmactivate': {
1030
- if (amt != null) {
1031
- MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
1032
- amt.setAcmResponse(data);
1115
+ case 'userSessions': {
1116
+ // Send back current user sessions list, this is Windows only.
1117
+ //sendConsoleText('userSessions: ' + JSON.stringify(data));
1118
+ if (process.platform != 'win32') break;
1119
+ var p = require('user-sessions').enumerateUsers();
1120
+ p.sessionid = data.sessionid;
1121
+ p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u, tag: data.tag }); });
1122
+ break;
1123
}
1034
- break;
1124
+ case 'cpuinfo':
1125
+ // CPU & memory utilization
1126
+ var cpuuse = require('sysinfo').cpuUtilization();
1127
+ cpuuse.sessionid = data.sessionid;
1128
+ cpuuse.tag = data.tag;
1129
+ cpuuse.then(function (data)
1130
+ {
1131
+ mesh.SendCommand(JSON.stringify(
1132
+ {
1133
+ action: 'msg',
1134
+ type: 'cpuinfo',
1135
+ cpu: data,
1136
+ memory: require('sysinfo').memUtilization(),
1137
+ thermals: require('sysinfo').thermals == null ? [] : require('sysinfo').thermals(),
1138
+ sessionid: this.sessionid,
1139
+ tag: this.tag
1140
+ }));
1141
+ }, function (ex) { });
1142
+ break;
1143
+ case 'localapp':
1144
+ // Send a message to a local application
1145
+ sendConsoleText('localappMsg: ' + data.appid + ', ' + JSON.stringify(data.value));
1146
+ if (data.appid != null) { sendToRegisteredApp(data.appid, data.value); } else { broadcastToRegisteredApps(data.value); }
1147
+ break;
1148
+ default:
1149
+ // Unknown action, ignore it.
1150
+ break;
1151
}
1036
- case 'wakeonlan': {
1037
- // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
1038
- //sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
1039
- for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
1040
- break;
1152
+ break;
1153
+ }
1154
+ case 'acmactivate': {
1155
+ if (amt != null)
1156
+ {
1157
+ MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
1158
+ amt.setAcmResponse(data);
1159
}
1042
- case 'runcommands': {
1043
- if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; }
1044
- sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds);
1045
-
1046
- // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
1047
- var options = {};
1048
- if (data.runAsUser > 0) {
1049
- try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
1050
- options.type = require('child_process').SpawnTypes.TERM;
1051
- }
1052
- if (data.runAsUser == 2) {
1053
- if (options.uid == null) break;
1054
- if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1055
- }
1160
+ break;
1161
+ }
1162
+ case 'wakeonlan': {
1163
+ // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
1164
+ //sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
1165
+ for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
1166
+ break;
1167
+ }
1168
+ case 'runcommands': {
1169
+ if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; }
1170
+ sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds);
1171
1057
- if (process.platform == 'win32') {
1058
- if (data.type == 1) {
1059
- // Windows command shell
1060
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1061
- mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1062
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1063
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1064
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1065
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1066
- } else if (data.type == 2) {
1067
- // Windows Powershell
1068
- mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1069
- mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
1070
- mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1071
- mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1072
- mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1073
- mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1074
- }
1075
- } else if (data.type == 3) {
1076
- // Linux shell
1077
- mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1172
+ // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
1173
+ var options = {};
1174
+ if (data.runAsUser > 0)
1175
+ {
1176
+ try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
1177
+ options.type = require('child_process').SpawnTypes.TERM;
1178
+ }
1179
+ if (data.runAsUser == 2)
1180
+ {
1181
+ if (options.uid == null) break;
1182
+ if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1183
+ }
1184
+
1185
+ if (process.platform == 'win32')
1186
+ {
1187
+ if (data.type == 1)
1188
+ {
1189
+ // Windows command shell
1190
+ mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1191
mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1192
mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1193
mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1081
- mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
1194
+ mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1195
+ mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1196
+ } else if (data.type == 2)
1197
+ {
1198
+ // Windows Powershell
1199
+ mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1200
+ mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
1201
+ mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1202
+ mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1203
+ mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1204
mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1205
}
1084
- break;
1085
- }
1086
- case 'uninstallagent':
1087
- // Uninstall this agent
1088
- var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1089
- try {
1090
- agentName = require('MeshAgent').serviceName;
1091
- }
1092
- catch (x) {
1093
- }
1094
-
1095
- if (require('service-manager').manager.getService(agentName).isMe()) {
1096
- try { diagnosticAgent_uninstall(); } catch (e) { }
1097
- var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1098
- 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 });
1099
- }
1100
- break;
1101
- case 'poweraction': {
1102
- // Server telling us to execute a power action
1103
- if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
1104
- var forced = 0;
1105
- if (data.forced == 1) { forced = 1; }
1106
- data.actiontype = parseInt(data.actiontype);
1107
- MeshServerLogEx(25, [data.actiontype, forced], "Performing power action=" + data.actiontype + ", forced=" + forced, data);
1108
- sendConsoleText("Performing power action=" + data.actiontype + ", forced=" + forced + '.');
1109
- var r = mesh.ExecPowerState(data.actiontype, forced);
1110
- sendConsoleText("ExecPowerState returned code: " + r);
1111
- }
1112
- break;
1113
- }
1114
- case 'iplocation': {
1115
- // 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
1116
- getIpLocationData(function (location) { mesh.SendCommand({ action: 'iplocation', type: 'publicip', value: location }); });
1117
- break;
1118
- }
1119
- case 'toast': {
1120
- // Display a toast message
1121
- if (data.title && data.msg) {
1122
- MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1123
- data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1124
- try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
1125
- }
1126
- break;
1206
+ } else if (data.type == 3)
1207
+ {
1208
+ // Linux shell
1209
+ mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1210
+ mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
1211
+ mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); });
1212
+ mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1213
+ mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
1214
+ mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1215
}
1128
- case 'openUrl': {
1129
- // Open a local web browser and return success/fail
1130
- //sendConsoleText('OpenURL: ' + data.url);
1131
- MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1132
- if (data.url) { mesh.SendCommand({ action: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1133
- break;
1216
+ break;
1217
+ }
1218
+ case 'uninstallagent':
1219
+ // Uninstall this agent
1220
+ var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1221
+ try
1222
+ {
1223
+ agentName = require('MeshAgent').serviceName;
1224
}
1135
- case 'amtconfig': {
1136
- // Perform Intel AMT activation and/or configuration
1137
- if ((apftunnel != null) || (amt == null) || (typeof data.user != 'string') || (typeof data.pass != 'string')) break;
1138
- amt.getMeiState(15, function (state) {
1139
- if ((apftunnel != null) || (amt == null)) return;
1140
- if ((state == null) || (state.ProvisioningState == null)) return;
1141
- if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
1142
- var apfarg = {
1143
- mpsurl: mesh.ServerUrl.replace('/agent.ashx', '/apf.ashx'),
1144
- mpsuser: data.user, // Agent user name
1145
- mpspass: data.pass, // Encrypted login cookie
1146
- mpskeepalive: 60000,
1147
- clientname: state.OsHostname,
1148
- clientaddress: '127.0.0.1',
1149
- clientuuid: state.UUID,
1150
- conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
1151
- meiState: state // MEI state will be passed to MPS server
1152
- };
1153
- addAmtEvent('LMS tunnel start.');
1154
- apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
1155
- apftunnel.onJsonControl = function (data) {
1156
- if (data.action == 'console') { addAmtEvent(data.msg); } // Add console message to AMT event log
1157
- if (data.action == 'mestate') { amt.getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
1158
- if (data.action == 'deactivate') { // Request CCM deactivation
1159
- var amtMeiModule, amtMei;
1160
- try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); return; }
1161
- amtMei.on('error', function (e) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); });
1162
- amtMei.unprovision(1, function (status) { if (apftunnel) apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
1163
- }
1164
- if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
1165
- }
1166
- apftunnel.onChannelClosed = function () { addAmtEvent('LMS tunnel closed.'); apftunnel = null; }
1167
- try { apftunnel.connect(); } catch (ex) { }
1168
- });
1169
- break;
1225
+ catch (x)
1226
+ {
1227
}
1171
- case 'getScript': {
1172
- // Received a configuration script from the server
1173
- sendConsoleText('getScript: ' + JSON.stringify(data));
1174
- break;
1228
+
1229
+ if (require('service-manager').manager.getService(agentName).isMe())
1230
+ {
1231
+ try { diagnosticAgent_uninstall(); } catch (e) { }
1232
+ var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1233
+ 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 });
1234
}
1176
- case 'sysinfo': {
1177
- // Fetch system information
1178
- getSystemInformation(function (results) {
1179
- if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1180
- });
1181
- break;
1235
+ break;
1236
+ case 'poweraction': {
1237
+ // Server telling us to execute a power action
1238
+ if ((mesh.ExecPowerState != undefined) && (data.actiontype))
1239
+ {
1240
+ var forced = 0;
1241
+ if (data.forced == 1) { forced = 1; }
1242
+ data.actiontype = parseInt(data.actiontype);
1243
+ MeshServerLogEx(25, [data.actiontype, forced], "Performing power action=" + data.actiontype + ", forced=" + forced, data);
1244
+ sendConsoleText("Performing power action=" + data.actiontype + ", forced=" + forced + '.');
1245
+ var r = mesh.ExecPowerState(data.actiontype, forced);
1246
+ sendConsoleText("ExecPowerState returned code: " + r);
1247
}
1183
- case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
1184
- case 'pong': { break; }
1185
- case 'plugin': {
1186
- try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; }
1187
- break;
1248
+ break;
1249
+ }
1250
+ case 'iplocation': {
1251
+ // 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
1252
+ getIpLocationData(function (location) { mesh.SendCommand({ action: 'iplocation', type: 'publicip', value: location }); });
1253
+ break;
1254
+ }
1255
+ case 'toast': {
1256
+ // Display a toast message
1257
+ if (data.title && data.msg)
1258
+ {
1259
+ MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1260
+ data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1261
+ try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
1262
}
1189
- case 'coredump':
1190
- // Set the current agent coredump situation.
1191
- if (data.value === true) {
1192
- if (process.platform == 'win32') {
1193
- // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1194
- process.coreDumpLocation = process.execPath.replace('.exe', '.dmp');
1195
- } else {
1196
- process.coreDumpLocation = (process.cwd() != '//') ? (process.cwd() + 'core') : null;
1263
+ break;
1264
+ }
1265
+ case 'openUrl': {
1266
+ // Open a local web browser and return success/fail
1267
+ //sendConsoleText('OpenURL: ' + data.url);
1268
+ MeshServerLogEx(20, [data.url], "Opening: " + data.url, data);
1269
+ if (data.url) { mesh.SendCommand({ action: 'openUrl', url: data.url, sessionid: data.sessionid, success: (openUserDesktopUrl(data.url) != null) }); }
1270
+ break;
1271
+ }
1272
+ case 'amtconfig': {
1273
+ // Perform Intel AMT activation and/or configuration
1274
+ if ((apftunnel != null) || (amt == null) || (typeof data.user != 'string') || (typeof data.pass != 'string')) break;
1275
+ amt.getMeiState(15, function (state)
1276
+ {
1277
+ if ((apftunnel != null) || (amt == null)) return;
1278
+ if ((state == null) || (state.ProvisioningState == null)) return;
1279
+ if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
1280
+ var apfarg = {
1281
+ mpsurl: mesh.ServerUrl.replace('/agent.ashx', '/apf.ashx'),
1282
+ mpsuser: data.user, // Agent user name
1283
+ mpspass: data.pass, // Encrypted login cookie
1284
+ mpskeepalive: 60000,
1285
+ clientname: state.OsHostname,
1286
+ clientaddress: '127.0.0.1',
1287
+ clientuuid: state.UUID,
1288
+ conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
1289
+ meiState: state // MEI state will be passed to MPS server
1290
+ };
1291
+ addAmtEvent('LMS tunnel start.');
1292
+ apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
1293
+ apftunnel.onJsonControl = function (data)
1294
+ {
1295
+ if (data.action == 'console') { addAmtEvent(data.msg); } // Add console message to AMT event log
1296
+ if (data.action == 'mestate') { amt.getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
1297
+ if (data.action == 'deactivate')
1298
+ { // Request CCM deactivation
1299
+ var amtMeiModule, amtMei;
1300
+ try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); return; }
1301
+ amtMei.on('error', function (e) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); });
1302
+ amtMei.unprovision(1, function (status) { if (apftunnel) apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
1303
}
1198
- } else if (data.value === false) {
1199
- process.coreDumpLocation = null;
1200
- }
1201
- break;
1202
- case 'getcoredump':
1203
- // Ask the agent if a core dump is currently available, if yes, also return the hash of the agent.
1204
- var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1205
- var coreDumpPath = null;
1206
- if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1207
- if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath))) {
1208
- try {
1209
- var coredate = fs.statSync(coreDumpPath).mtime;
1210
- var coretime = new Date(coredate).getTime();
1211
- var agenttime = new Date(fs.statSync(process.execPath).mtime).getTime();
1212
- if (coretime > agenttime) { r.exists = (db.Get('CoreDumpTime') != coredate); }
1213
- } catch (ex) { }
1214
- }
1215
- if (r.exists == true) {
1216
- r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); // Hash of current agent
1217
- r.corehashhex = getSHA384FileHash(coreDumpPath).toString('hex'); // Hash of core dump file
1304
+ if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
1305
}
1219
- mesh.SendCommand(JSON.stringify(r));
1220
- break;
1221
- case 'meshToolInfo':
1222
- if (data.pipe == true) { delete data.pipe; delete data.action; data.cmd = 'meshToolInfo'; broadcastToRegisteredApps(data); }
1223
- break;
1224
- case 'wget': // Server uses this command to tell the agent to download a file using HTTPS/GET and place it in a given path. This is used for one-to-many file uploads.
1225
- agentFileHttpPendingRequests.push(data);
1226
- serverFetchFile();
1227
- break;
1228
- default:
1229
- // Unknown action, ignore it.
1230
- break;
1306
+ apftunnel.onChannelClosed = function () { addAmtEvent('LMS tunnel closed.'); apftunnel = null; }
1307
+ try { apftunnel.connect(); } catch (ex) { }
1308
+ });
1309
+ break;
1310
}
1232
- }
1233
- }
1234
-
1235
- // Agent just get a file from the server and save it locally.
1236
- function serverFetchFile() {
1237
- if ((Object.keys(agentFileHttpRequests).length > 4) || (agentFileHttpPendingRequests.length == 0)) return; // No more than 4 active HTTPS requests to the server.
1238
- var data = agentFileHttpPendingRequests.shift();
1239
- if ((data.overwrite !== true) && fs.existsSync(data.path)) return; // Don't overwrite an existing file.
1240
- if (data.createFolder) { try { fs.mkdirSync(data.folder); } catch (ex) { } } // If requested, create the local folder.
1241
- data.url = 'http' + getServerTargetUrlEx('*/').substring(2);
1242
- var agentFileHttpOptions = http.parseUri(data.url);
1243
- agentFileHttpOptions.path = data.urlpath;
1244
-
1245
- // Perform manual server TLS certificate checking based on the certificate hash given by the server.
1246
- agentFileHttpOptions.rejectUnauthorized = 0;
1247
- agentFileHttpOptions.checkServerIdentity = function checkServerIdentity(certs) {
1248
- // If the tunnel certificate matches the control channel certificate, accept the connection
1249
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1250
- try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
1251
- // Check that the certificate is the one expected by the server, fail if not.
1252
- if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1253
- }
1254
- agentFileHttpOptions.checkServerIdentity.servertlshash = data.servertlshash;
1255
-
1256
- if (agentFileHttpOptions == null) return;
1257
- var agentFileHttpRequest = http.request(agentFileHttpOptions,
1258
- function (response) {
1259
- response.xparent = this;
1260
- try {
1261
- response.xfile = fs.createWriteStream(this.xpath, { flags: 'wbN' })
1262
- response.pipe(response.xfile);
1263
- response.end = function () { delete agentFileHttpRequests[this.xparent.xurlpath]; delete this.xparent; serverFetchFile(); }
1264
- } catch (ex) { delete agentFileHttpRequests[this.xurlpath]; delete response.xparent; serverFetchFile(); return; }
1311
+ case 'getScript': {
1312
+ // Received a configuration script from the server
1313
+ sendConsoleText('getScript: ' + JSON.stringify(data));
1314
+ break;
1315
}
1266
- );
1267
- agentFileHttpRequest.on('error', function (ex) { delete agentFileHttpRequests[this.xurlpath]; serverFetchFile(); });
1268
- agentFileHttpRequest.end();
1269
- agentFileHttpRequest.xurlpath = data.urlpath;
1270
- agentFileHttpRequest.xpath = data.path;
1271
- agentFileHttpRequests[data.urlpath] = agentFileHttpRequest;
1272
- }
1273
-
1274
- // Called when a file changed in the file system
1275
- /*
1276
- function onFileWatcher(a, b) {
1277
- console.log('onFileWatcher', a, b, this.path);
1278
- var response = getDirectoryInfo(this.path);
1279
- if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
1280
- }
1281
- */
1282
-
1283
- function getSystemInformation(func) {
1284
- try {
1285
- var results = { hardware: require('identifiers').get() }; // Hardware info
1286
- if (results.hardware && results.hardware.windows) {
1287
- // Remove extra entries and things that change quickly
1288
- var x = results.hardware.windows.osinfo;
1289
- try { delete x.FreePhysicalMemory; } catch (e) { }
1290
- try { delete x.FreeSpaceInPagingFiles; } catch (e) { }
1291
- try { delete x.FreeVirtualMemory; } catch (e) { }
1292
- try { delete x.LocalDateTime; } catch (e) { }
1293
- try { delete x.MaxProcessMemorySize; } catch (e) { }
1294
- try { delete x.TotalVirtualMemorySize; } catch (e) { }
1295
- try { delete x.TotalVisibleMemorySize; } catch (e) { }
1296
- try {
1297
- if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1298
- if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1299
- if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1300
- } catch (e) { }
1316
+ case 'sysinfo': {
1317
+ // Fetch system information
1318
+ getSystemInformation(function (results)
1319
+ {
1320
+ if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1321
+ });
1322
+ break;
1323
}
1302
- if (process.platform == 'win32')
1303
- {
1304
- results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot
1305
- if (require('identifiers').volumes != null)
1324
+ case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
1325
+ case 'pong': { break; }
1326
+ case 'plugin': {
1327
+ try { require(data.plugin).consoleaction(data, data.rights, data.sessionid, this); } catch (e) { throw e; }
1328
+ break;
1329
+ }
1330
+ case 'coredump':
1331
+ // Set the current agent coredump situation.
1332
+ if (data.value === true)
1333
{
1307
- try
1334
+ if (process.platform == 'win32')
1335
{
1309
- results.volumes = require('identifiers').volumes();
1310
- }
1311
- catch (e)
1336
+ // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1337
+ process.coreDumpLocation = process.execPath.replace('.exe', '.dmp');
1338
+ } else
1339
{
1340
+ process.coreDumpLocation = (process.cwd() != '//') ? (process.cwd() + 'core') : null;
1341
}
1342
+ } else if (data.value === false)
1343
+ {
1344
+ process.coreDumpLocation = null;
1345
}
1315
- }
1316
-
1317
- /*
1318
- if (process.platform == 'win32') {
1319
- var defragResult = function (r) {
1320
- if (typeof r == 'object') { results[this.callname] = r; }
1321
- if (this.callname == 'defrag') {
1322
- var pr = require('win-info').installedApps(); // Installed apps
1323
- pr.callname = 'installedApps';
1324
- pr.sessionid = data.sessionid;
1325
- pr.then(defragResult, defragResult);
1326
- }
1327
- else {
1328
- results.winpatches = require('win-info').qfe(); // Windows patches
1329
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1330
- func(results);
1331
- }
1332
- }
1333
- var pr = require('win-info').defrag({ volume: 'C:' }); // Defrag TODO
1334
- pr.callname = 'defrag';
1335
- pr.sessionid = data.sessionid;
1336
- pr.then(defragResult, defragResult);
1337
- } else {
1338
- */
1339
- results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1340
- func(results);
1341
- //}
1342
- } catch (e) { func(null, e); }
1343
- }
1344
-
1345
- // Get a formated response for a given directory path
1346
- function getDirectoryInfo(reqpath) {
1347
- var response = { path: reqpath, dir: [] };
1348
- if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
1349
- // List all the drives in the root, or the root itself
1350
- var results = null;
1351
- try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1352
- if (results != null) {
1353
- for (var i = 0; i < results.length; ++i) {
1354
- var drive = { n: results[i].name, t: 1 };
1355
- if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1356
- response.dir.push(drive);
1346
+ break;
1347
+ case 'getcoredump':
1348
+ // Ask the agent if a core dump is currently available, if yes, also return the hash of the agent.
1349
+ var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1350
+ var coreDumpPath = null;
1351
+ if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1352
+ if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath)))
1353
+ {
1354
+ try
1355
+ {
1356
+ var coredate = fs.statSync(coreDumpPath).mtime;
1357
+ var coretime = new Date(coredate).getTime();
1358
+ var agenttime = new Date(fs.statSync(process.execPath).mtime).getTime();
1359
+ if (coretime > agenttime) { r.exists = (db.Get('CoreDumpTime') != coredate); }
1360
+ } catch (ex) { }
1361
}
1358
- }
1359
- } else {
1360
- // List all the files and folders in this path
1361
- if (reqpath == '') { reqpath = '/'; }
1362
- var results = null, xpath = obj.path.join(reqpath, '*');
1363
- //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1364
- try { results = fs.readdirSync(xpath); } catch (e) { }
1365
- if (results != null) {
1366
- for (var i = 0; i < results.length; ++i) {
1367
- if ((results[i] != '.') && (results[i] != '..')) {
1368
- var stat = null, p = obj.path.join(reqpath, results[i]);
1369
- //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1370
- try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1371
- if ((stat != null) && (stat != undefined)) {
1372
- if (stat.isDirectory() == true) {
1373
- response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1374
- } else {
1375
- response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1376
- }
1377
- }
1378
- }
1362
+ if (r.exists == true)
1363
+ {
1364
+ r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); // Hash of current agent
1365
+ r.corehashhex = getSHA384FileHash(coreDumpPath).toString('hex'); // Hash of core dump file
1366
}
1380
- }
1367
+ mesh.SendCommand(JSON.stringify(r));
1368
+ break;
1369
+ case 'meshToolInfo':
1370
+ if (data.pipe == true) { delete data.pipe; delete data.action; data.cmd = 'meshToolInfo'; broadcastToRegisteredApps(data); }
1371
+ break;
1372
+ case 'wget': // Server uses this command to tell the agent to download a file using HTTPS/GET and place it in a given path. This is used for one-to-many file uploads.
1373
+ agentFileHttpPendingRequests.push(data);
1374
+ serverFetchFile();
1375
+ break;
1376
+ default:
1377
+ // Unknown action, ignore it.
1378
+ break;
1379
}
1382
- return response;
1380
}
1381
+}
1382
+
1383
+// Agent just get a file from the server and save it locally.
1384
+function serverFetchFile()
1385
+{
1386
+ if ((Object.keys(agentFileHttpRequests).length > 4) || (agentFileHttpPendingRequests.length == 0)) return; // No more than 4 active HTTPS requests to the server.
1387
+ var data = agentFileHttpPendingRequests.shift();
1388
+ if ((data.overwrite !== true) && fs.existsSync(data.path)) return; // Don't overwrite an existing file.
1389
+ if (data.createFolder) { try { fs.mkdirSync(data.folder); } catch (ex) { } } // If requested, create the local folder.
1390
+ data.url = 'http' + getServerTargetUrlEx('*/').substring(2);
1391
+ var agentFileHttpOptions = http.parseUri(data.url);
1392
+ agentFileHttpOptions.path = data.urlpath;
1393
+
1394
+ // Perform manual server TLS certificate checking based on the certificate hash given by the server.
1395
+ agentFileHttpOptions.rejectUnauthorized = 0;
1396
+ agentFileHttpOptions.checkServerIdentity = function checkServerIdentity(certs)
1397
+ {
1398
+ // If the tunnel certificate matches the control channel certificate, accept the connection
1399
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1400
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
1401
+ // Check that the certificate is the one expected by the server, fail if not.
1402
+ if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1403
+ }
1404
+ agentFileHttpOptions.checkServerIdentity.servertlshash = data.servertlshash;
1405
1385
- // Tunnel callback operations
1386
- function onTunnelUpgrade(response, s, head) {
1387
- this.s = s;
1388
- s.httprequest = this;
1389
- s.end = onTunnelClosed;
1390
- s.tunnel = this;
1391
- s.descriptorMetadata = "MeshAgent_relayTunnel";
1392
-
1393
- if (require('MeshAgent').idleTimeout != null) {
1394
- s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1395
- s.on('timeout', function () {
1396
- this.ping();
1397
- this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1398
- });
1406
+ if (agentFileHttpOptions == null) return;
1407
+ var agentFileHttpRequest = http.request(agentFileHttpOptions,
1408
+ function (response)
1409
+ {
1410
+ response.xparent = this;
1411
+ try
1412
+ {
1413
+ response.xfile = fs.createWriteStream(this.xpath, { flags: 'wbN' })
1414
+ response.pipe(response.xfile);
1415
+ response.end = function () { delete agentFileHttpRequests[this.xparent.xurlpath]; delete this.xparent; serverFetchFile(); }
1416
+ } catch (ex) { delete agentFileHttpRequests[this.xurlpath]; delete response.xparent; serverFetchFile(); return; }
1417
}
1418
+ );
1419
+ agentFileHttpRequest.on('error', function (ex) { delete agentFileHttpRequests[this.xurlpath]; serverFetchFile(); });
1420
+ agentFileHttpRequest.end();
1421
+ agentFileHttpRequest.xurlpath = data.urlpath;
1422
+ agentFileHttpRequest.xpath = data.path;
1423
+ agentFileHttpRequests[data.urlpath] = agentFileHttpRequest;
1424
+}
1425
1401
- //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1402
-
1403
- if (this.tcpport != null) {
1404
- // This is a TCP relay connection, pause now and try to connect to the target.
1405
- s.pause();
1406
- s.data = onTcpRelayServerTunnelData;
1407
- var connectionOptions = { port: parseInt(this.tcpport) };
1408
- if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
1409
- s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
1410
- s.tcprelay.peerindex = this.index;
1411
-
1412
- // Add the TCP session to the count and update the server
1413
- if (s.httprequest.userid != null) {
1414
- if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
1415
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1416
- broadcastSessionsToRegisteredApps();
1426
+// Called when a file changed in the file system
1427
+/*
1428
+function onFileWatcher(a, b) {
1429
+ console.log('onFileWatcher', a, b, this.path);
1430
+ var response = getDirectoryInfo(this.path);
1431
+ if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
1432
+}
1433
+*/
1434
+
1435
+function getSystemInformation(func)
1436
+{
1437
+ try
1438
+ {
1439
+ var results = { hardware: require('identifiers').get() }; // Hardware info
1440
+ if (results.hardware && results.hardware.windows)
1441
+ {
1442
+ // Remove extra entries and things that change quickly
1443
+ var x = results.hardware.windows.osinfo;
1444
+ try { delete x.FreePhysicalMemory; } catch (e) { }
1445
+ try { delete x.FreeSpaceInPagingFiles; } catch (e) { }
1446
+ try { delete x.FreeVirtualMemory; } catch (e) { }
1447
+ try { delete x.LocalDateTime; } catch (e) { }
1448
+ try { delete x.MaxProcessMemorySize; } catch (e) { }
1449
+ try { delete x.TotalVirtualMemorySize; } catch (e) { }
1450
+ try { delete x.TotalVisibleMemorySize; } catch (e) { }
1451
+ try
1452
+ {
1453
+ if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1454
+ if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1455
+ if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1456
+ } catch (e) { }
1457
+ }
1458
+ if (process.platform == 'win32')
1459
+ {
1460
+ results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot
1461
+ if (require('identifiers').volumes != null)
1462
+ {
1463
+ try
1464
+ {
1465
+ results.volumes = require('identifiers').volumes();
1466
+ }
1467
+ catch (e)
1468
+ {
1469
+ }
1470
}
1418
- } if (this.udpport != null) {
1419
- // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1420
- s.data = onUdpRelayServerTunnelData;
1421
- s.udprelay = require('dgram').createSocket({ type: 'udp4' });
1422
- s.udprelay.bind({ port: 0 });
1423
- s.udprelay.peerindex = this.index;
1424
- s.udprelay.on('message', onUdpRelayTargetTunnelConnect);
1425
- s.udprelay.udpport = this.udpport;
1426
- s.udprelay.udpaddr = this.udpaddr;
1427
- s.udprelay.first = true;
1428
-
1429
- // Add the UDP session to the count and update the server
1430
- if (s.httprequest.userid != null) {
1431
- if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
1432
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1433
- broadcastSessionsToRegisteredApps();
1471
+ }
1472
+
1473
+ /*
1474
+ if (process.platform == 'win32') {
1475
+ var defragResult = function (r) {
1476
+ if (typeof r == 'object') { results[this.callname] = r; }
1477
+ if (this.callname == 'defrag') {
1478
+ var pr = require('win-info').installedApps(); // Installed apps
1479
+ pr.callname = 'installedApps';
1480
+ pr.sessionid = data.sessionid;
1481
+ pr.then(defragResult, defragResult);
1482
+ }
1483
+ else {
1484
+ results.winpatches = require('win-info').qfe(); // Windows patches
1485
+ results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1486
+ func(results);
1487
+ }
1488
}
1489
+ var pr = require('win-info').defrag({ volume: 'C:' }); // Defrag TODO
1490
+ pr.callname = 'defrag';
1491
+ pr.sessionid = data.sessionid;
1492
+ pr.then(defragResult, defragResult);
1493
} else {
1436
- // This is a normal connect for KVM/Terminal/Files
1437
- s.data = onTunnelData;
1494
+ */
1495
+ results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1496
+ func(results);
1497
+ //}
1498
+ } catch (e) { func(null, e); }
1499
+}
1500
+
1501
+// Get a formated response for a given directory path
1502
+function getDirectoryInfo(reqpath)
1503
+{
1504
+ var response = { path: reqpath, dir: [] };
1505
+ if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32'))
1506
+ {
1507
+ // List all the drives in the root, or the root itself
1508
+ var results = null;
1509
+ try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1510
+ if (results != null)
1511
+ {
1512
+ for (var i = 0; i < results.length; ++i)
1513
+ {
1514
+ var drive = { n: results[i].name, t: 1 };
1515
+ if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1516
+ response.dir.push(drive);
1517
+ }
1518
+ }
1519
+ } else
1520
+ {
1521
+ // List all the files and folders in this path
1522
+ if (reqpath == '') { reqpath = '/'; }
1523
+ var results = null, xpath = obj.path.join(reqpath, '*');
1524
+ //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1525
+ try { results = fs.readdirSync(xpath); } catch (e) { }
1526
+ if (results != null)
1527
+ {
1528
+ for (var i = 0; i < results.length; ++i)
1529
+ {
1530
+ if ((results[i] != '.') && (results[i] != '..'))
1531
+ {
1532
+ var stat = null, p = obj.path.join(reqpath, results[i]);
1533
+ //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1534
+ try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1535
+ if ((stat != null) && (stat != undefined))
1536
+ {
1537
+ if (stat.isDirectory() == true)
1538
+ {
1539
+ response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1540
+ } else
1541
+ {
1542
+ response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1543
+ }
1544
+ }
1545
+ }
1546
+ }
1547
}
1548
}
1549
+ return response;
1550
+}
1551
+
1552
+// Tunnel callback operations
1553
+function onTunnelUpgrade(response, s, head)
1554
+{
1555
+ this.s = s;
1556
+ s.httprequest = this;
1557
+ s.end = onTunnelClosed;
1558
+ s.tunnel = this;
1559
+ s.descriptorMetadata = "MeshAgent_relayTunnel";
1560
1441
- // Called when UDP relay data is received // TODO****
1442
- function onUdpRelayTargetTunnelConnect(data) {
1443
- var peerTunnel = tunnels[this.peerindex];
1444
- peerTunnel.s.write(data);
1561
+ if (require('MeshAgent').idleTimeout != null)
1562
+ {
1563
+ s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1564
+ s.on('timeout', function ()
1565
+ {
1566
+ this.ping();
1567
+ this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1568
+ });
1569
}
1570
1447
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1448
- function onUdpRelayServerTunnelData(data) {
1449
- if (this.udprelay.first === true) {
1450
- delete this.udprelay.first; // Skip the first 'c' that is received.
1451
- } else {
1452
- this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1571
+ //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1572
+
1573
+ if (this.tcpport != null)
1574
+ {
1575
+ // This is a TCP relay connection, pause now and try to connect to the target.
1576
+ s.pause();
1577
+ s.data = onTcpRelayServerTunnelData;
1578
+ var connectionOptions = { port: parseInt(this.tcpport) };
1579
+ if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
1580
+ s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
1581
+ s.tcprelay.peerindex = this.index;
1582
+
1583
+ // Add the TCP session to the count and update the server
1584
+ if (s.httprequest.userid != null)
1585
+ {
1586
+ if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
1587
+ try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1588
+ broadcastSessionsToRegisteredApps();
1589
+ }
1590
+ } if (this.udpport != null)
1591
+ {
1592
+ // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1593
+ s.data = onUdpRelayServerTunnelData;
1594
+ s.udprelay = require('dgram').createSocket({ type: 'udp4' });
1595
+ s.udprelay.bind({ port: 0 });
1596
+ s.udprelay.peerindex = this.index;
1597
+ s.udprelay.on('message', onUdpRelayTargetTunnelConnect);
1598
+ s.udprelay.udpport = this.udpport;
1599
+ s.udprelay.udpaddr = this.udpaddr;
1600
+ s.udprelay.first = true;
1601
+
1602
+ // Add the UDP session to the count and update the server
1603
+ if (s.httprequest.userid != null)
1604
+ {
1605
+ if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
1606
+ try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1607
+ broadcastSessionsToRegisteredApps();
1608
}
1609
+ } else
1610
+ {
1611
+ // This is a normal connect for KVM/Terminal/Files
1612
+ s.data = onTunnelData;
1613
}
1614
+}
1615
+
1616
+// Called when UDP relay data is received // TODO****
1617
+function onUdpRelayTargetTunnelConnect(data)
1618
+{
1619
+ var peerTunnel = tunnels[this.peerindex];
1620
+ peerTunnel.s.write(data);
1621
+}
1622
1456
- // Called when the TCP relay target is connected
1457
- function onTcpRelayTargetTunnelConnect() {
1458
- var peerTunnel = tunnels[this.peerindex];
1459
- this.pipe(peerTunnel.s); // Pipe Target --> Server
1460
- peerTunnel.s.first = true;
1461
- peerTunnel.s.resume();
1623
+// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1624
+function onUdpRelayServerTunnelData(data)
1625
+{
1626
+ if (this.udprelay.first === true)
1627
+ {
1628
+ delete this.udprelay.first; // Skip the first 'c' that is received.
1629
+ } else
1630
+ {
1631
+ this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1632
}
1633
+}
1634
1464
- // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1465
- function onTcpRelayServerTunnelData(data) {
1466
- if (this.first == true) {
1467
- this.first = false;
1468
- this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1469
- }
1635
+// Called when the TCP relay target is connected
1636
+function onTcpRelayTargetTunnelConnect()
1637
+{
1638
+ var peerTunnel = tunnels[this.peerindex];
1639
+ this.pipe(peerTunnel.s); // Pipe Target --> Server
1640
+ peerTunnel.s.first = true;
1641
+ peerTunnel.s.resume();
1642
+}
1643
+
1644
+// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1645
+function onTcpRelayServerTunnelData(data)
1646
+{
1647
+ if (this.first == true)
1648
+ {
1649
+ this.first = false;
1650
+ this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1651
}
1652
+}
1653
1472
- function onTunnelClosed() {
1473
- var tunnel = tunnels[this.httprequest.index];
1474
- if (tunnel == null) return; // Stop duplicate calls.
1654
+function onTunnelClosed()
1655
+{
1656
+ var tunnel = tunnels[this.httprequest.index];
1657
+ if (tunnel == null) return; // Stop duplicate calls.
1658
1476
- // If this is a routing session, clean up and send the new session counts.
1477
- if (this.httprequest.userid != null) {
1478
- if (this.httprequest.tcpport != null) {
1479
- 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]; } }
1480
- try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1481
- broadcastSessionsToRegisteredApps();
1482
- } else if (this.httprequest.udpport != null) {
1483
- 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]; } }
1484
- try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1485
- broadcastSessionsToRegisteredApps();
1486
- }
1659
+ // If this is a routing session, clean up and send the new session counts.
1660
+ if (this.httprequest.userid != null)
1661
+ {
1662
+ if (this.httprequest.tcpport != null)
1663
+ {
1664
+ 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]; } }
1665
+ try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1666
+ broadcastSessionsToRegisteredApps();
1667
+ } else if (this.httprequest.udpport != null)
1668
+ {
1669
+ 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]; } }
1670
+ try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1671
+ broadcastSessionsToRegisteredApps();
1672
}
1673
+ }
1674
1489
- // Sent tunnel statistics to the server, only send this if compression was used.
1490
- if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString())) {
1491
- mesh.SendCommand({
1492
- action: 'tunnelCloseStats',
1493
- url: tunnel.url,
1494
- userid: tunnel.userid,
1495
- protocol: tunnel.protocol,
1496
- sessionid: tunnel.sessionid,
1497
- sent: this.bytesSent_uncompressed.toString(),
1498
- sentActual: this.bytesSent_actual.toString(),
1499
- sentRatio: this.bytesSent_ratio,
1500
- received: this.bytesReceived_uncompressed.toString(),
1501
- receivedActual: this.bytesReceived_actual.toString(),
1502
- receivedRatio: this.bytesReceived_ratio
1503
- });
1504
- }
1675
+ // Sent tunnel statistics to the server, only send this if compression was used.
1676
+ if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString()))
1677
+ {
1678
+ mesh.SendCommand({
1679
+ action: 'tunnelCloseStats',
1680
+ url: tunnel.url,
1681
+ userid: tunnel.userid,
1682
+ protocol: tunnel.protocol,
1683
+ sessionid: tunnel.sessionid,
1684
+ sent: this.bytesSent_uncompressed.toString(),
1685
+ sentActual: this.bytesSent_actual.toString(),
1686
+ sentRatio: this.bytesSent_ratio,
1687
+ received: this.bytesReceived_uncompressed.toString(),
1688
+ receivedActual: this.bytesReceived_actual.toString(),
1689
+ receivedRatio: this.bytesReceived_ratio
1690
+ });
1691
+ }
1692
1506
- //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1507
- if (this.httprequest.index) { delete tunnels[this.httprequest.index]; }
1693
+ //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1694
+ if (this.httprequest.index) { delete tunnels[this.httprequest.index]; }
1695
1509
- /*
1510
- // Close the watcher if required
1511
- if (this.httprequest.watcher != undefined) {
1512
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
1513
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
1514
- delete this.httprequest.watcher;
1515
- }
1516
- */
1696
+ /*
1697
+ // Close the watcher if required
1698
+ if (this.httprequest.watcher != undefined) {
1699
+ //console.log('Closing watcher: ' + this.httprequest.watcher.path);
1700
+ //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
1701
+ delete this.httprequest.watcher;
1702
+ }
1703
+ */
1704
+
1705
+ // If there is a upload or download active on this connection, close the file
1706
+ if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
1707
+ if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1708
+
1709
+ // Clean up WebRTC
1710
+ if (this.webrtc != null)
1711
+ {
1712
+ 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; }
1713
+ if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1714
+ try { this.webrtc.close(); } catch (e) { }
1715
+ this.webrtc.removeAllListeners('connected');
1716
+ this.webrtc.removeAllListeners('disconnected');
1717
+ this.webrtc.removeAllListeners('dataChannel');
1718
+ delete this.webrtc;
1719
+ }
1720
1518
- // If there is a upload or download active on this connection, close the file
1519
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
1520
- if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1521
-
1522
- // Clean up WebRTC
1523
- if (this.webrtc != null) {
1524
- 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; }
1525
- if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1526
- try { this.webrtc.close(); } catch (e) { }
1527
- this.webrtc.removeAllListeners('connected');
1528
- this.webrtc.removeAllListeners('disconnected');
1529
- this.webrtc.removeAllListeners('dataChannel');
1530
- delete this.webrtc;
1721
+ // Clean up WebSocket
1722
+ this.removeAllListeners('data');
1723
+}
1724
+function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1725
+function onTunnelData(data)
1726
+{
1727
+ //console.log("OnTunnelData");
1728
+ //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1729
+
1730
+ // If this is upload data, save it to file
1731
+ if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123))
1732
+ {
1733
+ // Save the data to file being uploaded.
1734
+ if (data[0] == 0)
1735
+ {
1736
+ // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1737
+ 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.
1738
+ } else
1739
+ {
1740
+ // If data does not start with zero, save as-is.
1741
+ 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.
1742
}
1743
+ this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
1744
+ return;
1745
+ }
1746
1533
- // Clean up WebSocket
1534
- this.removeAllListeners('data');
1747
+ if (this.httprequest.state == 0)
1748
+ {
1749
+ // Check if this is a relay connection
1750
+ if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1751
}
1536
- function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1537
- function onTunnelData(data) {
1538
- //console.log("OnTunnelData");
1539
- //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1540
-
1541
- // If this is upload data, save it to file
1542
- if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
1543
- // Save the data to file being uploaded.
1544
- if (data[0] == 0) {
1545
- // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1546
- 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.
1547
- } else {
1548
- // If data does not start with zero, save as-is.
1549
- 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.
1752
+ else
1753
+ {
1754
+ // Handle tunnel data
1755
+ if (this.httprequest.protocol == 0)
1756
+ { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
1757
+ // Take a look at the protocol
1758
+ if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1759
+ this.httprequest.protocol = parseInt(data);
1760
+ if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1761
+ if (this.httprequest.protocol == 10)
1762
+ {
1763
+ //
1764
+ // Basic file transfer
1765
+ //
1766
+ var stats = null;
1767
+ if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1768
+ try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1769
+ try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1770
+ if (this.httprequest.downloadFile)
1771
+ {
1772
+ //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1773
+ this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1774
+ this.httprequest.downloadFile.pipe(this);
1775
+ this.httprequest.downloadFile.end = function () { }
1776
+ } else
1777
+ {
1778
+ //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1779
+ this.write(JSON.stringify({ op: 'cancel' }));
1780
+ }
1781
}
1551
- this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
1552
- return;
1553
- }
1782
+ else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
1783
+ {
1784
+ //
1785
+ // Remote Terminal
1786
+ //
1787
1555
- if (this.httprequest.state == 0) {
1556
- // Check if this is a relay connection
1557
- if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1558
- }
1559
- else {
1560
- // Handle tunnel data
1561
- 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
1562
- // Take a look at the protocol
1563
- if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1564
- this.httprequest.protocol = parseInt(data);
1565
- if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1566
- if (this.httprequest.protocol == 10) {
1567
- //
1568
- // Basic file transfer
1569
- //
1570
- var stats = null;
1571
- if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1572
- try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1573
- try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1574
- if (this.httprequest.downloadFile) {
1575
- //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1576
- this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1577
- this.httprequest.downloadFile.pipe(this);
1578
- this.httprequest.downloadFile.end = function () { }
1579
- } else {
1580
- //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1581
- this.write(JSON.stringify({ op: 'cancel' }));
1582
- }
1788
+ // Check user access rights for terminal
1789
+ if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0)))
1790
+ {
1791
+ // Disengage this tunnel, user does not have the rights to do this!!
1792
+ this.httprequest.protocol = 999999;
1793
+ this.httprequest.s.end();
1794
+ sendConsoleText("Error: No Terminal Control Rights.");
1795
+ return;
1796
}
1584
- else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) {
1585
- //
1586
- // Remote Terminal
1587
- //
1588
-
1589
- // Check user access rights for terminal
1590
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1591
- // Disengage this tunnel, user does not have the rights to do this!!
1592
- this.httprequest.protocol = 999999;
1593
- this.httprequest.s.end();
1594
- sendConsoleText("Error: No Terminal Control Rights.");
1595
- return;
1596
- }
1797
1598
- this.descriptorMetadata = "Remote Terminal";
1798
+ this.descriptorMetadata = "Remote Terminal";
1799
1600
- if (process.platform == 'win32') {
1601
- if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) {
1602
- this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1603
- this.httprequest.s.end();
1604
- return;
1605
- }
1800
+ if (process.platform == 'win32')
1801
+ {
1802
+ if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
1803
+ {
1804
+ this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1805
+ this.httprequest.s.end();
1806
+ return;
1807
}
1808
+ }
1809
1608
- var prom = require('promise');
1609
- this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1610
- this.httprequest.tpromise.that = this;
1611
- this.httprequest.tpromise.httprequest = this.httprequest;
1612
-
1613
- this.end = function () {
1614
- if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1615
- if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
1810
+ var prom = require('promise');
1811
+ this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1812
+ this.httprequest.tpromise.that = this;
1813
+ this.httprequest.tpromise.httprequest = this.httprequest;
1814
1617
- // Remove the terminal session to the count to update the server
1618
- if (this.httprequest.userid != null) {
1619
- 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]; } }
1620
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1621
- broadcastSessionsToRegisteredApps();
1622
- }
1815
+ this.end = function ()
1816
+ {
1817
+ if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1818
+ if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
1819
1624
- if (process.platform == 'win32') {
1625
- // Unpipe the web socket
1626
- this.unpipe(this.httprequest._term);
1627
- if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1820
+ // Remove the terminal session to the count to update the server
1821
+ if (this.httprequest.userid != null)
1822
+ {
1823
+ 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]; } }
1824
+ try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1825
+ broadcastSessionsToRegisteredApps();
1826
+ }
1827
1629
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1630
- if (this.rtcchannel) {
1631
- this.rtcchannel.unpipe(this.httprequest._term);
1632
- if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1633
- }
1828
+ if (process.platform == 'win32')
1829
+ {
1830
+ // Unpipe the web socket
1831
+ this.unpipe(this.httprequest._term);
1832
+ if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1833
1635
- // Clean up
1636
- if (this.httprequest._term) { this.httprequest._term.end(); }
1637
- this.httprequest._term = null;
1834
+ // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1835
+ if (this.rtcchannel)
1836
+ {
1837
+ this.rtcchannel.unpipe(this.httprequest._term);
1838
+ if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1839
}
1639
- };
1840
1641
- // Perform User-Consent if needed.
1642
- if (this.httprequest.consent && (this.httprequest.consent & 16)) {
1643
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1644
- var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
1645
- if (this.httprequest.soptions != null) {
1646
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1647
- if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1648
- }
1649
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
1650
- this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1651
- this.httprequest.tpromise._consent.then(
1652
- function () {
1653
- // Success
1654
- MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1655
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1656
- this.retPromise._consent = null;
1657
- this.retPromise._res();
1658
- },
1659
- function (e) {
1660
- // Denied
1661
- MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1662
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1663
- this.retPromise._rej(e.toString());
1664
- });
1841
+ // Clean up
1842
+ if (this.httprequest._term) { this.httprequest._term.end(); }
1843
+ this.httprequest._term = null;
1844
}
1666
- else {
1667
- // User-Consent is not required, so just resolve this promise
1668
- this.httprequest.tpromise._res();
1845
+ };
1846
+
1847
+ // Perform User-Consent if needed.
1848
+ if (this.httprequest.consent && (this.httprequest.consent & 16))
1849
+ {
1850
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1851
+ var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
1852
+ if (this.httprequest.soptions != null)
1853
+ {
1854
+ if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1855
+ if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1856
}
1857
+ this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
1858
+ this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1859
+ this.httprequest.tpromise._consent.then(
1860
+ function ()
1861
+ {
1862
+ // Success
1863
+ MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1864
+ this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1865
+ this.retPromise._consent = null;
1866
+ this.retPromise._res();
1867
+ },
1868
+ function (e)
1869
+ {
1870
+ // Denied
1871
+ MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1872
+ this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1873
+ this.retPromise._rej(e.toString());
1874
+ });
1875
+ }
1876
+ else
1877
+ {
1878
+ // User-Consent is not required, so just resolve this promise
1879
+ this.httprequest.tpromise._res();
1880
+ }
1881
+
1882
1883
+ this.httprequest.tpromise.then(
1884
+ function ()
1885
+ {
1886
+ this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1887
+ this.httprequest.connectionPromise.ws = this.that;
1888
1672
- this.httprequest.tpromise.then(
1673
- function () {
1674
- this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1675
- this.httprequest.connectionPromise.ws = this.that;
1889
+ // Start Terminal
1890
+ if (process.platform == 'win32')
1891
+ {
1892
+ try
1893
+ {
1894
+ var cols = 80, rows = 25;
1895
+ if (this.httprequest.xoptions)
1896
+ {
1897
+ if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1898
+ if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1899
+ }
1900
1677
- // Start Terminal
1678
- if (process.platform == 'win32') {
1679
- try {
1680
- var cols = 80, rows = 25;
1681
- if (this.httprequest.xoptions) {
1682
- if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1683
- if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1901
+ if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1902
+ {
1903
+ // Admin Terminal
1904
+ if (require('win-virtual-terminal').supported)
1905
+ {
1906
+ // ConPTY PseudoTerminal
1907
+ // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1908
+
1909
+ // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1910
+ 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] } });
1911
+ this.httprequest._dispatcher.httprequest = this.httprequest;
1912
+ this.httprequest._dispatcher.on('connection', function (c)
1913
+ {
1914
+ if (this.httprequest.connectionPromise.completed)
1915
+ {
1916
+ c.end();
1917
+ }
1918
+ else
1919
+ {
1920
+ this.httprequest.connectionPromise._res(c);
1921
+ }
1922
+ });
1923
}
1685
-
1686
- if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6)) {
1687
- // Admin Terminal
1688
- if (require('win-virtual-terminal').supported) {
1689
- // ConPTY PseudoTerminal
1690
- // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1691
-
1692
- // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1693
- 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] } });
1694
- this.httprequest._dispatcher.httprequest = this.httprequest;
1695
- this.httprequest._dispatcher.on('connection', function (c) {
1696
- if (this.httprequest.connectionPromise.completed) {
1924
+ else
1925
+ {
1926
+ // Legacy Terminal
1927
+ this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1928
+ }
1929
+ }
1930
+ else
1931
+ {
1932
+ // Logged in user
1933
+ var userPromise = require('user-sessions').enumerateUsers();
1934
+ userPromise.that = this;
1935
+ userPromise.then(function (u)
1936
+ {
1937
+ var that = this.that;
1938
+ if (u.Active.length > 0)
1939
+ {
1940
+ var username = u.Active[0].Username;
1941
+ if (require('win-virtual-terminal').supported)
1942
+ {
1943
+ // ConPTY PseudoTerminal
1944
+ 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] } });
1945
+ }
1946
+ else
1947
+ {
1948
+ // Legacy Terminal
1949
+ 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] } });
1950
+ }
1951
+ that.httprequest._dispatcher.ws = that;
1952
+ that.httprequest._dispatcher.on('connection', function (c)
1953
+ {
1954
+ if (this.ws.httprequest.connectionPromise.completed)
1955
+ {
1956
c.end();
1957
}
1699
- else {
1700
- this.httprequest.connectionPromise._res(c);
1958
+ else
1959
+ {
1960
+ this.ws.httprequest.connectionPromise._res(c);
1961
}
1962
});
1963
}
1704
- else {
1705
- // Legacy Terminal
1706
- this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1707
- }
1708
- }
1709
- else {
1710
- // Logged in user
1711
- var userPromise = require('user-sessions').enumerateUsers();
1712
- userPromise.that = this;
1713
- userPromise.then(function (u) {
1714
- var that = this.that;
1715
- if (u.Active.length > 0) {
1716
- var username = u.Active[0].Username;
1717
- if (require('win-virtual-terminal').supported) {
1718
- // ConPTY PseudoTerminal
1719
- 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] } });
1720
- }
1721
- else {
1722
- // Legacy Terminal
1723
- 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] } });
1724
- }
1725
- that.httprequest._dispatcher.ws = that;
1726
- that.httprequest._dispatcher.on('connection', function (c) {
1727
- if (this.ws.httprequest.connectionPromise.completed) {
1728
- c.end();
1729
- }
1730
- else {
1731
- this.ws.httprequest.connectionPromise._res(c);
1732
- }
1733
- });
1734
- }
1735
- });
1736
- }
1737
- }
1738
- catch (e) {
1739
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1964
+ });
1965
}
1966
}
1742
- else {
1743
- try {
1744
- var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1745
- var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1746
- var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1747
-
1748
- var env = { HISTCONTROL: 'ignoreboth' };
1749
- if (this.httprequest.xoptions) {
1750
- if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1751
- if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1752
- }
1753
- var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1754
- if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin) {
1755
- if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1756
- this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1757
- }
1758
- else if (bash) {
1759
- var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1760
- // Spaces at the beginning of lines are needed to hide commands from the command history
1761
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1762
- this.httprequest.connectionPromise._res(p);
1763
- }
1764
- else if (sh) {
1765
- var p = childProcess.execFile(sh, ['sh'], options); // Start sh
1766
- // Spaces at the beginning of lines are needed to hide commands from the command history
1767
- if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1768
- this.httprequest.connectionPromise._res(p);
1769
- }
1770
- else {
1771
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
1772
- }
1967
+ catch (e)
1968
+ {
1969
+ this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1970
+ }
1971
+ }
1972
+ else
1973
+ {
1974
+ try
1975
+ {
1976
+ var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1977
+ var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1978
+ var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1979
+
1980
+ var env = { HISTCONTROL: 'ignoreboth' };
1981
+ if (this.httprequest.xoptions)
1982
+ {
1983
+ if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1984
+ if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1985
+ }
1986
+ var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1987
+ if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1988
+ {
1989
+ if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1990
+ this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1991
+ }
1992
+ else if (bash)
1993
+ {
1994
+ var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1995
+ // Spaces at the beginning of lines are needed to hide commands from the command history
1996
+ if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1997
+ this.httprequest.connectionPromise._res(p);
1998
+ }
1999
+ else if (sh)
2000
+ {
2001
+ var p = childProcess.execFile(sh, ['sh'], options); // Start sh
2002
+ // Spaces at the beginning of lines are needed to hide commands from the command history
2003
+ if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
2004
+ this.httprequest.connectionPromise._res(p);
2005
}
1774
- catch (e) {
1775
- this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
2006
+ else
2007
+ {
2008
+ this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
2009
}
2010
}
2011
+ catch (e)
2012
+ {
2013
+ this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
2014
+ }
2015
+ }
2016
1779
- this.httprequest.connectionPromise.then(
1780
- function (term) {
1781
- // SUCCESS
1782
- var stdoutstream;
1783
- var stdinstream;
1784
- if (process.platform == 'win32') {
1785
- this.ws.httprequest._term = term;
1786
- this.ws.httprequest._term.tunnel = this.ws;
1787
- stdoutstream = stdinstream = term;
1788
- }
1789
- else {
1790
- term.descriptorMetadata = 'Remote Terminal';
1791
- this.ws.httprequest.process = term;
1792
- this.ws.httprequest.process.tunnel = this.ws;
1793
- term.stderr.stdout = term.stdout;
1794
- term.stderr.on('data', function (c) { this.stdout.write(c); });
1795
- stdoutstream = term.stdout;
1796
- stdinstream = term.stdin;
1797
- this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
1798
- term.prependListener('exit', function () { this.tunnel.end(); });
1799
- }
2017
+ this.httprequest.connectionPromise.then(
2018
+ function (term)
2019
+ {
2020
+ // SUCCESS
2021
+ var stdoutstream;
2022
+ var stdinstream;
2023
+ if (process.platform == 'win32')
2024
+ {
2025
+ this.ws.httprequest._term = term;
2026
+ this.ws.httprequest._term.tunnel = this.ws;
2027
+ stdoutstream = stdinstream = term;
2028
+ }
2029
+ else
2030
+ {
2031
+ term.descriptorMetadata = 'Remote Terminal';
2032
+ this.ws.httprequest.process = term;
2033
+ this.ws.httprequest.process.tunnel = this.ws;
2034
+ term.stderr.stdout = term.stdout;
2035
+ term.stderr.on('data', function (c) { this.stdout.write(c); });
2036
+ stdoutstream = term.stdout;
2037
+ stdinstream = term.stdin;
2038
+ this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
2039
+ term.prependListener('exit', function () { this.tunnel.end(); });
2040
+ }
2041
1801
- this.ws.removeAllListeners('data');
1802
- this.ws.on('data', onTunnelControlData);
2042
+ this.ws.removeAllListeners('data');
2043
+ this.ws.on('data', onTunnelControlData);
2044
1804
- stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
1805
- this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2045
+ stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2046
+ this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2047
1807
- // Add the terminal session to the count to update the server
1808
- if (this.ws.httprequest.userid != null) {
1809
- if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
1810
- try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1811
- broadcastSessionsToRegisteredApps();
1812
- }
2048
+ // Add the terminal session to the count to update the server
2049
+ if (this.ws.httprequest.userid != null)
2050
+ {
2051
+ if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
2052
+ try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
2053
+ broadcastSessionsToRegisteredApps();
2054
+ }
2055
1814
- // Toast Notification, if required
1815
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
1816
- // User Notifications is required
1817
- var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
1818
- if (this.ws.httprequest.soptions != null) {
1819
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1820
- 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); }
1821
- }
1822
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2056
+ // Toast Notification, if required
2057
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
2058
+ {
2059
+ // User Notifications is required
2060
+ var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
2061
+ if (this.ws.httprequest.soptions != null)
2062
+ {
2063
+ if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2064
+ 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); }
2065
}
1824
- },
1825
- function (e) {
1826
- // FAILED to connect terminal
1827
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1828
- this.ws.end();
1829
- });
1830
- },
1831
- function (e) {
1832
- // DO NOT start terminal
1833
- this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1834
- this.that.end();
1835
- });
2066
+ try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2067
+ }
2068
+ },
2069
+ function (e)
2070
+ {
2071
+ // FAILED to connect terminal
2072
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2073
+ this.ws.end();
2074
+ });
2075
+ },
2076
+ function (e)
2077
+ {
2078
+ // DO NOT start terminal
2079
+ this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2080
+ this.that.end();
2081
+ });
2082
+ }
2083
+ else if (this.httprequest.protocol == 2)
2084
+ {
2085
+ //
2086
+ // Remote KVM
2087
+ //
2088
+
2089
+ // Check user access rights for desktop
2090
+ if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0)))
2091
+ {
2092
+ // Disengage this tunnel, user does not have the rights to do this!!
2093
+ this.httprequest.protocol = 999999;
2094
+ this.httprequest.s.end();
2095
+ sendConsoleText("Error: No Desktop Control Rights.");
2096
+ return;
2097
}
1837
- else if (this.httprequest.protocol == 2) {
1838
- //
1839
- // Remote KVM
1840
- //
1841
-
1842
- // Check user access rights for desktop
1843
- if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
1844
- // Disengage this tunnel, user does not have the rights to do this!!
1845
- this.httprequest.protocol = 999999;
1846
- this.httprequest.s.end();
1847
- sendConsoleText("Error: No Desktop Control Rights.");
1848
- return;
1849
- }
2098
1851
- this.descriptorMetadata = "Remote KVM";
2099
+ this.descriptorMetadata = "Remote KVM";
2100
+
2101
+ // Look for a TSID
2102
+ var tsid = null;
2103
+ if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
2104
+ require('MeshAgent')._tsid = tsid;
2105
1853
- // Look for a TSID
1854
- var tsid = null;
1855
- if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
1856
- require('MeshAgent')._tsid = tsid;
2106
+ // Remote desktop using native pipes
2107
+ this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this };
2108
+ this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
2109
+ this.desktop = this.httprequest.desktop;
2110
1858
- // Remote desktop using native pipes
1859
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this };
1860
- this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
1861
- this.desktop = this.httprequest.desktop;
2111
+ // Add ourself to the list of remote desktop sessions
2112
+ if (this.httprequest.desktop.kvm.tunnels == null) { this.httprequest.desktop.kvm.tunnels = []; }
2113
+ this.httprequest.desktop.kvm.tunnels.push(this);
2114
1863
- // Add ourself to the list of remote desktop sessions
1864
- if (this.httprequest.desktop.kvm.tunnels == null) { this.httprequest.desktop.kvm.tunnels = []; }
1865
- this.httprequest.desktop.kvm.tunnels.push(this);
2115
+ // Send a metadata update to all desktop sessions
2116
+ var users = {};
2117
+ if (this.httprequest.desktop.kvm.tunnels != null)
2118
+ {
2119
+ 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) { } }
2120
+ 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) { } }
2121
+ tunnelUserCount.desktop = users;
2122
+ try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
2123
+ broadcastSessionsToRegisteredApps();
2124
+ }
2125
+
2126
+ this.end = function ()
2127
+ {
2128
+ --this.desktop.kvm.connectionCount;
2129
+
2130
+ // Remove ourself from the list of remote desktop session
2131
+ var i = this.desktop.kvm.tunnels.indexOf(this);
2132
+ if (i >= 0) { this.desktop.kvm.tunnels.splice(i, 1); }
2133
2134
// Send a metadata update to all desktop sessions
2135
var users = {};
1869
- if (this.httprequest.desktop.kvm.tunnels != null) {
2136
+ if (this.httprequest.desktop.kvm.tunnels != null)
2137
+ {
2138
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) { } }
2139
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) { } }
2140
tunnelUserCount.desktop = users;
@@ -1874,1258 +2142,1444 @@ function createMeshCore(agent) {
2142
broadcastSessionsToRegisteredApps();
2143
}
2144
1877
- this.end = function () {
1878
- --this.desktop.kvm.connectionCount;
1879
-
1880
- // Remove ourself from the list of remote desktop session
1881
- var i = this.desktop.kvm.tunnels.indexOf(this);
1882
- if (i >= 0) { this.desktop.kvm.tunnels.splice(i, 1); }
1883
-
1884
- // Send a metadata update to all desktop sessions
1885
- var users = {};
1886
- if (this.httprequest.desktop.kvm.tunnels != null) {
1887
- 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) { } }
1888
- 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) { } }
1889
- tunnelUserCount.desktop = users;
1890
- try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
1891
- broadcastSessionsToRegisteredApps();
1892
- }
2145
+ // Unpipe the web socket
2146
+ try
2147
+ {
2148
+ this.unpipe(this.httprequest.desktop.kvm);
2149
+ this.httprequest.desktop.kvm.unpipe(this);
2150
+ }
2151
+ catch (e) { }
2152
1894
- // Unpipe the web socket
1895
- try {
1896
- this.unpipe(this.httprequest.desktop.kvm);
1897
- this.httprequest.desktop.kvm.unpipe(this);
2153
+ // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
2154
+ if (this.rtcchannel)
2155
+ {
2156
+ try
2157
+ {
2158
+ this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
2159
+ this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
2160
}
2161
catch (e) { }
2162
+ }
2163
1901
- // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1902
- if (this.rtcchannel) {
1903
- try {
1904
- this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
1905
- this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
1906
- }
1907
- catch (e) { }
1908
- }
1909
-
1910
- // Place wallpaper back if needed
1911
- // TODO
2164
+ // Place wallpaper back if needed
2165
+ // TODO
2166
1913
- if (this.desktop.kvm.connectionCount == 0) {
1914
- // Display a toast message. This may not be supported on all platforms.
1915
- // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
2167
+ if (this.desktop.kvm.connectionCount == 0)
2168
+ {
2169
+ // Display a toast message. This may not be supported on all platforms.
2170
+ // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
2171
1917
- this.httprequest.desktop.kvm.end();
1918
- if (this.httprequest.desktop.kvm.connectionBar) {
1919
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1920
- this.httprequest.desktop.kvm.connectionBar.close();
1921
- this.httprequest.desktop.kvm.connectionBar = null;
1922
- }
1923
- } else {
1924
- for (var i in this.httprequest.desktop.kvm.users) {
1925
- if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar) {
1926
- 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; } }
1927
- this.httprequest.desktop.kvm.users.splice(i, 1);
1928
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1929
- this.httprequest.desktop.kvm.connectionBar.close();
1930
- 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);
1931
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
1932
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1933
- MeshServerLogEx(29, 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
- break;
1940
- }
2172
+ this.httprequest.desktop.kvm.end();
2173
+ if (this.httprequest.desktop.kvm.connectionBar)
2174
+ {
2175
+ this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2176
+ this.httprequest.desktop.kvm.connectionBar.close();
2177
+ this.httprequest.desktop.kvm.connectionBar = null;
2178
+ }
2179
+ } else
2180
+ {
2181
+ for (var i in this.httprequest.desktop.kvm.users)
2182
+ {
2183
+ if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar)
2184
+ {
2185
+ 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; } }
2186
+ this.httprequest.desktop.kvm.users.splice(i, 1);
2187
+ this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2188
+ this.httprequest.desktop.kvm.connectionBar.close();
2189
+ 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);
2190
+ this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2191
+ this.httprequest.desktop.kvm.connectionBar.on('close', function ()
2192
+ {
2193
+ MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2194
+ for (var i in this.httprequest.desktop.kvm._pipedStreams)
2195
+ {
2196
+ this.httprequest.desktop.kvm._pipedStreams[i].end();
2197
+ }
2198
+ this.httprequest.desktop.kvm.end();
2199
+ });
2200
+ break;
2201
}
2202
}
1943
- };
1944
- if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
1945
- this.httprequest.desktop.kvm.connectionCount++;
1946
- this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
1947
- this.httprequest.desktop.kvm.users.push(this.httprequest.username);
1948
- this.httprequest.desktop.kvm.rusers.sort();
1949
- this.httprequest.desktop.kvm.users.sort();
1950
- } else {
1951
- this.httprequest.desktop.kvm.connectionCount = 1;
1952
- this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
1953
- this.httprequest.desktop.kvm.users = [this.httprequest.username];
2203
}
2204
+ };
2205
+ if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount'))
2206
+ {
2207
+ this.httprequest.desktop.kvm.connectionCount++;
2208
+ this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
2209
+ this.httprequest.desktop.kvm.users.push(this.httprequest.username);
2210
+ this.httprequest.desktop.kvm.rusers.sort();
2211
+ this.httprequest.desktop.kvm.users.sort();
2212
+ } else
2213
+ {
2214
+ this.httprequest.desktop.kvm.connectionCount = 1;
2215
+ this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
2216
+ this.httprequest.desktop.kvm.users = [this.httprequest.username];
2217
+ }
2218
1956
- if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
1957
- // If we have remote control rights, pipe the KVM input
1958
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
1959
- } else {
1960
- // We need to only pipe non-mouse & non-keyboard inputs.
1961
- //sendConsoleText('Warning: No Remote Desktop Input Rights.');
1962
- // TODO!!!
1963
- }
2219
+ if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)))
2220
+ {
2221
+ // If we have remote control rights, pipe the KVM input
2222
+ this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
2223
+ } else
2224
+ {
2225
+ // We need to only pipe non-mouse & non-keyboard inputs.
2226
+ //sendConsoleText('Warning: No Remote Desktop Input Rights.');
2227
+ // TODO!!!
2228
+ }
2229
1965
- // Perform notification if needed. Toast messages may not be supported on all platforms.
1966
- if (this.httprequest.consent && (this.httprequest.consent & 8)) {
1967
- // User Consent Prompt is required
1968
- // Send a console message back using the console channel, "\n" is supported.
1969
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1970
- var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
1971
- if (this.httprequest.soptions != null) {
1972
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1973
- if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1974
- }
1975
- var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
1976
- pr.ws = this;
1977
- this.pause();
1978
- this._consentpromise = pr;
1979
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
1980
- pr.then(
1981
- function () {
1982
- // Success
1983
- this.ws._consentpromise = null;
1984
- MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1985
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1986
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
1987
- // User Notifications is required
1988
- var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1989
- if (this.ws.httprequest.soptions != null) {
1990
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1991
- 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); }
1992
- }
1993
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2230
+ // Perform notification if needed. Toast messages may not be supported on all platforms.
2231
+ if (this.httprequest.consent && (this.httprequest.consent & 8))
2232
+ {
2233
+ // User Consent Prompt is required
2234
+ // Send a console message back using the console channel, "\n" is supported.
2235
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2236
+ var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
2237
+ if (this.httprequest.soptions != null)
2238
+ {
2239
+ if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2240
+ if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2241
+ }
2242
+ var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
2243
+ pr.ws = this;
2244
+ this.pause();
2245
+ this._consentpromise = pr;
2246
+ this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2247
+ pr.then(
2248
+ function ()
2249
+ {
2250
+ // Success
2251
+ this.ws._consentpromise = null;
2252
+ MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2253
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2254
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1))
2255
+ {
2256
+ // User Notifications is required
2257
+ var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
2258
+ if (this.ws.httprequest.soptions != null)
2259
+ {
2260
+ if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2261
+ 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); }
2262
}
1995
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40)) {
1996
- // Connection Bar is required
1997
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
1998
- this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1999
- this.ws.httprequest.desktop.kvm.connectionBar.close();
2000
- }
2001
- try {
2002
- 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);
2003
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2263
+ try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2264
+ }
2265
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40))
2266
+ {
2267
+ // Connection Bar is required
2268
+ if (this.ws.httprequest.desktop.kvm.connectionBar)
2269
+ {
2270
+ this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2271
+ this.ws.httprequest.desktop.kvm.connectionBar.close();
2272
+ }
2273
+ try
2274
+ {
2275
+ 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);
2276
+ MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2277
+ }
2278
+ catch (e)
2279
+ {
2280
+ if (process.platform != 'darwin')
2281
+ {
2282
+ MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2283
}
2005
- catch (e) {
2006
- if (process.platform != 'darwin') {
2007
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2284
+ }
2285
+ if (this.ws.httprequest.desktop.kvm.connectionBar)
2286
+ {
2287
+ this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
2288
+ this.ws.httprequest.desktop.kvm.connectionBar.on('close', function ()
2289
+ {
2290
+ MeshServerLogEx(33, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2291
+ for (var i in this.httprequest.desktop.kvm._pipedStreams)
2292
+ {
2293
+ this.httprequest.desktop.kvm._pipedStreams[i].end();
2294
}
2009
- }
2010
- if (this.ws.httprequest.desktop.kvm.connectionBar) {
2011
- this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
2012
- this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
2013
- MeshServerLogEx(33, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2014
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2015
- this.httprequest.desktop.kvm._pipedStreams[i].end();
2016
- }
2017
- this.httprequest.desktop.kvm.end();
2018
- });
2019
- }
2295
+ this.httprequest.desktop.kvm.end();
2296
+ });
2297
}
2021
- this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
2022
- this.ws.resume();
2023
- },
2024
- function (e) {
2025
- // User Consent Denied/Failed
2026
- this.ws._consentpromise = null;
2027
- MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2028
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2029
- });
2030
- } else {
2031
- // User Consent Prompt is not required
2032
- if (this.httprequest.consent && (this.httprequest.consent & 1)) {
2033
- // User Notifications is required
2034
- MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2035
- var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
2036
- if (this.httprequest.soptions != null) {
2037
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2038
- if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2298
}
2040
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2041
- } else {
2042
- MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2299
+ this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
2300
+ this.ws.resume();
2301
+ },
2302
+ function (e)
2303
+ {
2304
+ // User Consent Denied/Failed
2305
+ this.ws._consentpromise = null;
2306
+ MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2307
+ this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2308
+ });
2309
+ } else
2310
+ {
2311
+ // User Consent Prompt is not required
2312
+ if (this.httprequest.consent && (this.httprequest.consent & 1))
2313
+ {
2314
+ // User Notifications is required
2315
+ MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2316
+ var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
2317
+ if (this.httprequest.soptions != null)
2318
+ {
2319
+ if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2320
+ if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2321
}
2044
- if (this.httprequest.consent && (this.httprequest.consent & 0x40)) {
2045
- // Connection Bar is required
2046
- if (this.httprequest.desktop.kvm.connectionBar) {
2047
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2048
- this.httprequest.desktop.kvm.connectionBar.close();
2049
- }
2050
- try {
2051
- 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);
2052
- MeshServerLogEx(37, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
2053
- }
2054
- catch (e) {
2055
- MeshServerLogEx(38, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
2056
- }
2057
- if (this.httprequest.desktop.kvm.connectionBar) {
2058
- this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2059
- this.httprequest.desktop.kvm.connectionBar.on('close', function () {
2060
- MeshServerLogEx(39, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2061
- for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2062
- this.httprequest.desktop.kvm._pipedStreams[i].end();
2063
- }
2064
- this.httprequest.desktop.kvm.end();
2065
- });
2066
- }
2322
+ try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2323
+ } else
2324
+ {
2325
+ MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2326
+ }
2327
+ if (this.httprequest.consent && (this.httprequest.consent & 0x40))
2328
+ {
2329
+ // Connection Bar is required
2330
+ if (this.httprequest.desktop.kvm.connectionBar)
2331
+ {
2332
+ this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2333
+ this.httprequest.desktop.kvm.connectionBar.close();
2334
+ }
2335
+ try
2336
+ {
2337
+ 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);
2338
+ MeshServerLogEx(37, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
2339
+ }
2340
+ catch (e)
2341
+ {
2342
+ MeshServerLogEx(38, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
2343
+ }
2344
+ if (this.httprequest.desktop.kvm.connectionBar)
2345
+ {
2346
+ this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2347
+ this.httprequest.desktop.kvm.connectionBar.on('close', function ()
2348
+ {
2349
+ MeshServerLogEx(39, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2350
+ for (var i in this.httprequest.desktop.kvm._pipedStreams)
2351
+ {
2352
+ this.httprequest.desktop.kvm._pipedStreams[i].end();
2353
+ }
2354
+ this.httprequest.desktop.kvm.end();
2355
+ });
2356
}
2068
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
2357
}
2358
+ this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
2359
+ }
2360
2071
- this.removeAllListeners('data');
2072
- this.on('data', onTunnelControlData);
2073
- //this.write('MeshCore KVM Hello!1');
2361
+ this.removeAllListeners('data');
2362
+ this.on('data', onTunnelControlData);
2363
+ //this.write('MeshCore KVM Hello!1');
2364
2075
- } else if (this.httprequest.protocol == 5) {
2076
- //
2077
- // Remote Files
2078
- //
2365
+ } else if (this.httprequest.protocol == 5)
2366
+ {
2367
+ //
2368
+ // Remote Files
2369
+ //
2370
2080
- // Check user access rights for files
2081
- if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
2082
- // Disengage this tunnel, user does not have the rights to do this!!
2083
- this.httprequest.protocol = 999999;
2084
- this.httprequest.s.end();
2085
- sendConsoleText("Error: No files control rights.");
2086
- return;
2087
- }
2371
+ // Check user access rights for files
2372
+ if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0)))
2373
+ {
2374
+ // Disengage this tunnel, user does not have the rights to do this!!
2375
+ this.httprequest.protocol = 999999;
2376
+ this.httprequest.s.end();
2377
+ sendConsoleText("Error: No files control rights.");
2378
+ return;
2379
+ }
2380
2089
- this.descriptorMetadata = "Remote Files";
2381
+ this.descriptorMetadata = "Remote Files";
2382
2091
- // Add the files session to the count to update the server
2092
- if (this.httprequest.userid != null) {
2093
- if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
2383
+ // Add the files session to the count to update the server
2384
+ if (this.httprequest.userid != null)
2385
+ {
2386
+ if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
2387
+ try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2388
+ broadcastSessionsToRegisteredApps();
2389
+ }
2390
+
2391
+ this.end = function ()
2392
+ {
2393
+ // Remove the files session from the count to update the server
2394
+ if (this.httprequest.userid != null)
2395
+ {
2396
+ 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]; } }
2397
try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2398
broadcastSessionsToRegisteredApps();
2399
}
2400
+ };
2401
2098
- this.end = function () {
2099
- // Remove the files session from the count to update the server
2100
- if (this.httprequest.userid != null) {
2101
- 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]; } }
2102
- try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2103
- broadcastSessionsToRegisteredApps();
2104
- }
2105
- };
2106
-
2107
- // Perform notification if needed. Toast messages may not be supported on all platforms.
2108
- if (this.httprequest.consent && (this.httprequest.consent & 32)) {
2109
- // User Consent Prompt is required
2110
- // Send a console message back using the console channel, "\n" is supported.
2111
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2112
- var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
2113
- if (this.httprequest.soptions != null) {
2114
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2115
- if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2116
- }
2117
- var pr = require('message-box').create(consentTitle, consentMessage, 30);
2118
- pr.ws = this;
2119
- this.pause();
2120
- this._consentpromise = pr;
2121
- this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2122
- pr.then(
2123
- function () {
2124
- // Success
2125
- this.ws._consentpromise = null;
2126
- MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2127
- this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2128
- if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
2129
- // User Notifications is required
2130
- var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2131
- if (this.ws.httprequest.soptions != null) {
2132
- if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2133
- 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); }
2134
- }
2135
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2402
+ // Perform notification if needed. Toast messages may not be supported on all platforms.
2403
+ if (this.httprequest.consent && (this.httprequest.consent & 32))
2404
+ {
2405
+ // User Consent Prompt is required
2406
+ // Send a console message back using the console channel, "\n" is supported.
2407
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2408
+ var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
2409
+ if (this.httprequest.soptions != null)
2410
+ {
2411
+ if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2412
+ if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2413
+ }
2414
+ var pr = require('message-box').create(consentTitle, consentMessage, 30);
2415
+ pr.ws = this;
2416
+ this.pause();
2417
+ this._consentpromise = pr;
2418
+ this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2419
+ pr.then(
2420
+ function ()
2421
+ {
2422
+ // Success
2423
+ this.ws._consentpromise = null;
2424
+ MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2425
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2426
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4))
2427
+ {
2428
+ // User Notifications is required
2429
+ var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2430
+ if (this.ws.httprequest.soptions != null)
2431
+ {
2432
+ if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2433
+ 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); }
2434
}
2137
- this.ws.resume();
2138
- },
2139
- function (e) {
2140
- // User Consent Denied/Failed
2141
- this.ws._consentpromise = null;
2142
- MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2143
- this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2144
- });
2145
- } else {
2146
- // User Consent Prompt is not required
2147
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
2148
- // User Notifications is required
2149
- MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2150
- var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2151
- if (this.httprequest.soptions != null) {
2152
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2153
- if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2435
+ try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2436
}
2155
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2156
- } else {
2157
- MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2437
+ this.ws.resume();
2438
+ },
2439
+ function (e)
2440
+ {
2441
+ // User Consent Denied/Failed
2442
+ this.ws._consentpromise = null;
2443
+ MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2444
+ this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2445
+ });
2446
+ } else
2447
+ {
2448
+ // User Consent Prompt is not required
2449
+ if (this.httprequest.consent && (this.httprequest.consent & 4))
2450
+ {
2451
+ // User Notifications is required
2452
+ MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2453
+ var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2454
+ if (this.httprequest.soptions != null)
2455
+ {
2456
+ if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2457
+ if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2458
}
2159
- this.resume();
2459
+ try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2460
+ } else
2461
+ {
2462
+ MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2463
}
2464
+ this.resume();
2465
+ }
2466
2162
- // Setup files
2163
- // NOP
2467
+ // Setup files
2468
+ // NOP
2469
+ }
2470
+ } else if (this.httprequest.protocol == 1)
2471
+ {
2472
+ // Send data into terminal stdin
2473
+ //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2474
+ } else if (this.httprequest.protocol == 2)
2475
+ {
2476
+ // Send data into remote desktop
2477
+ if (this.httprequest.desktop.state == 0)
2478
+ {
2479
+ this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2480
+ this.httprequest.desktop.state = 1;
2481
+ } else
2482
+ {
2483
+ this.httprequest.desktop.write(data);
2484
+ }
2485
+ } else if (this.httprequest.protocol == 5)
2486
+ {
2487
+ // Process files commands
2488
+ var cmd = null;
2489
+ try { cmd = JSON.parse(data); } catch (e) { };
2490
+ if (cmd == null) { return; }
2491
+ if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2492
+ if (cmd.action == undefined) { return; }
2493
+ //sendConsoleText('CMD: ' + JSON.stringify(cmd));
2494
+
2495
+ if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2496
+ //console.log(objToString(cmd, 0, ' '));
2497
+ switch (cmd.action)
2498
+ {
2499
+ case 'ls': {
2500
+ /*
2501
+ // Close the watcher if required
2502
+ var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
2503
+ if ((this.httprequest.watcher != undefined) && (samepath == false)) {
2504
+ //console.log('Closing watcher: ' + this.httprequest.watcher.path);
2505
+ //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
2506
+ delete this.httprequest.watcher;
2507
+ }
2508
+ */
2509
+
2510
+ // Send the folder content to the browser
2511
+ var response = getDirectoryInfo(cmd.path);
2512
+ if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
2513
+ this.write(Buffer.from(JSON.stringify(response)));
2514
+
2515
+ /*
2516
+ // Start the directory watcher
2517
+ if ((cmd.path != '') && (samepath == false)) {
2518
+ var watcher = fs.watch(cmd.path, onFileWatcher);
2519
+ watcher.tunnel = this.httprequest;
2520
+ watcher.path = cmd.path;
2521
+ this.httprequest.watcher = watcher;
2522
+ //console.log('Starting watcher: ' + this.httprequest.watcher.path);
2523
+ }
2524
+ */
2525
+ break;
2526
}
2165
- } else if (this.httprequest.protocol == 1) {
2166
- // Send data into terminal stdin
2167
- //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2168
- } else if (this.httprequest.protocol == 2) {
2169
- // Send data into remote desktop
2170
- if (this.httprequest.desktop.state == 0) {
2171
- this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2172
- this.httprequest.desktop.state = 1;
2173
- } else {
2174
- this.httprequest.desktop.write(data);
2527
+ case 'mkdir': {
2528
+ // Create a new empty folder
2529
+ fs.mkdirSync(cmd.path);
2530
+ MeshServerLogEx(44, [cmd.path], "Create folder: \"" + cmd.path + "\"", this.httprequest);
2531
+ break;
2532
}
2176
- } else if (this.httprequest.protocol == 5) {
2177
- // Process files commands
2178
- var cmd = null;
2179
- try { cmd = JSON.parse(data); } catch (e) { };
2180
- if (cmd == null) { return; }
2181
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2182
- if (cmd.action == undefined) { return; }
2183
- //sendConsoleText('CMD: ' + JSON.stringify(cmd));
2184
-
2185
- if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2186
- //console.log(objToString(cmd, 0, ' '));
2187
- switch (cmd.action) {
2188
- case 'ls': {
2189
- /*
2190
- // Close the watcher if required
2191
- var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
2192
- if ((this.httprequest.watcher != undefined) && (samepath == false)) {
2193
- //console.log('Closing watcher: ' + this.httprequest.watcher.path);
2194
- //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
2195
- delete this.httprequest.watcher;
2196
- }
2197
- */
2198
-
2199
- // Send the folder content to the browser
2200
- var response = getDirectoryInfo(cmd.path);
2201
- if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
2202
- this.write(Buffer.from(JSON.stringify(response)));
2203
-
2204
- /*
2205
- // Start the directory watcher
2206
- if ((cmd.path != '') && (samepath == false)) {
2207
- var watcher = fs.watch(cmd.path, onFileWatcher);
2208
- watcher.tunnel = this.httprequest;
2209
- watcher.path = cmd.path;
2210
- this.httprequest.watcher = watcher;
2211
- //console.log('Starting watcher: ' + this.httprequest.watcher.path);
2533
+ case 'rm': {
2534
+ // Delete, possibly recursive delete
2535
+ for (var i in cmd.delfiles)
2536
+ {
2537
+ var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2538
+ try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2539
+ if ((delcount == 1) && !cmd.rec)
2540
+ {
2541
+ MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2542
+ } else
2543
+ {
2544
+ if (cmd.rec)
2545
+ {
2546
+ MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2547
+ } else
2548
+ {
2549
+ MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2550
+ }
2551
}
2213
- */
2214
- break;
2552
}
2216
- case 'mkdir': {
2217
- // Create a new empty folder
2218
- fs.mkdirSync(cmd.path);
2219
- MeshServerLogEx(44, [cmd.path], "Create folder: \"" + cmd.path + "\"", this.httprequest);
2553
+ break;
2554
+ }
2555
+ case 'markcoredump': {
2556
+ // If we are asking for the coredump file, set the right path.
2557
+ var coreDumpPath = null;
2558
+ if (process.platform == 'win32')
2559
+ {
2560
+ if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2561
+ } else
2562
+ {
2563
+ if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2564
+ }
2565
+ if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
2566
+ break;
2567
+ }
2568
+ case 'rename':
2569
+ {
2570
+ // Rename a file or folder
2571
+ var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
2572
+ var newfullpath = obj.path.join(cmd.path, cmd.newname);
2573
+ MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
2574
+ try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
2575
break;
2576
}
2222
- case 'rm': {
2223
- // Delete, possibly recursive delete
2224
- for (var i in cmd.delfiles) {
2225
- var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2226
- try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2227
- if ((delcount == 1) && !cmd.rec) {
2228
- MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2229
- } else {
2230
- if (cmd.rec) {
2231
- MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2232
- } else {
2233
- MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2234
- }
2235
- }
2236
- }
2577
+ case 'findfile':
2578
+ {
2579
+ // Search for files
2580
+ var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
2581
+ if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
2582
+ this._search = r;
2583
+ r.socket = this;
2584
+ r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
2585
+ r.socket.path = cmd.path; // Search path
2586
+ r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
2587
+ r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
2588
break;
2589
}
2239
- case 'markcoredump': {
2240
- // If we are asking for the coredump file, set the right path.
2241
- var coreDumpPath = null;
2242
- if (process.platform == 'win32') {
2243
- if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2244
- } else {
2245
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2246
- }
2247
- if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
2590
+ case 'cancelfindfile':
2591
+ {
2592
+ if (this._search) { this._search.cancel(); this._search = null; }
2593
break;
2594
}
2250
- case 'rename':
2251
- {
2252
- // Rename a file or folder
2253
- var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
2254
- var newfullpath = obj.path.join(cmd.path, cmd.newname);
2255
- MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
2256
- try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
2257
- break;
2258
- }
2259
- case 'findfile':
2260
- {
2261
- // Search for files
2262
- var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
2263
- if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
2264
- this._search = r;
2265
- r.socket = this;
2266
- r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
2267
- r.socket.path = cmd.path; // Search path
2268
- r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
2269
- r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
2270
- break;
2271
- }
2272
- case 'cancelfindfile':
2273
- {
2274
- if (this._search) { this._search.cancel(); this._search = null; }
2275
- break;
2276
- }
2277
- case 'download':
2278
- {
2279
- // Download a file
2280
- var sendNextBlock = 0;
2281
- if (cmd.sub == 'start') { // Setup the download
2282
- if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
2283
- if (process.platform == 'win32') {
2284
- if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2285
- } else {
2286
- if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2287
- }
2595
+ case 'download':
2596
+ {
2597
+ // Download a file
2598
+ var sendNextBlock = 0;
2599
+ if (cmd.sub == 'start')
2600
+ { // Setup the download
2601
+ if ((cmd.path == null) && (cmd.ask == 'coredump'))
2602
+ { // If we are asking for the coredump file, set the right path.
2603
+ if (process.platform == 'win32')
2604
+ {
2605
+ if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2606
+ } else
2607
+ {
2608
+ if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2609
}
2289
- MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
2290
- if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2291
- this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2292
- 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; }
2293
- if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2294
- } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
2295
- 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; }
2610
}
2297
- // Send the next download block(s)
2298
- while (sendNextBlock > 0) {
2299
- sendNextBlock--;
2300
- var buf = Buffer.alloc(16384);
2301
- var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
2302
- this.filedownload.ptr += len;
2303
- if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
2304
- this.write(buf.slice(0, len + 4)); // Write as binary
2305
- }
2306
- break;
2611
+ MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
2612
+ if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2613
+ this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2614
+ 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; }
2615
+ if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2616
+ } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id))
2617
+ { // Download commands
2618
+ 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; }
2619
}
2308
- case 'upload':
2620
+ // Send the next download block(s)
2621
+ while (sendNextBlock > 0)
2622
{
2310
- // Upload a file, browser to agent
2311
- if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
2312
- if (cmd.path == undefined) break;
2313
- var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2314
- this.httprequest.uploadFilePath = filepath;
2315
- MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
2316
- try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
2317
- this.httprequest.uploadFileid = cmd.reqid;
2318
- if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
2319
- break;
2623
+ sendNextBlock--;
2624
+ var buf = Buffer.alloc(16384);
2625
+ var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
2626
+ this.filedownload.ptr += len;
2627
+ if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
2628
+ this.write(buf.slice(0, len + 4)); // Write as binary
2629
}
2321
- case 'uploaddone':
2630
+ break;
2631
+ }
2632
+ case 'upload':
2633
+ {
2634
+ // Upload a file, browser to agent
2635
+ if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
2636
+ if (cmd.path == undefined) break;
2637
+ var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
2638
+ this.httprequest.uploadFilePath = filepath;
2639
+ MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
2640
+ try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
2641
+ this.httprequest.uploadFileid = cmd.reqid;
2642
+ if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
2643
+ break;
2644
+ }
2645
+ case 'uploaddone':
2646
+ {
2647
+ // Indicates that an upload is done
2648
+ if (this.httprequest.uploadFile)
2649
{
2323
- // Indicates that an upload is done
2324
- if (this.httprequest.uploadFile) {
2325
- fs.closeSync(this.httprequest.uploadFile);
2326
- this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2327
- delete this.httprequest.uploadFile;
2328
- delete this.httprequest.uploadFileid;
2329
- delete this.httprequest.uploadFilePath;
2330
- }
2331
- break;
2650
+ fs.closeSync(this.httprequest.uploadFile);
2651
+ this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2652
+ delete this.httprequest.uploadFile;
2653
+ delete this.httprequest.uploadFileid;
2654
+ delete this.httprequest.uploadFilePath;
2655
}
2333
- case 'uploadcancel':
2656
+ break;
2657
+ }
2658
+ case 'uploadcancel':
2659
+ {
2660
+ // Indicates that an upload is canceled
2661
+ if (this.httprequest.uploadFile)
2662
{
2335
- // Indicates that an upload is canceled
2336
- if (this.httprequest.uploadFile) {
2337
- fs.closeSync(this.httprequest.uploadFile);
2338
- fs.unlinkSync(this.httprequest.uploadFilePath);
2339
- this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2340
- delete this.httprequest.uploadFile;
2341
- delete this.httprequest.uploadFileid;
2342
- delete this.httprequest.uploadFilePath;
2343
- }
2344
- break;
2663
+ fs.closeSync(this.httprequest.uploadFile);
2664
+ fs.unlinkSync(this.httprequest.uploadFilePath);
2665
+ this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2666
+ delete this.httprequest.uploadFile;
2667
+ delete this.httprequest.uploadFileid;
2668
+ delete this.httprequest.uploadFilePath;
2669
}
2346
- case 'copy':
2670
+ break;
2671
+ }
2672
+ case 'copy':
2673
+ {
2674
+ // Copy a bunch of files from scpath to dspath
2675
+ for (var i in cmd.names)
2676
{
2348
- // Copy a bunch of files from scpath to dspath
2349
- for (var i in cmd.names) {
2350
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2351
- MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2352
- if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
2353
- }
2354
- break;
2677
+ var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2678
+ MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2679
+ if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
2680
}
2356
- case 'move':
2681
+ break;
2682
+ }
2683
+ case 'move':
2684
+ {
2685
+ // Move a bunch of files from scpath to dspath
2686
+ for (var i in cmd.names)
2687
{
2358
- // Move a bunch of files from scpath to dspath
2359
- for (var i in cmd.names) {
2360
- var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2361
- MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2362
- if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
2363
- }
2364
- break;
2688
+ var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2689
+ MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2690
+ if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
2691
}
2366
- case 'zip':
2367
- // Zip a bunch of files
2368
- if (this.zip != null) return; // Zip operating is currently running, exit now.
2369
-
2370
- // Check that the specified files exist & build full paths
2371
- var fp, stat, p = [];
2372
- 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); } }
2373
- if (p.length == 0) return; // No files, quit now.
2374
-
2375
- // Setup file compression
2376
- var ofile = cmd.path + '/' + cmd.output;
2377
- this.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zipping' })));
2378
- this.zipfile = ofile;
2379
- delete this.zipcancel;
2380
- var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2381
- out.xws = this;
2382
- out.on('close', function () {
2383
- this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2384
- this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2385
- if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
2386
- delete this.xws.zipcancel;
2387
- delete this.xws.zipfile;
2388
- delete this.xws.zip;
2389
- });
2390
- this.zip = require('zip-writer').write({ files: p, basePath: cmd.path });
2391
- this.zip.xws = this;
2392
- 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));
2393
- this.zip.pipe(out);
2394
- break;
2395
- case 'cancel':
2396
- // Cancel zip operation if present
2397
- try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (e) { }
2398
- this.zip = null;
2399
- break;
2400
- default:
2401
- // Unknown action, ignore it.
2402
- break;
2403
- }
2404
- } else if (this.httprequest.protocol == 7) { // Plugin data exchange
2405
- var cmd = null;
2406
- try { cmd = JSON.parse(data); } catch (e) { };
2407
- if (cmd == null) { return; }
2408
- if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2409
- if (cmd.action == undefined) return;
2410
-
2411
- switch (cmd.action) {
2412
- case 'plugin': {
2413
- try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2692
break;
2693
}
2416
- default: {
2417
- // probably shouldn't happen, but just in case this feature is expanded
2418
- }
2694
+ case 'zip':
2695
+ // Zip a bunch of files
2696
+ if (this.zip != null) return; // Zip operating is currently running, exit now.
2697
+
2698
+ // Check that the specified files exist & build full paths
2699
+ var fp, stat, p = [];
2700
+ 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); } }
2701
+ if (p.length == 0) return; // No files, quit now.
2702
+
2703
+ // Setup file compression
2704
+ var ofile = cmd.path + '/' + cmd.output;
2705
+ this.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zipping' })));
2706
+ this.zipfile = ofile;
2707
+ delete this.zipcancel;
2708
+ var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2709
+ out.xws = this;
2710
+ out.on('close', function ()
2711
+ {
2712
+ this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2713
+ this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2714
+ if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
2715
+ delete this.xws.zipcancel;
2716
+ delete this.xws.zipfile;
2717
+ delete this.xws.zip;
2718
+ });
2719
+ this.zip = require('zip-writer').write({ files: p, basePath: cmd.path });
2720
+ this.zip.xws = this;
2721
+ 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));
2722
+ this.zip.pipe(out);
2723
+ break;
2724
+ case 'cancel':
2725
+ // Cancel zip operation if present
2726
+ try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (e) { }
2727
+ this.zip = null;
2728
+ break;
2729
+ default:
2730
+ // Unknown action, ignore it.
2731
+ break;
2732
+ }
2733
+ } else if (this.httprequest.protocol == 7)
2734
+ { // Plugin data exchange
2735
+ var cmd = null;
2736
+ try { cmd = JSON.parse(data); } catch (e) { };
2737
+ if (cmd == null) { return; }
2738
+ if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2739
+ if (cmd.action == undefined) return;
2740
+
2741
+ switch (cmd.action)
2742
+ {
2743
+ case 'plugin': {
2744
+ try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2745
+ break;
2746
+ }
2747
+ default: {
2748
+ // probably shouldn't happen, but just in case this feature is expanded
2749
}
2420
-
2750
}
2422
- //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
2751
+
2752
}
2753
+ //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
2754
}
2755
+}
2756
2426
- // Delete a directory with a files and directories within it
2427
- function deleteFolderRecursive(path, rec) {
2428
- var count = 0;
2429
- if (fs.existsSync(path)) {
2430
- if (rec == true) {
2431
- fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
2432
- var curPath = obj.path.join(path, file);
2433
- if (fs.statSync(curPath).isDirectory()) { // recurse
2434
- count += deleteFolderRecursive(curPath, true);
2435
- } else { // delete file
2436
- fs.unlinkSync(curPath);
2437
- count++;
2438
- }
2439
- });
2440
- }
2441
- fs.unlinkSync(path);
2442
- count++;
2757
+// Delete a directory with a files and directories within it
2758
+function deleteFolderRecursive(path, rec)
2759
+{
2760
+ var count = 0;
2761
+ if (fs.existsSync(path))
2762
+ {
2763
+ if (rec == true)
2764
+ {
2765
+ fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index)
2766
+ {
2767
+ var curPath = obj.path.join(path, file);
2768
+ if (fs.statSync(curPath).isDirectory())
2769
+ { // recurse
2770
+ count += deleteFolderRecursive(curPath, true);
2771
+ } else
2772
+ { // delete file
2773
+ fs.unlinkSync(curPath);
2774
+ count++;
2775
+ }
2776
+ });
2777
}
2444
- return count;
2445
- };
2778
+ fs.unlinkSync(path);
2779
+ count++;
2780
+ }
2781
+ return count;
2782
+}
2783
2447
- // Called when receiving control data on WebRTC
2448
- function onTunnelWebRTCControlData(data) {
2449
- if (typeof data != 'string') return;
2450
- var obj;
2451
- try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2452
- if (obj.type == 'close') {
2453
- //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2454
- try { this.close(); } catch (e) { }
2455
- try { this.xrtc.close(); } catch (e) { }
2456
- }
2784
+// Called when receiving control data on WebRTC
2785
+function onTunnelWebRTCControlData(data)
2786
+{
2787
+ if (typeof data != 'string') return;
2788
+ var obj;
2789
+ try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2790
+ if (obj.type == 'close')
2791
+ {
2792
+ //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2793
+ try { this.close(); } catch (e) { }
2794
+ try { this.xrtc.close(); } catch (e) { }
2795
}
2796
+}
2797
2459
- // Called when receiving control data on websocket
2460
- function onTunnelControlData(data, ws) {
2461
- var obj;
2462
- if (ws == null) { ws = this; }
2463
- if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
2464
- else if (typeof data == 'object') { obj = data; } else { return; }
2465
- //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2466
- //console.log('onTunnelControlData: ' + JSON.stringify(data));
2467
-
2468
- if (obj.action) {
2469
- switch (obj.action) {
2470
- case 'lock': {
2471
- // Lock the current user out of the desktop
2472
- try {
2473
- if (process.platform == 'win32') {
2474
- MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
2475
- var child = require('child_process');
2476
- child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
2477
- }
2478
- } catch (e) { }
2479
- break;
2480
- }
2481
- default:
2482
- // Unknown action, ignore it.
2483
- break;
2798
+// Called when receiving control data on websocket
2799
+function onTunnelControlData(data, ws)
2800
+{
2801
+ var obj;
2802
+ if (ws == null) { ws = this; }
2803
+ if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
2804
+ else if (typeof data == 'object') { obj = data; } else { return; }
2805
+ //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2806
+ //console.log('onTunnelControlData: ' + JSON.stringify(data));
2807
+
2808
+ if (obj.action)
2809
+ {
2810
+ switch (obj.action)
2811
+ {
2812
+ case 'lock': {
2813
+ // Lock the current user out of the desktop
2814
+ try
2815
+ {
2816
+ if (process.platform == 'win32')
2817
+ {
2818
+ MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
2819
+ var child = require('child_process');
2820
+ child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
2821
+ }
2822
+ } catch (e) { }
2823
+ break;
2824
}
2485
- return;
2825
+ default:
2826
+ // Unknown action, ignore it.
2827
+ break;
2828
}
2829
+ return;
2830
+ }
2831
2488
- switch (obj.type) {
2489
- case 'options': {
2490
- // These are additional connection options passed in the control channel.
2491
- //sendConsoleText('options: ' + JSON.stringify(obj));
2492
- delete obj.type;
2493
- ws.httprequest.xoptions = obj;
2832
+ switch (obj.type)
2833
+ {
2834
+ case 'options': {
2835
+ // These are additional connection options passed in the control channel.
2836
+ //sendConsoleText('options: ' + JSON.stringify(obj));
2837
+ delete obj.type;
2838
+ ws.httprequest.xoptions = obj;
2839
2495
- // Set additional user consent options if present
2496
- if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
2840
+ // Set additional user consent options if present
2841
+ if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
2842
2498
- break;
2843
+ break;
2844
+ }
2845
+ case 'close': {
2846
+ // We received the close on the websocket
2847
+ //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
2848
+ try { ws.close(); } catch (e) { }
2849
+ break;
2850
+ }
2851
+ case 'termsize': {
2852
+ // Indicates a change in terminal size
2853
+ if (process.platform == 'win32')
2854
+ {
2855
+ if (ws.httprequest._dispatcher == null) return;
2856
+ //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
2857
+ if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
2858
+ } else
2859
+ {
2860
+ if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
2861
+ //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
2862
+
2863
+ if (ws.httprequest.process.tcsetsize) { ws.httprequest.process.tcsetsize(obj.rows, obj.cols); }
2864
}
2500
- case 'close': {
2501
- // We received the close on the websocket
2502
- //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
2503
- try { ws.close(); } catch (e) { }
2504
- break;
2865
+ break;
2866
+ }
2867
+ case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
2868
+ if (ws.httprequest.protocol == 1)
2869
+ { // Terminal
2870
+ // 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
2871
+ if (process.platform == 'win32')
This file is too large to show in full.