1. Added user-consent 2. Added Diagnostic Agent test methods for 'console'
1. Added user-consent 2. Added Diagnostic Agent test methods for 'console'
Bryan Roe committed
Jun 14, 2019 at 13:57 UTC
6611b56cc6f9ad35083a4dd92933d9a902ec7f3a
1 file changed
+332
-59
agents/meshcore.js
+332
-59
@@ -22,6 +22,7 @@ process.on('uncaughtException', function (ex) {
22
//attachDebugger({ webport: 9999, wait: 1 }).then(function (prt) { console.log('Point Browser for Debug to port: ' + prt); });
23
24
// Mesh Rights
25
+var MNG_ERROR = 65;
26
var MESHRIGHT_EDITMESH = 1;
27
var MESHRIGHT_MANAGEUSERS = 2;
28
var MESHRIGHT_MANAGECOMPUTERS = 4;
@@ -36,10 +37,12 @@ var MESHRIGHT_NOFILES = 1024;
37
var MESHRIGHT_NOAMT = 2048;
38
var MESHRIGHT_LIMITEDINPUT = 4096;
39
39
-function createMeshCore(agent) {
40
+function createMeshCore(agent)
41
+{
42
var obj = {};
43
42
- if (process.platform == 'darwin' && !process.versions) {
44
+ if (process.platform == 'darwin' && !process.versions)
45
+ {
46
// This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
47
var child = require('child_process').execFile('/bin/sh', ['sh']);
48
child.stdout.str = '';
@@ -48,18 +51,21 @@ function createMeshCore(agent) {
51
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]; } }");
52
child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
53
child.waitExit();
51
- if (child.stdout.str.trim() == 'Crashed') {
54
+ if (child.stdout.str.trim() == 'Crashed')
55
+ {
56
child = require('child_process').execFile('/bin/sh', ['sh']);
57
child.stdout.str = '';
58
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
59
child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
60
child.waitExit();
61
58
- if (parseInt(child.stdout.str.trim()) == process.pid) {
62
+ if (parseInt(child.stdout.str.trim()) == process.pid)
63
+ {
64
// The currently running MeshAgent is us, so we can continue with the update
65
var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
66
var tokens = plist.split('<key>KeepAlive</key>');
62
- if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
67
+ if (tokens[1].split('>')[0].split('<')[1] == 'dict')
68
+ {
69
var tmp = tokens[1].split('</dict>');
70
tmp.shift();
71
tokens[1] = '\n <true/>' + tmp.join('</dict>');
@@ -114,6 +120,133 @@ function createMeshCore(agent) {
120
}
121
}
122
123
+ // Create Secure IPC for Diagnostic Agent Communications
124
+ obj.DAIPC = require('net').createServer();
125
+ if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (ee) { } }
126
+ obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
127
+ try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH }); } catch (e) { }
128
+ obj.DAIPC.on('connection', function (c)
129
+ {
130
+ c._send = function (j)
131
+ {
132
+ var data = JSON.stringify(j);
133
+ var packet = Buffer.alloc(data.length + 4);
134
+ packet.writeUInt32LE(data.length + 4, 0);
135
+ Buffer.from(data).copy(packet, 4);
136
+ this.end(packet);
137
+ };
138
+ this._daipc = c;
139
+ c.parent = this;
140
+ c.on('end', function () { console.log('Connection Closed'); this.parent._daipc = null; });
141
+ c.on('data', function (chunk)
142
+ {
143
+ if (chunk.length < 4) { this.unshift(chunk); return; }
144
+ var len = chunk.readUInt32LE(0);
145
+ if (len > 8192) { this.parent._daipc = null; this.end(); return; }
146
+ if (chunk.length < len) { this.unshift(chunk); return; }
147
+
148
+ var data = chunk.slice(4, len);
149
+ try
150
+ {
151
+ data = JSON.parse(data.toString());
152
+ }
153
+ catch(de)
154
+ {
155
+ this.parent._daipc = null; this.end(); return;
156
+ }
157
+
158
+ if (!data.cmd) { this.parent._daipc = null; this.end(); return; }
159
+
160
+ try
161
+ {
162
+ switch(data.cmd)
163
+ {
164
+ case 'query':
165
+ switch(data.value)
166
+ {
167
+ case 'connection':
168
+ data.result = require('MeshAgent').ConnectedServer;
169
+ this._send(data);
170
+ break;
171
+ }
172
+ break;
173
+ default:
174
+ this.parent._daipc = null; this.end(); return;
175
+ break;
176
+ }
177
+ }
178
+ catch(xe)
179
+ {
180
+ this.parent._daipc = null; this.end(); return;
181
+ }
182
+ });
183
+ });
184
+ function diagnosticAgent_uninstall()
185
+ {
186
+ require('service-manager').manager.uninstallService('meshagentDiagnostic');
187
+ require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
188
+ };
189
+ function diagnosticAgent_installCheck(install)
190
+ {
191
+ try
192
+ {
193
+ var diag = require('service-manager').manager.getService('meshagentDiagnostic');
194
+ return (diag);
195
+ }
196
+ catch (e)
197
+ {
198
+ }
199
+ if (!install) { return (null); }
200
+
201
+ var svc = null;
202
+ try
203
+ {
204
+ require('service-manager').manager.installService(
205
+ {
206
+ name: 'meshagentDiagnostic',
207
+ displayName: 'Mesh Agent Diagnostic Service',
208
+ description: 'Mesh Agent Diagnostic Service',
209
+ servicePath: process.execPath,
210
+ parameters: ['-recovery']
211
+ //files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
212
+ });
213
+ svc = require('service-manager').manager.getService('meshagentDiagnostic');
214
+ }
215
+ catch (e)
216
+ {
217
+ return (null);
218
+ }
219
+ var proxyConfig = require('global-tunnel').proxyConfig;
220
+ var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
221
+ var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
222
+ ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
223
+ ddb.Put('disableUpdate', '1');
224
+ ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
225
+ ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
226
+ ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
227
+ if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
228
+ if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
229
+ if (proxyConfig)
230
+ {
231
+ ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
232
+ }
233
+ else
234
+ {
235
+ ddb.Put('ignoreProxyFile', '1');
236
+ }
237
+
238
+ require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
239
+ require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: 'Diagnostic Agent Registered [' + nodeid.length + '/' + nodeid + ']' });
240
+
241
+ delete ddb;
242
+
243
+ // Set a recurrent task, to run the Diagnostic Agent every 2 days
244
+ 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'});
245
+ //require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
246
+
247
+ return (svc);
248
+ }
249
+
250
/*
251
function borderController() {
252
this.container = null;
@@ -191,6 +324,8 @@ function createMeshCore(agent) {
324
mesh = agent.getMeshApi();
325
}
326
327
+ mesh.DAIPC = obj.DAIPC;
328
+
329
/*
330
var AMTScanner = require("AMTScanner");
331
var scan = new AMTScanner();
@@ -815,39 +950,7 @@ function createMeshCore(agent) {
950
return;
951
}
952
818
- // Test the console messaging system
819
- //this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote terminal...' })); // Send a console message back using the console channel, "\n" is supported.
820
-
821
- // Perform notification if needed. Toast messages may not be supported on all platforms.
822
- if (this.httprequest.consent && (this.httprequest.consent & 2)) {
823
- try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
824
- }
825
-
826
- // Remote terminal using native pipes
827
- if (process.platform == "win32")
828
- {
829
- this.httprequest._term = require('win-terminal').Start(80, 25);
830
- this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
831
- this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
832
- this.prependListener('end', function () { this.httprequest._term.end(function () { console.log('Terminal was closed'); }); });
833
- //this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
834
- } else {
835
- if (fs.existsSync("/bin/bash")) {
836
- this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
837
- if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
838
- } else {
839
- this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
840
- if (process.platform == 'linux') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nPS1='\\u@\\h:\\w\\$ '\nclear\n"); }
841
- }
842
- //if (this.httprequest.process == null) { }
843
- this.httprequest.process.tunnel = this;
844
- this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
845
- this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
846
- this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
847
- this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
848
- this.prependListener('end', function () { this.httprequest.process.kill(); });
849
- }
850
-
953
+
954
this.end = function () {
955
if (process.platform == "win32") {
956
// Unpipe the web socket
@@ -868,11 +971,71 @@ function createMeshCore(agent) {
971
}
972
};
973
974
+ // Remote terminal using native pipes
975
+ if (process.platform == "win32") {
976
+ this.httprequest._term = require('win-terminal').Start(80, 25);
977
+ this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
978
+ this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
979
+ this.prependListener('end', function () { this.httprequest._term.end(function () { console.log('Terminal was closed'); }); });
980
+ } else {
981
+ this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
982
+ this.httprequest.process.tunnel = this;
983
+ this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
984
+ this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
985
+ this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
986
+ this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
987
+ this.prependListener('end', function () { this.httprequest.process.kill(); });
988
+ this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n");
989
+ }
990
+
991
+
992
+
993
+ // Perform notification if needed. Toast messages may not be supported on all platforms.
994
+ if (this.httprequest.consent && (this.httprequest.consent & 16)) {
995
+ // User Consent Prompt is required
996
+
997
+ // Send a console message back using the console channel, "\n" is supported.
998
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
999
+
1000
+ var pr = require('message-box').create('Mesh Central', this.httprequest.username + ' requesting Terminal Access. Grant access?', 10);
1001
+ pr.ws = this;
1002
+ this.pause();
1003
+
1004
+ pr.then(
1005
+ function () {
1006
+ // Success!
1007
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
1008
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
1009
+ // User Notifications is required
1010
+ try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
1011
+ }
1012
+
1013
+ this.ws.resume();
1014
+ },
1015
+ function (e) {
1016
+ // User Consent Denied/Failed!
1017
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
1018
+ this.ws.end();
1019
+ });
1020
+ }
1021
+ else {
1022
+ // User Consent Prompt is not required
1023
+ if (this.httprequest.consent && (this.httprequest.consent & 2)) {
1024
+ // User Notifications is required
1025
+ try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
1026
+ }
1027
+ this.resume();
1028
+ }
1029
+
1030
+
1031
+
1032
+
1033
+
1034
this.removeAllListeners('data');
1035
this.on('data', onTunnelControlData);
1036
//this.write('MeshCore Terminal Hello');
874
- } else if (this.httprequest.protocol == 2) {
875
-
1037
+ } else if (this.httprequest.protocol == 2)
1038
+ {
1039
// Check user access rights for desktop
1040
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) {
1041
// Disengage this tunnel, user does not have the rights to do this!!
@@ -882,13 +1045,6 @@ function createMeshCore(agent) {
1045
return;
1046
}
1047
885
- // Test the console messaging system
886
- //this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote desktop...' })); // Send a console message back using the console channel, "\n" is supported.
887
-
888
- // Perform notification if needed. Toast messages may not be supported on all platforms.
889
- if (this.httprequest.consent && (this.httprequest.consent & 1)) {
890
- try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
891
- }
1048
1049
// Remote desktop using native pipes
1050
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
@@ -926,7 +1082,56 @@ function createMeshCore(agent) {
1082
// TODO!!!
1083
}
1084
929
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text. Pipe the KVM --> Browser images.
1085
+ // Perform notification if needed. Toast messages may not be supported on all platforms.
1086
+ if (this.httprequest.consent && (this.httprequest.consent & 8))
1087
+ {
1088
+ // User Consent Prompt is required
1089
+
1090
+ // Send a console message back using the console channel, "\n" is supported.
1091
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
1092
+
1093
+ var pr = require('message-box').create('Mesh Central', this.httprequest.username + ' requesting KVM Access. Grant access?', 10);
1094
+ pr.ws = this;
1095
+ this.pause();
1096
+
1097
+ pr.then(
1098
+ function ()
1099
+ {
1100
+ // Success!
1101
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
1102
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1))
1103
+ {
1104
+ // User Notifications is required
1105
+ try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
1106
+ }
1107
+
1108
+ this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
1109
+ this.ws.resume();
1110
+ },
1111
+ function (e)
1112
+ {
1113
+ // User Consent Denied/Failed!
1114
+ this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
1115
+
1116
+ //var err = 'User consent: ' + e.toString();
1117
+ //var b = Buffer.alloc(5 + err.length);
1118
+ //b.writeUInt16BE(MNG_ERROR, 0);
1119
+ //b.writeUInt16BE(err.length + 4, 2);
1120
+ //Buffer.from(err).copy(b, 4);
1121
+ //this.ws.end(b);
1122
+ });
1123
+ }
1124
+ else
1125
+ {
1126
+ // User Consent Prompt is not required
1127
+ if (this.httprequest.consent && (this.httprequest.consent & 1))
1128
+ {
1129
+ // User Notifications is required
1130
+ try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
1131
+ }
1132
+ this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
1133
+ }
1134
+
1135
this.removeAllListeners('data');
1136
this.on('data', onTunnelControlData);
1137
//this.write('MeshCore KVM Hello!1');
@@ -942,12 +1147,41 @@ function createMeshCore(agent) {
1147
return;
1148
}
1149
945
- // Test the console messaging system
946
- //this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote files...' })); // Send a console message back using the console channel, "\n" is supported.
1150
+ // Perform notification if needed. Toast messages may not be supported on all platforms.
1151
+ if (this.httprequest.consent && (this.httprequest.consent & 32))
1152
+ {
1153
+ // User Consent Prompt is required
1154
+
1155
+ // Send a console message back using the console channel, "\n" is supported.
1156
+ this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
1157
948
- // Perform notification if needed
949
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
950
- try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file access.'); } catch (ex) { }
1158
+ var pr = require('message-box').create('Mesh Central', this.httprequest.username + ' requesting remote File Access. Grant access?', 10);
1159
+ pr.ws = this;
1160
+ this.pause();
1161
+
1162
+ pr.then(
1163
+ function () {
1164
+ // Success!
1165
+ this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
1166
+ if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4))
1167
+ {
1168
+ // User Notifications is required
1169
+ try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote file session.'); } catch (ex) { }
1170
+ }
1171
+ this.ws.resume();
1172
+ },
1173
+ function (e) {
1174
+ // User Consent Denied/Failed!
1175
+ this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
1176
+ });
1177
+ }
1178
+ else {
1179
+ // User Consent Prompt is not required
1180
+ if (this.httprequest.consent && (this.httprequest.consent & 4)) {
1181
+ // User Notifications is required
1182
+ try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file session.'); } catch (ex) { }
1183
+ }
1184
+ this.resume();
1185
}
1186
1187
// Setup files
@@ -1372,12 +1606,9 @@ function createMeshCore(agent) {
1606
break;
1607
}
1608
case 'toast': {
1375
- if (process.platform == 'win32') {
1376
- if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
1377
- try { require('toaster').Toast('MeshCentral', args['_'][0]); response = 'ok'; } catch (ex) { response = ex; }
1378
- }
1379
- } else {
1380
- response = 'Only supported on Windows.';
1609
+ if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else
1610
+ {
1611
+ require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
1612
}
1613
break;
1614
}
@@ -1763,6 +1994,48 @@ function createMeshCore(agent) {
1994
}
1995
break;
1996
}
1997
+ case 'diagnostic':
1998
+ {
1999
+ if (!mesh.DAIPC.listening)
2000
+ {
2001
+ response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
2002
+ break;
2003
+ }
2004
+ var diag = diagnosticAgent_installCheck();
2005
+ if (diag)
2006
+ {
2007
+ if (args['_'].length == 1 && args['_'][0] == 'uninstall')
2008
+ {
2009
+ diagnosticAgent_uninstall();
2010
+ response = 'Diagnostic Agent uninstalled';
2011
+ }
2012
+ else
2013
+ {
2014
+ response = 'Diagnostic Agent installed at: ' + diag.appLocation();
2015
+ }
2016
+ }
2017
+ else
2018
+ {
2019
+ if (args['_'].length == 1 && args['_'][0] == 'install')
2020
+ {
2021
+ diag = diagnosticAgent_installCheck(true);
2022
+ if (diag)
2023
+ {
2024
+ response = 'Diagnostic agent was installed at: ' + diag.appLocation();
2025
+ }
2026
+ else
2027
+ {
2028
+ response = 'Diagnostic agent installation failed';
2029
+ }
2030
+ }
2031
+ else
2032
+ {
2033
+ response = 'Diagnostic Agent Not installed. To install: diagnostic install';
2034
+ }
2035
+ }
2036
+ if (diag) { diag.close(); diag = null; }
2037
+ break;
2038
+ }
2039
default: { // This is an unknown command, return an error message
2040
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
2041
break;