New toast notifications
Ylian Saint-Hilaire committed
Apr 19, 2018 at 18:19 UTC
bd82453c3bde56ee2a7366beb14ac95ca29303ee
30 files changed
+725
-33
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_arm
Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ
agents/meshagent_pi
Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ
agents/meshagent_pogo
Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ
agents/meshagent_poky
Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ
agents/meshagent_poky64
Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ
agents/meshagent_x86
Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ
agents/meshagent_x86-64
Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ
agents/meshagent_x86-64_nokvm
Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ
agents/meshagent_x86_nokvm
Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ
agents/meshcore.js
+24
-6
@@ -18,7 +18,7 @@ function createMeshCore(agent) {
18
var obj = {};
19
20
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
21
- obj.meshCoreInfo = "MeshCore v4";
21
+ obj.meshCoreInfo = "MeshCore v5";
22
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
23
var meshServerConnectionState = 0;
24
var tunnels = {};
@@ -402,6 +402,11 @@ function createMeshCore(agent) {
402
getIpLocationData(function (location) { mesh.SendCommand({ "action": "iplocation", "type": "publicip", "value": location }); });
403
break;
404
}
405
+ case 'toast': {
406
+ // Display a toast message
407
+ if (data.title && data.msg) { require('toaster').Toast(data.title, data.msg); }
408
+ break;
409
+ }
410
}
411
}
412
}
@@ -521,7 +526,6 @@ function createMeshCore(agent) {
526
527
// Clean up WebSocket
528
this.removeAllListeners('data');
524
- delete this;
529
}
530
function onTunnelSendOk() { sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid); }
531
function onTunnelData(data) {
@@ -571,19 +575,28 @@ function createMeshCore(agent) {
575
this.on('data', onTunnelControlData);
576
//this.write('MeshCore Terminal Hello');
577
if (process.platform != 'win32') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n"); }
574
- } else if (this.httprequest.protocol == 2) {
578
+ } else if (this.httprequest.protocol == 2)
579
+ {
580
// Remote desktop using native pipes
581
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
582
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
583
this.desktop = this.httprequest.desktop;
584
+
585
+ // Display a toast message
586
+ //require('toaster').Toast('MeshCentral', 'Remote Desktop Control Started.');
587
+
588
this.end = function () {
589
--this.desktop.kvm.connectionCount;
590
this.unpipe(this.httprequest.desktop.kvm);
591
this.httprequest.desktop.kvm.unpipe(this);
583
- if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
592
+ if (this.desktop.kvm.connectionCount == 0) {
593
+ // Display a toast message
594
+ //require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.');
595
+ this.httprequest.desktop.kvm.end();
596
+ }
597
};
598
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
586
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. (****************)
599
+ this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
600
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
601
this.removeAllListeners('data');
602
this.on('data', onTunnelControlData);
@@ -839,7 +852,12 @@ function createMeshCore(agent) {
852
var response = null;
853
switch (cmd) {
854
case 'help': { // Displays available commands
842
- response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios.';
855
+ response = 'aaaAvailable commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast.';
856
+ break;
857
+ }
858
+ case 'toast': {
859
+ require('toaster').Toast('MeshCentral', args['_'][0]);
860
+ response = 'ok';
861
break;
862
}
863
case 'setdebug': {
agents/modules_meshcore/process-manager.js
+17
-13
@@ -5,15 +5,16 @@ Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
-http://www.apache.org/licenses/LICENSE-2.0
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
+// JavaScript source code
18
var GM = require('_GenericMarshal');
19
20
function processManager() {
@@ -34,12 +35,16 @@ function processManager() {
35
}
36
this.getProcesses = function getProcesses(callback) {
37
switch (process.platform) {
38
+ default:
39
+ throw ('Enumerating processes on ' + process.platform + ' not supported');
40
case 'win32':
38
- var h = this._kernel32.CreateToolhelp32Snapshot(2, 0), info = GM.CreateVariable(304), retVal = {};
41
+ var retVal = [];
42
+ var h = this._kernel32.CreateToolhelp32Snapshot(2, 0);
43
+ var info = GM.CreateVariable(304);
44
info.toBuffer().writeUInt32LE(304, 0);
45
var nextProcess = this._kernel32.Process32First(h, info);
46
while (nextProcess.Val) {
42
- retVal[info.Deref(8, 4).toBuffer().readUInt32LE(0)] = { cmd: info.Deref(GM.PointerSize == 4 ? 36 : 44, 260).String };
47
+ retVal.push({ pid: info.Deref(8, 4).toBuffer().readUInt32LE(0), cmd: info.Deref(GM.PointerSize == 4 ? 36 : 44, 260).String });
48
nextProcess = this._kernel32.Process32Next(h, info);
49
}
50
if (callback) { callback.apply(this, [retVal]); }
@@ -55,15 +60,16 @@ function processManager() {
60
for (var i = 1; i < arguments.length; ++i) { p.args.push(arguments[i]); }
61
p.on('exit', function onGetProcesses() {
62
delete this.Parent._psp[this.pid];
58
- var retVal = {}, lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
63
+ var retVal = [], lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
64
for (var i in lines) {
60
- var tokens = lines[i].split(' '), tokenList = [];
65
+ var tokens = lines[i].split(' ');
66
+ var tokenList = [];
67
for (var x in tokens) {
68
if (i == 0 && tokens[x]) { key[tokens[x]] = keyi++; }
69
if (i > 0 && tokens[x]) { tokenList.push(tokens[x]); }
70
}
71
if ((i > 0) && (tokenList[key.PID])) {
66
- retVal[tokenList[key.PID]] = { user: tokenList[key.USER], cmd: tokenList[key.COMMAND] };
72
+ retVal.push({ pid: tokenList[key.PID], user: tokenList[key.USER], cmd: tokenList[key.COMMAND] });
73
}
74
}
75
if (this.callback) {
@@ -73,22 +79,20 @@ function processManager() {
79
});
80
p.stdout.on('data', function (chunk) { this.parent.ps += chunk.toString(); });
81
break;
76
- default:
77
- throw ('Enumerating processes on ' + process.platform + ' not supported');
82
}
83
};
84
this.getProcessInfo = function getProcessInfo(pid) {
85
switch (process.platform) {
86
+ default:
87
+ throw ('getProcessInfo() not supported for ' + process.platform);
88
case 'linux':
83
- var status = require('fs').readFileSync('/proc/' + pid + '/status'), lines = status.toString().split('\n'), info = {};
89
+ var status = require('fs').readFileSync('/proc/' + pid + '/status'), info = {}, lines = status.toString().split('\n');
90
for (var i in lines) {
91
var tokens = lines[i].split(':');
92
if (tokens.length > 1) { tokens[1] = tokens[1].trim(); }
93
info[tokens[0]] = tokens[1];
94
}
89
- return info;
90
- default:
91
- throw ('getProcessInfo() not supported for ' + process.platform);
95
+ return (info);
96
}
97
};
98
}
agents/modules_meshcore/toaster.js
new
+72
@@ -0,0 +1,72 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
+var toasters = {};
18
+
19
+function Toaster()
20
+{
21
+ this._ObjectID = 'Toaster';
22
+ this.Toast = function Toast(title, caption)
23
+ {
24
+ if (process.platform != 'win32') return;
25
+
26
+ var retVal = {};
27
+ var emitter = require('events').inherits(retVal);
28
+ emitter.createEvent('Clicked');
29
+ emitter.createEvent('Dismissed');
30
+
31
+ var session = require('user-sessions').Current();
32
+ for (var i in session)
33
+ {
34
+ console.log(session[i]);
35
+ }
36
+ try
37
+ {
38
+ console.log('Attempting Toast Mechanism 1');
39
+ retVal._child = require('ScriptContainer').Create({ processIsolation: true, sessionId: session.connected[0].SessionId });
40
+ }
41
+ catch (e) {
42
+ console.log(e);
43
+ console.log('Attempting Toast Mechanism 2');
44
+ retVal._child = require('ScriptContainer').Create({ processIsolation: true });
45
+ }
46
+ retVal._child.parent = retVal;
47
+
48
+ retVal._child.on('exit', function (code) { this.parent.emit('Dismissed'); delete this.parent._child; });
49
+ retVal._child.addModule('win-console', getJSModule('win-console'));
50
+ retVal._child.addModule('win-messagepump', getJSModule('win-messagepump'));
51
+
52
+ var str = "\
53
+ try{\
54
+ var toast = require('win-console');\
55
+ var balloon = toast.SetTrayIcon({ szInfo: '" + caption + "', szInfoTitle: '" + title + "', balloonOnly: true });\
56
+ balloon.on('ToastDismissed', function(){process.exit();});\
57
+ }\
58
+ catch(e)\
59
+ {\
60
+ require('ScriptContainer').send(e);\
61
+ }\
62
+ require('ScriptContainer').send('done');\
63
+ ";
64
+ retVal._child.ExecuteString(str);
65
+ toasters[retVal._hashCode()] = retVal;
66
+ retVal.on('Dismissed', function () { delete toasters[this._hashCode()]; });
67
+ console.log('Returning');
68
+ return (retVal);
69
+ };
70
+}
71
+
72
+module.exports = new Toaster();
\ No newline at end of file
agents/modules_meshcore/user-sessions.js
renamed
+66
-1
@@ -1,4 +1,18 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
17
function UserSessions()
18
{
@@ -87,6 +101,8 @@ function UserSessions()
101
}
102
103
this._wts.WTSFreeMemory(pinfo.Deref());
104
+
105
+ Object.defineProperty(retVal, 'connected', { value: showActiveOnly(retVal) });
106
return (retVal);
107
};
108
}
@@ -94,9 +110,58 @@ function UserSessions()
110
{
111
this.Current = function Current()
112
{
97
- return ({});
113
+ var retVal = {};
114
+ var emitterUtils = require('events').inherits(retVal);
115
+ emitterUtils.createEvent('logon');
116
+
117
+ retVal._child = require('child_process').execFile('/usr/bin/last', ['last', '-f', '/var/run/utmp']);
118
+ retVal._child.Parent = retVal;
119
+ retVal._child._txt = '';
120
+ retVal._child.on('exit', function (code)
121
+ {
122
+ var lines = this._txt.split('\n');
123
+ var sessions = [];
124
+ for(var i in lines)
125
+ {
126
+ if (lines[i])
127
+ {
128
+ console.log(getTokens(lines[i]));
129
+ var user = lines[i].substring(0, lines[i].indexOf(' '));
130
+ sessions.push(user);
131
+ }
132
+ }
133
+ sessions.pop();
134
+ console.log(sessions);
135
+ });
136
+ retVal._child.stdout.Parent = retVal._child;
137
+ retVal._child.stdout.on('data', function (chunk) { this.Parent._txt += chunk.toString(); });
138
+
139
+ return (retVal);
140
+ }
141
+ }
142
+}
143
+function showActiveOnly(source)
144
+{
145
+ var retVal = [];
146
+ for (var i in source)
147
+ {
148
+ if (source[i].State == 'Active' || source[i].State == 'Connected')
149
+ {
150
+ retVal.push(source[i]);
151
}
152
}
153
+ return (retVal);
154
+}
155
+function getTokens(str)
156
+{
157
+ var columns = [];
158
+ var i;
159
+
160
+ columns.push(str.substring(0, (i=str.indexOf(' '))));
161
+ while (str[++i] == ' ');
162
+ columns.push(str.substring(i, str.substring(i).indexOf(' ') + i));
163
+
164
+ return (columns);
165
}
166
167
module.exports = new UserSessions();
\ No newline at end of file
agents/modules_meshcore/wifi-scanner-windows.js
+16
@@ -1,3 +1,19 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
18
function _Scan()
19
{
agents/modules_meshcore/wifi-scanner.js
+16
-1
@@ -1,7 +1,22 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
var MemoryStream = require('MemoryStream');
18
var WindowsChildScript = 'var parent = require("ScriptContainer");var Wireless = require("wifi-scanner-windows");Wireless.on("Scan", function (ap) { parent.send(ap); });Wireless.Scan();';
19
4
-
20
function AccessPoint(_ssid, _bssid, _lq)
21
{
22
this.ssid = _ssid;
agents/modules_meshcore/win-console.js
new
+164
@@ -0,0 +1,164 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
+var TrayIconFlags =
18
+ {
19
+ NIF_MESSAGE: 0x00000001,
20
+ NIF_ICON: 0x00000002,
21
+ NIF_TIP: 0x00000004,
22
+ NIF_STATE: 0x00000008,
23
+ NIF_INFO: 0x00000010,
24
+ NIF_GUID: 0x00000020,
25
+ NIF_REALTIME: 0x00000040,
26
+ NIF_SHOWTIP: 0x00000080,
27
+
28
+ NIM_ADD: 0x00000000,
29
+ NIM_MODIFY: 0x00000001,
30
+ NIM_DELETE: 0x00000002,
31
+ NIM_SETFOCUS: 0x00000003,
32
+ NIM_SETVERSION: 0x00000004
33
+ };
34
+var NOTIFYICON_VERSION_4 = 4;
35
+var MessageTypes = { WM_APP: 0x8000, WM_USER: 0x0400 };
36
+function WindowsConsole()
37
+{
38
+ if (process.platform == 'win32')
39
+ {
40
+ this._ObjectID = 'WindowsConsole';
41
+ this._Marshal = require('_GenericMarshal');
42
+ this._kernel32 = this._Marshal.CreateNativeProxy("kernel32.dll");
43
+ this._user32 = this._Marshal.CreateNativeProxy("user32.dll");
44
+ this._kernel32.CreateMethod("GetConsoleWindow");
45
+ this._kernel32.CreateMethod('GetCurrentThread');
46
+ this._user32.CreateMethod("ShowWindow");
47
+ this._user32.CreateMethod("LoadImageA");
48
+ this._user32.CreateMethod({ method: 'GetMessageA', threadDispatch: 1 });
49
+ this._shell32 = this._Marshal.CreateNativeProxy('Shell32.dll');
50
+ this._shell32.CreateMethod('Shell_NotifyIconA');
51
+
52
+ this._handle = this._kernel32.GetConsoleWindow();
53
+ this.minimize = function () {
54
+ this._user32.ShowWindow(this._handle, 6);
55
+ };
56
+ this.restore = function () {
57
+ this._user32.ShowWindow(this._handle, 9);
58
+ };
59
+ this.hide = function () {
60
+ this._user32.ShowWindow(this._handle, 0);
61
+ };
62
+ this.show = function () {
63
+ this._user32.ShowWindow(this._handle, 5);
64
+ };
65
+
66
+
67
+ this._loadicon = function (imagePath) {
68
+ var h = this._user32.LoadImageA(0, this._Marshal.CreateVariable(imagePath), 1, 0, 0, 0x00000010 | 0x00008000 | 0x00000040); // LR_LOADFROMFILE | LR_SHARED | LR_DEFAULTSIZE
69
+ return (h);
70
+ };
71
+
72
+ this.SetTrayIcon = function SetTrayIcon(options)
73
+ {
74
+ var data = this._Marshal.CreateVariable(this._Marshal.PointerSize == 4 ? 508 : 528);
75
+ //console.log('struct size = ' + data._size);
76
+ //console.log('TryIcon, WM_MESSAGE filter = ' + options.filter);
77
+ data.toBuffer().writeUInt32LE(data._size, 0);
78
+
79
+ var trayType = TrayIconFlags.NIF_TIP | TrayIconFlags.NIF_MESSAGE
80
+ options.filter = MessageTypes.WM_APP + 1;
81
+ data.Deref(this._Marshal.PointerSize == 4 ? 16 : 24, 4).toBuffer().writeUInt32LE(options.filter);
82
+
83
+ if (!options.noBalloon) { trayType |= TrayIconFlags.NIF_INFO; }
84
+
85
+ if (options.icon)
86
+ {
87
+ trayType |= TrayIconFlags.NIF_ICON;
88
+ var hIcon = data.Deref(this._Marshal.PointerSize == 4 ? 20 : 32, this._Marshal.PointerSize);
89
+ options.icon.pointerBuffer().copy(hIcon.toBuffer());
90
+ }
91
+
92
+ data.Deref(this._Marshal.PointerSize * 2, 4).toBuffer().writeUInt32LE(1);
93
+ data.Deref(this._Marshal.PointerSize == 4 ? 12 : 20, 4).toBuffer().writeUInt32LE(trayType);
94
+ data.Deref(this._Marshal.PointerSize == 4 ? 416 : 432, 4).toBuffer().writeUInt32LE(NOTIFYICON_VERSION_4);
95
+
96
+ var szTip = data.Deref(this._Marshal.PointerSize == 4 ? 24 : 40, 128);
97
+ var szInfo = data.Deref(this._Marshal.PointerSize == 4 ? 160 : 176, 256);
98
+ var szInfoTitle = data.Deref(this._Marshal.PointerSize == 4 ? 420 : 436, 64);
99
+
100
+ if (options.szTip) { Buffer.from(options.szTip).copy(szTip.toBuffer()); }
101
+ if (options.szInfo) { Buffer.from(options.szInfo).copy(szInfo.toBuffer()); }
102
+ if (options.szInfoTitle) { Buffer.from(options.szInfoTitle).copy(szInfoTitle.toBuffer()); }
103
+
104
+
105
+ var MessagePump = require('win-messagepump');
106
+ retVal = { _ObjectID: 'WindowsConsole.TrayIcon', MessagePump: new MessagePump(options) };
107
+ var retValEvents = require('events').inherits(retVal);
108
+ retValEvents.createEvent('ToastClicked');
109
+ retValEvents.createEvent('IconHover');
110
+ retValEvents.createEvent('ToastDismissed');
111
+ retVal.Options = options;
112
+ retVal.MessagePump.TrayIcon = retVal;
113
+ retVal.MessagePump.NotifyData = data;
114
+ retVal.MessagePump.WindowsConsole = this;
115
+ retVal.MessagePump.on('exit', function onExit(code) { console.log('Pump Exited'); if (this.TrayIcon) { this.TrayIcon.remove(); } });
116
+ retVal.MessagePump.on('hwnd', function onHwnd(h)
117
+ {
118
+ //console.log('Got HWND');
119
+ options.hwnd = h;
120
+ h.pointerBuffer().copy(this.NotifyData.Deref(this.WindowsConsole._Marshal.PointerSize, this.WindowsConsole._Marshal.PointerSize).toBuffer());
121
+
122
+ if(this.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_ADD, this.NotifyData).Val == 0)
123
+ {
124
+ // Something went wrong
125
+ }
126
+ });
127
+ retVal.MessagePump.on('message', function onWindowsMessage(msg)
128
+ {
129
+ if(msg.message == this.TrayIcon.Options.filter)
130
+ {
131
+ var handled = false;
132
+ if (msg.wparam == 1 && msg.lparam == 1029)
133
+ {
134
+ this.TrayIcon.emit('ToastClicked');
135
+ handled = true;
136
+ }
137
+ if (msg.wparam == 1 && msg.lparam == 512)
138
+ {
139
+ this.TrayIcon.emit('IconHover');
140
+ handled = true;
141
+ }
142
+ if (this.TrayIcon.Options.balloonOnly && msg.wparam == 1 && (msg.lparam == 1028 || msg.lparam == 1029))
143
+ {
144
+ this.TrayIcon.emit('ToastDismissed');
145
+ this.TrayIcon.remove();
146
+ handled = true;
147
+ }
148
+ if (!handled) { console.log(msg); }
149
+ }
150
+ });
151
+ retVal.remove = function remove()
152
+ {
153
+ this.MessagePump.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_DELETE, this.MessagePump.NotifyData);
154
+ this.MessagePump.stop();
155
+ delete this.MessagePump.TrayIcon;
156
+ delete this.MessagePump;
157
+ };
158
+ return (retVal);
159
+
160
+ };
161
+ }
162
+}
163
+
164
+module.exports = new WindowsConsole();
\ No newline at end of file
agents/modules_meshcore/win-messagepump.js
new
+122
@@ -0,0 +1,122 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
+var WH_CALLWNDPROC = 4;
18
+var WM_QUIT = 0x0012;
19
+
20
+function WindowsMessagePump(options)
21
+{
22
+ this._ObjectID = 'WindowsMessagePump';
23
+ this._options = options;
24
+ var emitterUtils = require('events').inherits(this);
25
+ emitterUtils.createEvent('hwnd');
26
+ emitterUtils.createEvent('error');
27
+ emitterUtils.createEvent('message');
28
+ emitterUtils.createEvent('exit');
29
+
30
+ this._child = require('ScriptContainer').Create({ processIsolation: 0 });
31
+ this._child.MessagePump = this;
32
+ this._child.prependListener('~', function _childFinalizer() { this.MessagePump.emit('exit', 0); console.log('calling stop'); this.MessagePump.stop(); });
33
+ this._child.once('exit', function onExit(code) { this.MessagePump.emit('exit', code); });
34
+ this._child.once('ready', function onReady()
35
+ {
36
+ console.log('child ready');
37
+ var execString =
38
+ "var m = require('_GenericMarshal');\
39
+ var h = null;\
40
+ var k = m.CreateNativeProxy('Kernel32.dll');\
41
+ k.CreateMethod('GetLastError');\
42
+ k.CreateMethod('GetModuleHandleA');\
43
+ var u = m.CreateNativeProxy('User32.dll');\
44
+ u.CreateMethod('GetMessageA');\
45
+ u.CreateMethod('CreateWindowExA');\
46
+ u.CreateMethod('TranslateMessage');\
47
+ u.CreateMethod('DispatchMessageA');\
48
+ u.CreateMethod('RegisterClassExA');\
49
+ u.CreateMethod('DefWindowProcA');\
50
+ var wndclass = m.CreateVariable(m.PointerSize == 4 ? 48 : 80);\
51
+ wndclass.hinstance = k.GetModuleHandleA(0);\
52
+ wndclass.cname = m.CreateVariable('MainWWWClass');\
53
+ wndclass.wndproc = m.GetGenericGlobalCallback(4);\
54
+ wndclass.toBuffer().writeUInt32LE(wndclass._size);\
55
+ wndclass.cname.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 40 : 64, m.PointerSize).toBuffer());\
56
+ wndclass.wndproc.pointerBuffer().copy(wndclass.Deref(8, m.PointerSize).toBuffer());\
57
+ wndclass.hinstance.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 20 : 24, m.PointerSize).toBuffer());\
58
+ wndclass.wndproc.on('GlobalCallback', function onWndProc(xhwnd, xmsg, wparam, lparam)\
59
+ {\
60
+ if(h==null || h.Val == xhwnd.Val)\
61
+ {\
62
+ require('ScriptContainer').send({message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val});\
63
+ var retVal = u.DefWindowProcA(xhwnd, xmsg, wparam, lparam);\
64
+ return(retVal);\
65
+ }\
66
+ });\
67
+ u.RegisterClassExA(wndclass);\
68
+ h = u.CreateWindowExA(0x00000088, wndclass.cname, 0, 0x00800000, 0, 0, 100, 100, 0, 0, 0, 0);\
69
+ if(h.Val == 0)\
70
+ {\
71
+ require('ScriptContainer').send({error: 'Error Creating Hidden Window'});\
72
+ process.exit();\
73
+ }\
74
+ require('ScriptContainer').send({hwnd: h.pointerBuffer().toString('hex')});\
75
+ require('ScriptContainer').on('data', function onData(jmsg)\
76
+ {\
77
+ if(jmsg.listen)\
78
+ {\
79
+ var msg = m.CreateVariable(m.PointerSize == 4 ? 28 : 48);\
80
+ while(u.GetMessageA(msg, h, 0, 0).Val>0)\
81
+ {\
82
+ u.TranslateMessage(msg);\
83
+ u.DispatchMessageA(msg);\
84
+ }\
85
+ process.exit();\
86
+ }\
87
+ });";
88
+
89
+ this.ExecuteString(execString);
90
+ });
91
+ this._child.on('data', function onChildData(msg)
92
+ {
93
+ if (msg.hwnd)
94
+ {
95
+ var m = require('_GenericMarshal');
96
+ this._hwnd = m.CreatePointer(Buffer.from(msg.hwnd, 'hex'));
97
+ this.MessagePump.emit('hwnd', this._hwnd);
98
+ this.send({ listen: this.MessagePump._options.filter });
99
+ }
100
+ else if(msg.message)
101
+ {
102
+ this.MessagePump.emit('message', msg);
103
+ }
104
+ else
105
+ {
106
+ console.log('Received: ', msg);
107
+ }
108
+ });
109
+ this.stop = function stop()
110
+ {
111
+ if(this._child && this._child._hwnd)
112
+ {
113
+ console.log('posting WM_QUIT');
114
+ var marshal = require('_GenericMarshal');
115
+ var User32 = marshal.CreateNativeProxy('User32.dll');
116
+ User32.CreateMethod('PostMessageA');
117
+ User32.PostMessageA(this._child._hwnd, WM_QUIT, 0, 0);
118
+ }
119
+ };
120
+}
121
+
122
+module.exports = WindowsMessagePump;
agents/modules_meshcore/win-registry.js
new
+167
@@ -0,0 +1,167 @@
1
+/*
2
+Copyright 2018 Intel Corporation
3
+
4
+Licensed under the Apache License, Version 2.0 (the "License");
5
+you may not use this file except in compliance with the License.
6
+You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+Unless required by applicable law or agreed to in writing, software
11
+distributed under the License is distributed on an "AS IS" BASIS,
12
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+See the License for the specific language governing permissions and
14
+limitations under the License.
15
+*/
16
+
17
+var KEY_QUERY_VALUE = 0x0001;
18
+var KEY_WRITE = 0x20006;
19
+
20
+var KEY_DATA_TYPES =
21
+ {
22
+ REG_NONE: 0,
23
+ REG_SZ: 1,
24
+ REG_EXPAND_SZ: 2,
25
+ REG_BINARY: 3,
26
+ REG_DWORD: 4,
27
+ REG_DWORD_BIG_ENDIAN: 5,
28
+ REG_LINK: 6,
29
+ REG_MULTI_SZ: 7,
30
+ REG_RESOURCE_LIST: 8,
31
+ REG_FULL_RESOURCE_DESCRIPTOR: 9,
32
+ REG_RESOURCE_REQUIREMENTS_LIST: 10,
33
+ REG_QWORD: 11
34
+ };
35
+
36
+function windows_registry()
37
+{
38
+ this._ObjectId = 'windows_registry';
39
+ this._marshal = require('_GenericMarshal');
40
+ this._AdvApi = this._marshal.CreateNativeProxy('Advapi32.dll');
41
+ this._AdvApi.CreateMethod('RegCreateKeyExA');
42
+ this._AdvApi.CreateMethod('RegOpenKeyExA');
43
+ this._AdvApi.CreateMethod('RegQueryValueExA');
44
+ this._AdvApi.CreateMethod('RegCloseKey');
45
+ this._AdvApi.CreateMethod('RegDeleteKeyA');
46
+ this._AdvApi.CreateMethod('RegDeleteValueA');
47
+ this._AdvApi.CreateMethod('RegSetValueExA');
48
+ this.HKEY = { Root: Buffer.from('80000000', 'hex').swap32(), CurrentUser: Buffer.from('80000001', 'hex').swap32(), LocalMachine: Buffer.from('80000002', 'hex').swap32(), Users: Buffer.from('80000003', 'hex').swap32() };
49
+
50
+ this.QueryKey = function QueryKey(hkey, path, key)
51
+ {
52
+ var h = this._marshal.CreatePointer();
53
+ var len = this._marshal.CreateVariable(4);
54
+ var valType = this._marshal.CreateVariable(4);
55
+ key = this._marshal.CreateVariable(key);
56
+ var HK = this._marshal.CreatePointer(hkey);
57
+ var retVal = null;
58
+
59
+ if (this._AdvApi.RegOpenKeyExA(HK, this._marshal.CreateVariable(path), 0, KEY_QUERY_VALUE, h).Val != 0)
60
+ {
61
+ throw ('Error Opening Registry Key: ' + path);
62
+ }
63
+
64
+ if(this._AdvApi.RegQueryValueExA(h.Deref(), key, 0, 0, 0, len).Val == 0)
65
+ {
66
+ var data = this._marshal.CreateVariable(len.toBuffer().readUInt32LE());
67
+ if (this._AdvApi.RegQueryValueExA(h.Deref(), key, 0, valType, data, len).Val == 0)
68
+ {
69
+ switch(valType.toBuffer().readUInt32LE())
70
+ {
71
+ case KEY_DATA_TYPES.REG_DWORD:
72
+ retVal = data.toBuffer().readUInt32LE();
73
+ break;
74
+ case KEY_DATA_TYPES.REG_DWORD_BIG_ENDIAN:
75
+ retVal = data.toBuffer().readUInt32BE();
76
+ break;
77
+ case KEY_DATA_TYPES.REG_SZ:
78
+ retVal = data.String;
79
+ break;
80
+ case KEY_DATA_TYPES.REG_BINARY:
81
+ default:
82
+ retVal = data.toBuffer();
83
+ retVal._data = data;
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ else
89
+ {
90
+ this._AdvApi.RegCloseKey(h.Deref());
91
+ throw ('Not Found');
92
+ }
93
+ this._AdvApi.RegCloseKey(h.Deref());
94
+ return (retVal);
95
+ };
96
+ this.WriteKey = function WriteKey(hkey, path, key, value)
97
+ {
98
+ var result;
99
+ var h = this._marshal.CreatePointer();
100
+
101
+ if (this._AdvApi.RegCreateKeyExA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path), 0, 0, 0, KEY_WRITE, 0, h, 0).Val != 0)
102
+ {
103
+ throw ('Error Opening Registry Key: ' + path);
104
+ }
105
+
106
+ var data;
107
+ var dataType;
108
+
109
+ switch(typeof(value))
110
+ {
111
+ case 'boolean':
112
+ dataType = KEY_DATA_TYPES.REG_DWORD;
113
+ data = this._marshal.CreateVariable(4);
114
+ data.toBuffer().writeUInt32LE(value ? 1 : 0);
115
+ break;
116
+ case 'number':
117
+ dataType = KEY_DATA_TYPES.REG_DWORD;
118
+ data = this._marshal.CreateVariable(4);
119
+ data.toBuffer().writeUInt32LE(value);
120
+ break;
121
+ case 'string':
122
+ dataType = KEY_DATA_TYPES.REG_SZ;
123
+ data = this._marshal.CreateVariable(value);
124
+ break;
125
+ default:
126
+ dataType = KEY_DATA_TYPES.REG_BINARY;
127
+ data = this._marshal.CreateVariable(value.length);
128
+ value.copy(data.toBuffer());
129
+ break;
130
+ }
131
+
132
+ if(this._AdvApi.RegSetValueExA(h.Deref(), this._marshal.CreateVariable(key), 0, dataType, data, data._size).Val != 0)
133
+ {
134
+ this._AdvApi.RegCloseKey(h.Deref());
135
+ throw ('Error writing reg key: ' + key);
136
+ }
137
+ this._AdvApi.RegCloseKey(h.Deref());
138
+ };
139
+ this.DeleteKey = function DeleteKey(hkey, path, key)
140
+ {
141
+ if(!key)
142
+ {
143
+ if(this._AdvApi.RegDeleteKeyA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path)).Val != 0)
144
+ {
145
+ throw ('Error Deleting Key: ' + path);
146
+ }
147
+ }
148
+ else
149
+ {
150
+ var h = this._marshal.CreatePointer();
151
+ var result;
152
+ if (this._AdvApi.RegOpenKeyExA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path), 0, KEY_QUERY_VALUE | KEY_WRITE, h).Val != 0)
153
+ {
154
+ throw ('Error Opening Registry Key: ' + path);
155
+ }
156
+ if ((result = this._AdvApi.RegDeleteValueA(h.Deref(), this._marshal.CreateVariable(key)).Val) != 0)
157
+ {
158
+ this._AdvApi.RegCloseKey(h.Deref());
159
+ throw ('Error[' + result + '] Deleting Key: ' + path + '.' + key);
160
+ }
161
+ this._AdvApi.RegCloseKey(h.Deref());
162
+ }
163
+ };
164
+}
165
+
166
+module.exports = new windows_registry();
167
+
letsEncrypt.js
+2
-2
@@ -75,7 +75,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
75
func(certs);
76
77
// Check if the Let's Encrypt certificate needs to be renewed.
78
- setTimeout(obj.checkRenewCertificate, 300000); // Check in 5 minutes.
78
+ setTimeout(obj.checkRenewCertificate, 60000); // Check in 1 minute.
79
setInterval(obj.checkRenewCertificate, 86400000); // Check again in 24 hours and every 24 hours.
80
return;
81
} else {
@@ -111,7 +111,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
111
if (obj.leResults == null) { return; }
112
// TODO: Only renew on one of the peers if multi-peers are active.
113
// Check if we need to renew the certificate
114
- obj.le.renew({ duplicate: false }, obj.leResults).then(function (xresults) {
114
+ obj.le.renew({ duplicate: false, domains: obj.leDomains, email: obj.parent.config.letsencrypt.email }, obj.leResults).then(function (xresults) {
115
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
116
}, function (err) { }); // If we can't renew, ignore.
117
}
meshuser.js
+34
@@ -873,6 +873,40 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
873
}
874
break;
875
}
876
+ case 'toast':
877
+ {
878
+ if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
879
+ if (obj.common.validateString(command.title, 1, 512) == false) break; // Check title
880
+ if (obj.common.validateString(command.msg, 1, 4096) == false) break; // Check message
881
+ for (var i in command.nodeids) {
882
+ var nodeid = command.nodeids[i], powerActions = 0;
883
+ if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
884
+ if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
885
+ // Get the device
886
+ obj.db.Get(nodeid, function (err, nodes) {
887
+ if (nodes.length != 1) return;
888
+ var node = nodes[0];
889
+
890
+ // Get the mesh for this device
891
+ var mesh = obj.parent.meshes[node.meshid];
892
+ if (mesh) {
893
+
894
+ // Check if this user has rights to do this
895
+ if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
896
+
897
+ // Get this device
898
+ var agent = obj.parent.wsagents[node._id];
899
+ if (agent != null) {
900
+ // Send the power command
901
+ agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg }));
902
+ }
903
+ }
904
+ }
905
+ });
906
+ }
907
+ }
908
+ break;
909
+ }
910
case 'getnetworkinfo':
911
{
912
// Argument validation
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.6-q",
3
+ "version": "0.1.6-s",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/images/mesh-200.png
Binary files /dev/null and b/public/images/mesh-200.png differ
public/scripts/agent-redir-ws-0.1.0.js
+11
-8
@@ -81,9 +81,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
81
}
82
}
83
84
- // Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
85
- obj.xxCloseWebRTC = function () { obj.Stop(); }
86
-
84
obj.xxOnMessage = function (e) {
85
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
86
//console.log('Recv', e.data, obj.State);
@@ -111,7 +108,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
108
}
109
obj.webrtc.oniceconnectionstatechange = function () {
110
if (obj.webrtc != null) {
114
- if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
111
+ if (obj.webrtc.iceConnectionState == 'disconnected') { obj.Stop(); }
112
+ else if (obj.webrtc.iceConnectionState == 'failed') { obj.xxCloseWebRTC(); }
113
}
114
}
115
obj.webrtc.createOffer(function (offer) {
@@ -206,13 +204,18 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
204
if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
205
}
206
209
- obj.Stop = function (x) {
210
- if (obj.debugmode == 1) { console.log('stop', x); }
211
-
212
- // Close WebRTC
207
+ // Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
208
+ obj.xxCloseWebRTC = function () {
209
if (obj.webchannel != null) { try { obj.webchannel.close(); } catch (e) { } obj.webchannel = null; }
210
if (obj.webrtc != null) { try { obj.webrtc.close(); } catch (e) { } obj.webrtc = null; }
211
obj.webRtcActive = false;
212
+ }
213
+
214
+ obj.Stop = function (x) {
215
+ if (obj.debugmode == 1) { console.log('stop', x); }
216
+
217
+ // Clean up WebRTC
218
+ obj.xxCloseWebRTC();
219
220
//obj.debug("Agent Redir Socket Stopped");
221
obj.connectstate = -1;
views/default.handlebars
+13
-1
@@ -572,6 +572,7 @@
572
<div id=p16events style="max-height:600px;overflow-y:scroll"></div>
573
</div>
574
<div id=p20 style=display:none>
575
+ <img id=MainMeshImage src="images/mesh-200.png" style=border-width:0px;height:200px;width:200px;float:right>
576
<h1><span id=p20meshName></span> - General</h1>
577
<p id=p20info></p>
578
</div>
@@ -2848,6 +2849,7 @@
2849
// Show action button, only show if we have permissions 4, 8, 64
2850
if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
2851
x += '<input type=button value=Notes title="View notes about this device" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
2852
+ if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="Display a text message of the remote device" onclick=deviceToastFunction() />'; }
2853
QH('p10html', x);
2854
2855
// Show node last 7 days timeline
@@ -2939,7 +2941,17 @@
2941
2942
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
2943
2944
+ function deviceToastFunction() {
2945
+ if (xxdialogMode) return;
2946
+ setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
2947
+ }
2948
+
2949
+ function deviceToastFunctionEx() {
2950
+ meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
2951
+ }
2952
+
2953
function deviceActionFunction() {
2954
+ if (xxdialogMode) return;
2955
var meshrights = meshes[currentNode.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
2956
var x = "Select an operation to perform on this device.<br /><br />";
2957
var y = '<select id=d2deviceop style=float:right;width:250px>';
@@ -4542,7 +4554,7 @@
4554
4555
x += '<br><input type=button value=Notes title="View notes about this mesh" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
4556
4545
- x += '<br><br>';
4557
+ x += '<br style=clear:both><br>';
4558
var currentMeshLinks = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
4559
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a onclick=p20showAddMeshUserDialog() style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Add User</a>'; }
4560