Added agent installation invite using email.

Ylian Saint-Hilaire committed Jan 23, 2018 at 14:15 UTC c3144c097a7de27576b22686cc0c7cc4e520d71d
19 files changed +387 -151
MeshCentralServer.njsproj
+8
@@ -21,8 +21,16 @@
21 <PropertyGroup Condition="'$(Configuration)' == 'Release'" />
22 <ItemGroup>
23 <Compile Include="agents\meshcore.js" />
24 + <Compile Include="agents\modules_meshcmd\amt-0.2.0.js" />
25 + <Compile Include="agents\modules_meshcmd\amt-scanner.js" />
26 + <Compile Include="agents\modules_meshcmd\amt-script-0.2.0.js" />
27 + <Compile Include="agents\modules_meshcmd\amt-wsman-0.2.0.js" />
28 + <Compile Include="agents\modules_meshcmd\amt-wsman-duk-0.2.0.js" />
29 <Compile Include="agents\modules_meshcmd\amt_heci.js" />
30 + <Compile Include="agents\modules_meshcmd\lme_heci.js" />
31 + <Compile Include="agents\modules_meshcore\amt-scanner.js" />
32 <Compile Include="agents\modules_meshcore\amt_heci.js" />
33 + <Compile Include="agents\modules_meshcore\lme_heci.js" />
34 <Compile Include="agents\modules_meshcore\WifiScanner.js" />
35 <Compile Include="agents\tinycore.js" />
36 <Compile Include="amtevents.js" />
agents/meshcore.js
+6 -2
@@ -719,6 +719,7 @@ function createMeshCore(agent) {
719 // Other side received websocket end of data marker, start sending data on WebRTC channel
720 if (this.httprequest.protocol == 1) { // Terminal
721 this.httprequest.process.stdout.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
722 + this.httprequest.process.stderr.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
723 } else if (this.httprequest.protocol == 2) { // Desktop
724 this.httprequest.desktop.kvm.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
725 }
@@ -731,12 +732,15 @@ function createMeshCore(agent) {
732 this.webrtc.on('dataChannel', function (rtcchannel) {
733 sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
734 rtcchannel.xrtc = this;
735 + rtcchannel.websocket = this.websocket;
736 this.rtcchannel = rtcchannel;
735 - this.rtcchannel.on('data', onTunnelWebRTCControlData);
736 - this.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
737 + this.websocket.rtcchannel = rtcchannel;
738 + this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
739 + this.websocket.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
740 if (this.websocket.httprequest.protocol == 1) { // Terminal
741 // 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
742 this.websocket.httprequest.process.stdout.unpipe(this.websocket);
743 + this.websocket.httprequest.process.stderr.unpipe(this.websocket);
744 this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
745 } else if (this.websocket.httprequest.protocol == 2) { // Desktop
746 // This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
agents/modules_meshcmd/amt-0.2.0.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 * @fileoverview Intel(r) AMT Communication StackXX
19 * @author Ylian Saint-Hilaire
agents/modules_meshcmd/amt-scanner.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 * @description Meshcentral Intel AMT Local Scanner
19 * @author Ylian Saint-Hilaire & Joko Sastriawan
agents/modules_meshcmd/amt-script-0.2.0.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 * @fileoverview Script Compiler / Decompiler / Runner
19 * @author Ylian Saint-Hilaire
agents/modules_meshcmd/amt-wsman-0.2.0.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 * @description Intel(r) AMT WSMAN Stack
19 * @author Ylian Saint-Hilaire
agents/modules_meshcmd/amt-wsman-duk-0.2.0.js
+17 -1
@@ -1,4 +1,20 @@
1 -/**
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 * @description WSMAN communication using duktape http
19 * @author Ylian Saint-Hilaire
20 * @version v0.2.0c
agents/modules_meshcmd/amt_heci.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 var Q = require('queue');
18
19 function amt_heci() {
agents/modules_meshcmd/lme_heci.js
+16 -1
@@ -1,3 +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 var MemoryStream = require('MemoryStream');
18 var lme_id = 0;
@@ -151,7 +166,7 @@ function lme_heci() {
166 }
167 this[name][port] = require('net').createServer();
168 this[name][port].HECI = this;
154 - this[name][port].listen({ port: port });
169 + this[name][port].listen({ port: port, host: '127.0.0.1' });
170 this[name][port].on('connection', function (socket) {
171 //console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
172 this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
agents/modules_meshcore/WifiScanner.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 var MemoryStream = require('MemoryStream');
18 var WindowsWireless = new Buffer([
19 0x0A, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x5F, 0x53, 0x63, 0x61, 0x6E, 0x28, 0x29, 0x0A, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x77, 0x6C, 0x61, 0x6E,
agents/modules_meshcore/amt-scanner.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 * @description Meshcentral Intel AMT Local Scanner
19 * @author Ylian Saint-Hilaire & Joko Sastriawan
agents/modules_meshcore/amt_heci.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 var Q = require('queue');
18
19 function amt_heci() {
agents/modules_meshcore/lme_heci.js
+105 -130
@@ -1,3 +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 var MemoryStream = require('MemoryStream');
18 var lme_id = 0;
@@ -21,8 +36,7 @@ var APF_CHANNEL_CLOSE = 97;
36 var APF_PROTOCOLVERSION = 192;
37
38
24 -function lme_object()
25 -{
39 +function lme_object() {
40 this.ourId = ++lme_id;
41 this.amtId = -1;
42 this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
@@ -32,12 +46,11 @@ function lme_object()
46 this.errorCount = 0;
47 }
48
35 -function stream_bufferedWrite()
36 -{
49 +function stream_bufferedWrite() {
50 var emitterUtils = require('events').inherits(this);
51 this.buffer = [];
52 this._readCheckImmediate = undefined;
40 -
53 +
54 // Writable Events
55 emitterUtils.createEvent('close');
56 emitterUtils.createEvent('drain');
@@ -45,21 +58,17 @@ function stream_bufferedWrite()
58 emitterUtils.createEvent('finish');
59 emitterUtils.createEvent('pipe');
60 emitterUtils.createEvent('unpipe');
48 -
61 +
62 // Readable Events
63 emitterUtils.createEvent('readable');
51 - this.isEmpty = function ()
52 - {
64 + this.isEmpty = function () {
65 return (this.buffer.length == 0);
66 };
55 - this.isWaiting = function ()
56 - {
67 + this.isWaiting = function () {
68 return (this._readCheckImmediate == undefined);
69 };
59 - this.write = function (chunk)
60 - {
61 - for (var args in arguments)
62 - {
70 + this.write = function (chunk) {
71 + for (var args in arguments) {
72 if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
73 }
74 var tmp = Buffer.alloc(chunk.length);
@@ -68,41 +77,34 @@ function stream_bufferedWrite()
77 this.emit('readable');
78 return (this.buffer.length == 0 ? true : false);
79 };
71 - this.read = function ()
72 - {
80 + this.read = function () {
81 var size = arguments.length == 0 ? undefined : arguments[0];
82 var bytesRead = 0;
83 var list = [];
76 - while((size == undefined || bytesRead < size) && this.buffer.length > 0)
77 - {
84 + while ((size == undefined || bytesRead < size) && this.buffer.length > 0) {
85 var len = this.buffer[0].data.length - this.buffer[0].offset;
86 var offset = this.buffer[0].offset;
80 -
81 - if(len > (size - bytesRead))
82 - {
87 +
88 + if (len > (size - bytesRead)) {
89 // Only reading a subset
90 list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
91 this.buffer[0].offset += (size - bytesRead);
92 bytesRead += (size - bytesRead);
93 }
88 - else
89 - {
94 + else {
95 // Reading the entire thing
96 list.push(this.buffer[0].data.slice(offset));
97 bytesRead += len;
98 this.buffer.shift();
99 }
100 }
96 - this._readCheckImmediate = setImmediate(function (buffered)
97 - {
101 + this._readCheckImmediate = setImmediate(function (buffered) {
102 buffered._readCheckImmediate = undefined;
99 - if(buffered.buffer.length == 0)
100 - {
103 + if (buffered.buffer.length == 0) {
104 // drained
105 buffered.emit('drain');
106 }
104 - else
105 - {
107 + else {
108 // not drained
109 buffered.emit('readable');
110 }
@@ -112,38 +114,33 @@ function stream_bufferedWrite()
114 }
115
116
115 -function lme_heci()
116 -{
117 +function lme_heci() {
118 var emitterUtils = require('events').inherits(this);
119 emitterUtils.createEvent('error');
120 emitterUtils.createEvent('connect');
120 -
121 +
122 var heci = require('heci');
123 this.INITIAL_RXWINDOW_SIZE = 4096;
123 -
124 +
125 this._LME = heci.create();
126 this._LME.LMS = this;
127 this._LME.on('error', function (e) { this.LMS.emit('error', e); });
127 - this._LME.on('connect', function ()
128 - {
128 + this._LME.on('connect', function () {
129 this.LMS.emit('connect');
130 - this.on('data', function (chunk)
131 - {
130 + this.on('data', function (chunk) {
131 // this = HECI
132 var cmd = chunk.readUInt8(0);
134 -
135 - switch(cmd)
136 - {
133 +
134 + switch (cmd) {
135 default:
136 //console.log('Received ' + chunk.length + ' bytes of data for LMS');
137 //console.log('Command = ' + cmd);
138 break;
141 - case APF_SERVICE_REQUEST:
139 + case APF_SERVICE_REQUEST:
140 var nameLen = chunk.readUInt32BE(1);
141 var name = chunk.slice(5, nameLen + 5);
142 //console.log("Service Request for: " + name);
145 - if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com')
146 - {
143 + if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com') {
144 var outBuffer = Buffer.alloc(5 + nameLen);
145 outBuffer.writeUInt8(6, 0);
146 outBuffer.writeUInt32BE(nameLen, 1);
@@ -151,30 +148,26 @@ function lme_heci()
148 this.write(outBuffer);
149 //console.log('Answering APF_SERVICE_REQUEST');
150 }
154 - else
155 - {
151 + else {
152 //console.log('UNKNOWN APF_SERVICE_REQUEST');
153 }
154 break;
159 - case APF_GLOBAL_REQUEST:
155 + case APF_GLOBAL_REQUEST:
156 var nameLen = chunk.readUInt32BE(1);
157 var name = chunk.slice(5, nameLen + 5).toString();
158
163 - switch(name)
164 - {
159 + switch (name) {
160 case 'tcpip-forward':
161 var len = chunk.readUInt32BE(nameLen + 6);
162 var port = chunk.readUInt32BE(nameLen + 10 + len);
163 //console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
169 - if (this[name] == undefined)
170 - {
164 + if (this[name] == undefined) {
165 this[name] = {};
166 }
167 this[name][port] = require('net').createServer();
168 this[name][port].HECI = this;
175 - this[name][port].listen({ port: port });
176 - this[name][port].on('connection', function (socket)
177 - {
169 + this[name][port].listen({ port: port, host: '127.0.0.1' });
170 + this[name][port].on('connection', function (socket) {
171 //console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
172 this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
173 });
@@ -192,54 +185,48 @@ function lme_heci()
185 break;
186 }
187 break;
195 - case APF_CHANNEL_OPEN_CONFIRMATION:
196 - var rChannel = chunk.readUInt32BE(1);
197 - var sChannel = chunk.readUInt32BE(5);
198 - var wSize = chunk.readUInt32BE(9);
199 - //console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
200 - if (this.sockets[rChannel] != undefined)
201 - {
202 - this.sockets[rChannel].lme.amtId = sChannel;
203 - this.sockets[rChannel].lme.rxWindow = wSize;
204 - this.sockets[rChannel].lme.txWindow = wSize;
205 - this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
206 - //console.log('LME_CS_CONNECTED');
207 - this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
208 - this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
209 - this.sockets[rChannel].bufferedStream.on('readable', function ()
210 - {
211 - if(this.socket.lme.txWindow > 0)
212 - {
213 - var buffer = this.read(this.socket.lme.txWindow);
214 - var packet = Buffer.alloc(9 + buffer.length);
215 - packet.writeUInt8(APF_CHANNEL_DATA, 0);
216 - packet.writeUInt32BE(this.socket.lme.amtId, 1);
217 - packet.writeUInt32BE(buffer.length, 5);
218 - buffer.copy(packet, 9);
219 - this.socket.lme.txWindow -= buffer.length;
220 - this.socket.HECI.write(packet);
221 - }
222 - });
223 - this.sockets[rChannel].bufferedStream.on('drain', function ()
224 - {
225 - this.socket.resume();
226 - });
227 - this.sockets[rChannel].on('data', function (chunk)
228 - {
229 - if (!this.bufferedStream.write(chunk)) { this.pause(); }
230 - });
231 - this.sockets[rChannel].on('end', function ()
232 - {
233 - var outBuffer = Buffer.alloc(5);
234 - outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
235 - outBuffer.writeUInt32BE(this.lme.amtId, 1);
236 - this.HECI.write(outBuffer);
237 - });
238 - this.sockets[rChannel].resume();
239 - }
240 -
241 - break;
242 - case APF_PROTOCOLVERSION:
188 + case APF_CHANNEL_OPEN_CONFIRMATION:
189 + var rChannel = chunk.readUInt32BE(1);
190 + var sChannel = chunk.readUInt32BE(5);
191 + var wSize = chunk.readUInt32BE(9);
192 + //console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
193 + if (this.sockets[rChannel] != undefined) {
194 + this.sockets[rChannel].lme.amtId = sChannel;
195 + this.sockets[rChannel].lme.rxWindow = wSize;
196 + this.sockets[rChannel].lme.txWindow = wSize;
197 + this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
198 + //console.log('LME_CS_CONNECTED');
199 + this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
200 + this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
201 + this.sockets[rChannel].bufferedStream.on('readable', function () {
202 + if (this.socket.lme.txWindow > 0) {
203 + var buffer = this.read(this.socket.lme.txWindow);
204 + var packet = Buffer.alloc(9 + buffer.length);
205 + packet.writeUInt8(APF_CHANNEL_DATA, 0);
206 + packet.writeUInt32BE(this.socket.lme.amtId, 1);
207 + packet.writeUInt32BE(buffer.length, 5);
208 + buffer.copy(packet, 9);
209 + this.socket.lme.txWindow -= buffer.length;
210 + this.socket.HECI.write(packet);
211 + }
212 + });
213 + this.sockets[rChannel].bufferedStream.on('drain', function () {
214 + this.socket.resume();
215 + });
216 + this.sockets[rChannel].on('data', function (chunk) {
217 + if (!this.bufferedStream.write(chunk)) { this.pause(); }
218 + });
219 + this.sockets[rChannel].on('end', function () {
220 + var outBuffer = Buffer.alloc(5);
221 + outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
222 + outBuffer.writeUInt32BE(this.lme.amtId, 1);
223 + this.HECI.write(outBuffer);
224 + });
225 + this.sockets[rChannel].resume();
226 + }
227 +
228 + break;
229 + case APF_PROTOCOLVERSION:
230 var major = chunk.readUInt32BE(1);
231 var minor = chunk.readUInt32BE(5);
232 var reason = chunk.readUInt32BE(9);
@@ -254,16 +241,13 @@ function lme_heci()
241 case APF_CHANNEL_WINDOW_ADJUST:
242 var rChannelId = chunk.readUInt32BE(1);
243 var bytesToAdd = chunk.readUInt32BE(5);
257 - if (this.sockets[rChannelId] != undefined)
258 - {
244 + if (this.sockets[rChannelId] != undefined) {
245 this.sockets[rChannelId].lme.txWindow += bytesToAdd;
260 - if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting())
261 - {
246 + if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting()) {
247 this.sockets[rChannelId].bufferedStream.emit('readable');
248 }
249 }
265 - else
266 - {
250 + else {
251 //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
252 }
253 break;
@@ -271,11 +255,9 @@ function lme_heci()
255 var rChannelId = chunk.readUInt32BE(1);
256 var dataLen = chunk.readUInt32BE(5);
257 var data = chunk.slice(9, 9 + dataLen);
274 - if (this.sockets[rChannelId] != undefined)
275 - {
258 + if (this.sockets[rChannelId] != undefined) {
259 this.sockets[rChannelId].pendingBytes.push(data.length);
277 - this.sockets[rChannelId].write(data, function ()
278 - {
260 + this.sockets[rChannelId].write(data, function () {
261 var written = this.pendingBytes.shift();
262 var outBuffer = Buffer.alloc(9);
263 outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
@@ -284,35 +266,31 @@ function lme_heci()
266 this.HECI.write(outBuffer);
267 });
268 }
287 - else
288 - {
269 + else {
270 //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
271 }
272 break;
273 case APF_CHANNEL_CLOSE:
274 var rChannelId = chunk.readUInt32BE(1);
294 - if (this.sockets[rChannelId] != undefined)
295 - {
296 - this.sockets[rChannelId].end();
275 + if (this.sockets[rChannelId] != undefined) {
276 + this.sockets[rChannelId].end();
277 var amtId = this.sockets[rChannelId].lme.amtId;
278 var buffer = Buffer.alloc(5);
279 delete this.sockets[rChannelId];
300 -
280 +
281 buffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
282 buffer.writeUInt32BE(amtId, 1);
283 this.write(buffer);
284 }
305 - else
306 - {
285 + else {
286 //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
287 }
288 break;
289 }
290 });
291 });
313 -
314 - this.bindDuplexStream = function (duplexStream, remoteFamily, localPort)
315 - {
292 +
293 + this.bindDuplexStream = function (duplexStream, remoteFamily, localPort) {
294 var socket = duplexStream;
295 //console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
296 socket.pendingBytes = [];
@@ -327,19 +305,16 @@ function lme_heci()
305 buffer.writeUInt32BE(socket.lme.ourId);
306 buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
307 buffer.writeUInt32BE(0xFFFFFFFF);
330 - for (var i = 0; i < 2; ++i)
331 - {
332 - if (remoteFamily == 'IPv6')
333 - {
308 + for (var i = 0; i < 2; ++i) {
309 + if (remoteFamily == 'IPv6') {
310 buffer.writeUInt32BE(3);
311 buffer.write('::1');
312 }
337 - else
338 - {
313 + else {
314 buffer.writeUInt32BE(9);
315 buffer.write('127.0.0.1');
316 }
342 -
317 +
318 buffer.writeUInt32BE(localPort);
319 }
320 this._LME.write(buffer.buffer);
@@ -347,7 +322,7 @@ function lme_heci()
322 this._LME.sockets[socket.lme.ourId] = socket;
323 socket.pause();
324 };
350 -
325 +
326 this._LME.connect(heci.GUIDS.LME, { noPipeline: 0 });
327 }
328
meshagent.js
+4 -3
@@ -148,10 +148,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
148 }
149 }
150 else if (cmdid == 15) { // MeshCommand_AgentTag
151 - ChangeAgentTag(msg.substring(2));
151 + var tag = msg.substring(2);
152 + while (tag.charCodeAt(tag.length - 1) == 0) { tag = tag.substring(0, tag.length - 1); } // Remove end-of-line zeros.
153 + ChangeAgentTag(tag);
154 }
153 - }
154 - else if (obj.authenticated < 2) { // We are not authenticated
155 + } else if (obj.authenticated < 2) { // We are not authenticated
156 var cmd = obj.common.ReadShort(msg, 0);
157 if (cmd == 1) {
158 // Agent authentication request
meshmail.js
+24 -6
@@ -26,6 +26,14 @@ module.exports.CreateMeshMain = function (parent) {
26 var accountResetMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b></td></tr></table><p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting an account password reset, click on the following link to complete the process.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to reset your account password.</a></p>If you did not initiate this request, please ignore this mail.</div>';
27 var accountResetMailText = '[[[SERVERNAME]]] - Account Reset\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting an account password reset. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n';
28
29 + // Default account invite mail
30 + var accountInviteSubject = '[[[SERVERNAME]]] - Agent Installation Invitation';
31 + var accountInviteMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Agent Installation</b></td></tr></table><p>User [[[USERNAME]]] on server <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting that you install a remote management agent. WARNING: this will allow the requester to <u>take control of your computer</u>. If you wish to do this, click on the following link to download the agent.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to download the MeshAgent for Windows.</a></p>If you did not know about this request, please ignore this mail.</div>';
32 + var accountInviteMailText = '[[[SERVERNAME]]] - Agent Installation Invitation\r\n\r\nUser [[[USERNAME]]] on server [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting you install a remote management agent. WARNING: This will allow the requester to take control of your computer. If you wish to do this, click on the following link to download the agent: [[[CALLBACKURL]]]\r\nIf you do not know about this request, please ignore this mail.\r\n';
33 +
34 + function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
35 + function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
36 +
37 // Setup mail server
38 var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: { rejectUnauthorized: false } };
39 if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; }
@@ -33,7 +41,7 @@ module.exports.CreateMeshMain = function (parent) {
41 obj.smtpServer = nodemailer.createTransport(options);
42
43 // Perform all e-mail substitution
36 - function mailReplacements(text, domain, username, email, cookie) {
44 + function mailReplacements(text, domain, username, email, options) {
45 var url;
46 if (domain.dns == null) {
47 // Default domain or subdomain of the default.
@@ -42,7 +50,10 @@ module.exports.CreateMeshMain = function (parent) {
50 // Domain with a DNS name.
51 url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + domain.dns + ':' + obj.parent.args.port + domain.url;
52 }
45 - if (cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + cookie) }
53 + if (options) {
54 + if (options.cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + options.cookie) }
55 + if (options.meshid != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'meshagents?id=3&meshid=' + options.meshid.split('/')[2] + '&tag=mailto:' + EscapeHtml(email)) }
56 + }
57 return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title);
58 }
59
@@ -54,17 +65,24 @@ module.exports.CreateMeshMain = function (parent) {
65
66 // Send account check mail
67 obj.sendAccountCheckMail = function (domain, username, email) {
57 - if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, no reset possible.
68 + if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, no reset possible.
69 var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 }, obj.mailCookieEncryptionKey);
59 - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, cookie), html: mailReplacements(accountCheckMailHtml, domain, username, email, cookie) });
70 + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, { cookie: cookie }), html: mailReplacements(accountCheckMailHtml, domain, username, email, { cookie: cookie }) });
71 sendNextMail();
72 }
73
74 // Send account reset mail
75 obj.sendAccountResetMail = function (domain, username, email) {
65 - if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, don't validate the email address.
76 + if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, don't validate the email address.
77 var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
67 - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, cookie), html: mailReplacements(accountResetMailHtml, domain, username, email, cookie) });
78 + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, { cookie: cookie }), html: mailReplacements(accountResetMailHtml, domain, username, email, { cookie: cookie }) });
79 + sendNextMail();
80 + }
81 +
82 + // Send agent invite mail
83 + obj.sendAgentInviteMail = function (domain, username, email, meshid) {
84 + if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, can't do this.
85 + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountInviteSubject, domain, username, email), text: mailReplacements(accountInviteMailText, domain, username, email, { meshid: meshid }), html: mailReplacements(accountInviteMailHtml, domain, username, email, { meshid: meshid }) });
86 sendNextMail();
87 }
88
meshuser.js
+20 -1
@@ -427,7 +427,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
427 if ((command.meshtype == 1) || (command.meshtype == 2)) {
428 // Create a type 1 agent-less Intel AMT mesh.
429 obj.parent.crypto.randomBytes(48, function (err, buf) {
430 - var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
430 + var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
431 var links = {}
432 links[user._id] = { name: user.name, rights: 0xFFFFFFFF };
433 var mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
@@ -876,6 +876,25 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
876 });
877 break;
878 }
879 + case 'inviteAgent':
880 + {
881 + if (obj.parent.parent.mailserver == null) return; // This operation requires the email server
882 + if ((obj.parent.parent.certificates.CommonName == null) || (obj.parent.parent.certificates.CommonName == 'un-configured')) return; // Server name must be configured
883 + if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
884 +
885 + // Get the mesh
886 + var mesh = obj.parent.meshes[command.meshid];
887 + if (mesh) {
888 + if (mesh.mtype != 2) return; // This operation is only allowed for mesh type 2, agent mesh
889 +
890 + // Check if this user has rights to do this
891 + //if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
892 +
893 + // Perform email invitation
894 + obj.parent.parent.mailserver.sendAgentInviteMail(domain, user.name, command.email, command.meshid);
895 + }
896 + break;
897 + }
898 }
899 });
900
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.1.2-s",
3 + "version": "0.1.3-c",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
views/default.handlebars
+52 -5
@@ -1283,9 +1283,10 @@
1283 }
1284
1285 function ondockeydown(e) {
1286 - if (!xxdialogMode && xxcurrentView == 11 && desktop) return desktop.m.handleKeyDown(e);
1287 - if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyDown(e);
1286 + if (!xxdialogMode && xxcurrentView == 11 && desktop) { return desktop.m.handleKeyDown(e); }
1287 + if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyDown(e); }
1288 if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
1289 + if (!xxdialogMode && xxcurrentView == 15) { return agentConsoleHandleKeys(e); }
1290 if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
1291 var processed = 0;
1292 if (Q('viewselect').value < 3) {
@@ -1460,6 +1461,9 @@
1461 }
1462 if (mesh.mtype == 2) {
1463 r += ' <a style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
1464 + if (features & 64) {
1465 + r += ' <a style=cursor:pointer;font-size:10px title="Invite someone to install the mesh agent." onclick=inviteAgentToMesh(\"' + mesh._id + '\")>Invite</a>';
1466 + }
1467 }
1468 return r;
1469 }
@@ -1568,6 +1572,33 @@
1572 QV('dlgAddCira2', val == 2);
1573 }
1574
1575 + // Return true is the input string looks like an email address
1576 + function checkEmail(str) {
1577 + var x = str.split('@');
1578 + var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
1579 + if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
1580 + return ok;
1581 + }
1582 +
1583 + function inviteAgentToMesh(meshid) {
1584 + if (xxdialogMode) return;
1585 + var mesh = meshes[meshid];
1586 + var meshidx = meshid.substring(5);
1587 + if (meshidx[0] == '/') meshidx = meshidx.substring(1);
1588 + var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".<br /><br />";
1589 + x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>');
1590 + setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid);
1591 + validateAgentInvite();
1592 + }
1593 +
1594 + function validateAgentInvite() {
1595 + QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
1596 + }
1597 +
1598 + function performAgentInvite(button, meshid) {
1599 + meshserver.Send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value });
1600 + }
1601 +
1602 function addAgentToMesh(meshid) {
1603 if (xxdialogMode) return;
1604 var mesh = meshes[meshid];
@@ -1580,7 +1611,7 @@
1611 //x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
1612 x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
1613 x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank">Windows executable (.exe)</a>');
1583 - //x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>');
1614 + if (debugmode == true) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
1615 x += "</div>";
1616
1617 // Linux agent install
@@ -2491,7 +2522,9 @@
2522
2523 // Attribute: Mesh Agent Tag
2524 if ((node.agent != null) && (node.agent.tag != null)) {
2494 - x += addDeviceAttribute('Agent Tag', node.agent.tag);
2525 + var tag = EscapeHtml(node.agent.tag);
2526 + if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
2527 + x += addDeviceAttribute('Agent Tag', tag);
2528 }
2529
2530 // Attribute: Intel AMT
@@ -3664,7 +3697,6 @@
3697 if (e.keyCode == 13 && consoleFocus == 0) { p15consoleSend(e); processed = 1; }
3698 else if (e.keyCode == 8 && consoleFocus == 0) { var x = box.value; box.value = x.substring(0, x.length - 1); processed = 1; }
3699 else if (e.keyCode == 27) { box.value = ''; processed = 1; }
3667 - else if (e.key.length === 1 && consoleFocus == 0) { box.value = ((box.value + e.key)); processed = 1; }
3700 else if ((e.keyCode == 38) || (e.keyCode == 40)) { // Arrow up || Arrow down
3701 var hindex = consoleHistory.indexOf(box.value);
3702 //console.log(hindex, consoleHistory);
@@ -3673,12 +3705,27 @@
3705 else if ((e.keyCode == 40) && (hindex == 0)) { box.value = ''; }
3706 processed = 1;
3707 }
3708 + else if (e.key.length === 1) {
3709 + //box.value = ((box.value + e.key));
3710 + insertTextAtCursor(box, e.key);
3711 + processed = 1;
3712 + }
3713 } else {
3714 if (e.charCode != 0 && consoleFocus == 0) { box.value = ((box.value + String.fromCharCode(e.charCode))); processed = 1; }
3715 }
3716 if (processed > 0) { return haltEvent(e); }
3717 }
3718
3719 + // Insert text at the cursor location on the
3720 + function insertTextAtCursor(ctrl, val) {
3721 + if (document.selection) { ctrl.focus(); sel = document.selection.createRange(); sel.text = val; }
3722 + else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
3723 + var start = ctrl.selectionStart, end = ctrl.selectionEnd;
3724 + ctrl.value = ctrl.value.substring(0, start) + val + ctrl.value.substring(end, ctrl.value.length);
3725 + ctrl.setSelectionRange(end + 1, end + 1);
3726 + } else { ctrl.value += myValue; }
3727 + }
3728 +
3729 var consoleNode;
3730 function setupConsole() {
3731 // Setup the console
webserver.js
+6 -1
@@ -675,6 +675,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
675 user = obj.users[req.session.userid]
676 logoutcontrol = 'Welcome ' + user.name + '.';
677 }
678 +
679 + // Give the web page a list of supported server features
680 var features = 0;
681 if (obj.args.wanonly == true) { features += 1; } // WAN-only mode
682 if (obj.args.lanonly == true) { features += 2; } // LAN-only mode
@@ -682,6 +684,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
684 if (domain.userQuota == -1) { features += 8; } // No server files mode
685 if (obj.args.tlsoffload == true) { features += 16; } // No mutual-auth CIRA
686 if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
687 + if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName != 'un-configured')) { features += 64; } // Email invites
688 +
689 + // Send the master web application
690 if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
691 res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64, footer: (domain.footer == null) ? '' : domain.footer });
692 } else {
@@ -1426,7 +1431,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1431 if (xdomain != '') xdomain += "/";
1432 var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
1433 if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + obj.args.port + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1429 -
1434 + if (req.query.tag != true) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
1435 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
1436 obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe });
1437 });