Added agent installation invite using email.

This commit is contained in:
Ylian Saint-Hilaire 2018-01-23 14:15:59 -08:00
parent 65f99a3c31
commit c3144c097a
19 changed files with 387 additions and 151 deletions

View File

@ -21,8 +21,16 @@
<PropertyGroup Condition="'$(Configuration)' == 'Release'" />
<ItemGroup>
<Compile Include="agents\meshcore.js" />
<Compile Include="agents\modules_meshcmd\amt-0.2.0.js" />
<Compile Include="agents\modules_meshcmd\amt-scanner.js" />
<Compile Include="agents\modules_meshcmd\amt-script-0.2.0.js" />
<Compile Include="agents\modules_meshcmd\amt-wsman-0.2.0.js" />
<Compile Include="agents\modules_meshcmd\amt-wsman-duk-0.2.0.js" />
<Compile Include="agents\modules_meshcmd\amt_heci.js" />
<Compile Include="agents\modules_meshcmd\lme_heci.js" />
<Compile Include="agents\modules_meshcore\amt-scanner.js" />
<Compile Include="agents\modules_meshcore\amt_heci.js" />
<Compile Include="agents\modules_meshcore\lme_heci.js" />
<Compile Include="agents\modules_meshcore\WifiScanner.js" />
<Compile Include="agents\tinycore.js" />
<Compile Include="amtevents.js" />

View File

@ -719,6 +719,7 @@ function createMeshCore(agent) {
// Other side received websocket end of data marker, start sending data on WebRTC channel
if (this.httprequest.protocol == 1) { // Terminal
this.httprequest.process.stdout.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
this.httprequest.process.stderr.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
} else if (this.httprequest.protocol == 2) { // Desktop
this.httprequest.desktop.kvm.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
}
@ -731,12 +732,15 @@ function createMeshCore(agent) {
this.webrtc.on('dataChannel', function (rtcchannel) {
sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
rtcchannel.xrtc = this;
rtcchannel.websocket = this.websocket;
this.rtcchannel = rtcchannel;
this.rtcchannel.on('data', onTunnelWebRTCControlData);
this.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
this.websocket.rtcchannel = rtcchannel;
this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
this.websocket.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
if (this.websocket.httprequest.protocol == 1) { // Terminal
// 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
this.websocket.httprequest.process.stdout.unpipe(this.websocket);
this.websocket.httprequest.process.stderr.unpipe(this.websocket);
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
} else if (this.websocket.httprequest.protocol == 2) { // Desktop
// 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

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @fileoverview Intel(r) AMT Communication StackXX
* @author Ylian Saint-Hilaire

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @description Meshcentral Intel AMT Local Scanner
* @author Ylian Saint-Hilaire & Joko Sastriawan

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @fileoverview Script Compiler / Decompiler / Runner
* @author Ylian Saint-Hilaire

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @description Intel(r) AMT WSMAN Stack
* @author Ylian Saint-Hilaire

View File

@ -1,4 +1,20 @@
/**
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @description WSMAN communication using duktape http
* @author Ylian Saint-Hilaire
* @version v0.2.0c

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var Q = require('queue');
function amt_heci() {

View File

@ -1,3 +1,18 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var MemoryStream = require('MemoryStream');
var lme_id = 0;
@ -151,7 +166,7 @@ function lme_heci() {
}
this[name][port] = require('net').createServer();
this[name][port].HECI = this;
this[name][port].listen({ port: port });
this[name][port].listen({ port: port, host: '127.0.0.1' });
this[name][port].on('connection', function (socket) {
//console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var MemoryStream = require('MemoryStream');
var WindowsWireless = new Buffer([
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,

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @description Meshcentral Intel AMT Local Scanner
* @author Ylian Saint-Hilaire & Joko Sastriawan

View File

@ -1,3 +1,19 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var Q = require('queue');
function amt_heci() {

View File

@ -1,3 +1,18 @@
/*
Copyright 2018 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var MemoryStream = require('MemoryStream');
var lme_id = 0;
@ -21,8 +36,7 @@ var APF_CHANNEL_CLOSE = 97;
var APF_PROTOCOLVERSION = 192;
function lme_object()
{
function lme_object() {
this.ourId = ++lme_id;
this.amtId = -1;
this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
@ -32,8 +46,7 @@ function lme_object()
this.errorCount = 0;
}
function stream_bufferedWrite()
{
function stream_bufferedWrite() {
var emitterUtils = require('events').inherits(this);
this.buffer = [];
this._readCheckImmediate = undefined;
@ -48,18 +61,14 @@ function stream_bufferedWrite()
// Readable Events
emitterUtils.createEvent('readable');
this.isEmpty = function ()
{
this.isEmpty = function () {
return (this.buffer.length == 0);
};
this.isWaiting = function ()
{
this.isWaiting = function () {
return (this._readCheckImmediate == undefined);
};
this.write = function (chunk)
{
for (var args in arguments)
{
this.write = function (chunk) {
for (var args in arguments) {
if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
}
var tmp = Buffer.alloc(chunk.length);
@ -68,41 +77,34 @@ function stream_bufferedWrite()
this.emit('readable');
return (this.buffer.length == 0 ? true : false);
};
this.read = function ()
{
this.read = function () {
var size = arguments.length == 0 ? undefined : arguments[0];
var bytesRead = 0;
var list = [];
while((size == undefined || bytesRead < size) && this.buffer.length > 0)
{
while ((size == undefined || bytesRead < size) && this.buffer.length > 0) {
var len = this.buffer[0].data.length - this.buffer[0].offset;
var offset = this.buffer[0].offset;
if(len > (size - bytesRead))
{
if (len > (size - bytesRead)) {
// Only reading a subset
list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
this.buffer[0].offset += (size - bytesRead);
bytesRead += (size - bytesRead);
}
else
{
else {
// Reading the entire thing
list.push(this.buffer[0].data.slice(offset));
bytesRead += len;
this.buffer.shift();
}
}
this._readCheckImmediate = setImmediate(function (buffered)
{
this._readCheckImmediate = setImmediate(function (buffered) {
buffered._readCheckImmediate = undefined;
if(buffered.buffer.length == 0)
{
if (buffered.buffer.length == 0) {
// drained
buffered.emit('drain');
}
else
{
else {
// not drained
buffered.emit('readable');
}
@ -112,8 +114,7 @@ function stream_bufferedWrite()
}
function lme_heci()
{
function lme_heci() {
var emitterUtils = require('events').inherits(this);
emitterUtils.createEvent('error');
emitterUtils.createEvent('connect');
@ -124,16 +125,13 @@ function lme_heci()
this._LME = heci.create();
this._LME.LMS = this;
this._LME.on('error', function (e) { this.LMS.emit('error', e); });
this._LME.on('connect', function ()
{
this._LME.on('connect', function () {
this.LMS.emit('connect');
this.on('data', function (chunk)
{
this.on('data', function (chunk) {
// this = HECI
var cmd = chunk.readUInt8(0);
switch(cmd)
{
switch (cmd) {
default:
//console.log('Received ' + chunk.length + ' bytes of data for LMS');
//console.log('Command = ' + cmd);
@ -142,8 +140,7 @@ function lme_heci()
var nameLen = chunk.readUInt32BE(1);
var name = chunk.slice(5, nameLen + 5);
//console.log("Service Request for: " + name);
if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com')
{
if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com') {
var outBuffer = Buffer.alloc(5 + nameLen);
outBuffer.writeUInt8(6, 0);
outBuffer.writeUInt32BE(nameLen, 1);
@ -151,8 +148,7 @@ function lme_heci()
this.write(outBuffer);
//console.log('Answering APF_SERVICE_REQUEST');
}
else
{
else {
//console.log('UNKNOWN APF_SERVICE_REQUEST');
}
break;
@ -160,21 +156,18 @@ function lme_heci()
var nameLen = chunk.readUInt32BE(1);
var name = chunk.slice(5, nameLen + 5).toString();
switch(name)
{
switch (name) {
case 'tcpip-forward':
var len = chunk.readUInt32BE(nameLen + 6);
var port = chunk.readUInt32BE(nameLen + 10 + len);
//console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
if (this[name] == undefined)
{
if (this[name] == undefined) {
this[name] = {};
}
this[name][port] = require('net').createServer();
this[name][port].HECI = this;
this[name][port].listen({ port: port });
this[name][port].on('connection', function (socket)
{
this[name][port].listen({ port: port, host: '127.0.0.1' });
this[name][port].on('connection', function (socket) {
//console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
});
@ -193,52 +186,46 @@ function lme_heci()
}
break;
case APF_CHANNEL_OPEN_CONFIRMATION:
var rChannel = chunk.readUInt32BE(1);
var sChannel = chunk.readUInt32BE(5);
var wSize = chunk.readUInt32BE(9);
//console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
if (this.sockets[rChannel] != undefined)
{
this.sockets[rChannel].lme.amtId = sChannel;
this.sockets[rChannel].lme.rxWindow = wSize;
this.sockets[rChannel].lme.txWindow = wSize;
this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
//console.log('LME_CS_CONNECTED');
this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
this.sockets[rChannel].bufferedStream.on('readable', function ()
{
if(this.socket.lme.txWindow > 0)
{
var buffer = this.read(this.socket.lme.txWindow);
var packet = Buffer.alloc(9 + buffer.length);
packet.writeUInt8(APF_CHANNEL_DATA, 0);
packet.writeUInt32BE(this.socket.lme.amtId, 1);
packet.writeUInt32BE(buffer.length, 5);
buffer.copy(packet, 9);
this.socket.lme.txWindow -= buffer.length;
this.socket.HECI.write(packet);
}
});
this.sockets[rChannel].bufferedStream.on('drain', function ()
{
this.socket.resume();
});
this.sockets[rChannel].on('data', function (chunk)
{
if (!this.bufferedStream.write(chunk)) { this.pause(); }
});
this.sockets[rChannel].on('end', function ()
{
var outBuffer = Buffer.alloc(5);
outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
outBuffer.writeUInt32BE(this.lme.amtId, 1);
this.HECI.write(outBuffer);
});
this.sockets[rChannel].resume();
}
var rChannel = chunk.readUInt32BE(1);
var sChannel = chunk.readUInt32BE(5);
var wSize = chunk.readUInt32BE(9);
//console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
if (this.sockets[rChannel] != undefined) {
this.sockets[rChannel].lme.amtId = sChannel;
this.sockets[rChannel].lme.rxWindow = wSize;
this.sockets[rChannel].lme.txWindow = wSize;
this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
//console.log('LME_CS_CONNECTED');
this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
this.sockets[rChannel].bufferedStream.on('readable', function () {
if (this.socket.lme.txWindow > 0) {
var buffer = this.read(this.socket.lme.txWindow);
var packet = Buffer.alloc(9 + buffer.length);
packet.writeUInt8(APF_CHANNEL_DATA, 0);
packet.writeUInt32BE(this.socket.lme.amtId, 1);
packet.writeUInt32BE(buffer.length, 5);
buffer.copy(packet, 9);
this.socket.lme.txWindow -= buffer.length;
this.socket.HECI.write(packet);
}
});
this.sockets[rChannel].bufferedStream.on('drain', function () {
this.socket.resume();
});
this.sockets[rChannel].on('data', function (chunk) {
if (!this.bufferedStream.write(chunk)) { this.pause(); }
});
this.sockets[rChannel].on('end', function () {
var outBuffer = Buffer.alloc(5);
outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
outBuffer.writeUInt32BE(this.lme.amtId, 1);
this.HECI.write(outBuffer);
});
this.sockets[rChannel].resume();
}
break;
break;
case APF_PROTOCOLVERSION:
var major = chunk.readUInt32BE(1);
var minor = chunk.readUInt32BE(5);
@ -254,16 +241,13 @@ function lme_heci()
case APF_CHANNEL_WINDOW_ADJUST:
var rChannelId = chunk.readUInt32BE(1);
var bytesToAdd = chunk.readUInt32BE(5);
if (this.sockets[rChannelId] != undefined)
{
if (this.sockets[rChannelId] != undefined) {
this.sockets[rChannelId].lme.txWindow += bytesToAdd;
if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting())
{
if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting()) {
this.sockets[rChannelId].bufferedStream.emit('readable');
}
}
else
{
else {
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
}
break;
@ -271,11 +255,9 @@ function lme_heci()
var rChannelId = chunk.readUInt32BE(1);
var dataLen = chunk.readUInt32BE(5);
var data = chunk.slice(9, 9 + dataLen);
if (this.sockets[rChannelId] != undefined)
{
if (this.sockets[rChannelId] != undefined) {
this.sockets[rChannelId].pendingBytes.push(data.length);
this.sockets[rChannelId].write(data, function ()
{
this.sockets[rChannelId].write(data, function () {
var written = this.pendingBytes.shift();
var outBuffer = Buffer.alloc(9);
outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
@ -284,15 +266,13 @@ function lme_heci()
this.HECI.write(outBuffer);
});
}
else
{
else {
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
}
break;
case APF_CHANNEL_CLOSE:
var rChannelId = chunk.readUInt32BE(1);
if (this.sockets[rChannelId] != undefined)
{
if (this.sockets[rChannelId] != undefined) {
this.sockets[rChannelId].end();
var amtId = this.sockets[rChannelId].lme.amtId;
var buffer = Buffer.alloc(5);
@ -302,8 +282,7 @@ function lme_heci()
buffer.writeUInt32BE(amtId, 1);
this.write(buffer);
}
else
{
else {
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
}
break;
@ -311,8 +290,7 @@ function lme_heci()
});
});
this.bindDuplexStream = function (duplexStream, remoteFamily, localPort)
{
this.bindDuplexStream = function (duplexStream, remoteFamily, localPort) {
var socket = duplexStream;
//console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
socket.pendingBytes = [];
@ -327,15 +305,12 @@ function lme_heci()
buffer.writeUInt32BE(socket.lme.ourId);
buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
buffer.writeUInt32BE(0xFFFFFFFF);
for (var i = 0; i < 2; ++i)
{
if (remoteFamily == 'IPv6')
{
for (var i = 0; i < 2; ++i) {
if (remoteFamily == 'IPv6') {
buffer.writeUInt32BE(3);
buffer.write('::1');
}
else
{
else {
buffer.writeUInt32BE(9);
buffer.write('127.0.0.1');
}

View File

@ -148,10 +148,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
}
}
else if (cmdid == 15) { // MeshCommand_AgentTag
ChangeAgentTag(msg.substring(2));
var tag = msg.substring(2);
while (tag.charCodeAt(tag.length - 1) == 0) { tag = tag.substring(0, tag.length - 1); } // Remove end-of-line zeros.
ChangeAgentTag(tag);
}
}
else if (obj.authenticated < 2) { // We are not authenticated
} else if (obj.authenticated < 2) { // We are not authenticated
var cmd = obj.common.ReadShort(msg, 0);
if (cmd == 1) {
// Agent authentication request

View File

@ -26,6 +26,14 @@ module.exports.CreateMeshMain = function (parent) {
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>';
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';
// Default account invite mail
var accountInviteSubject = '[[[SERVERNAME]]] - Agent Installation Invitation';
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>';
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';
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; }
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; }
// Setup mail server
var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: { rejectUnauthorized: false } };
if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; }
@ -33,7 +41,7 @@ module.exports.CreateMeshMain = function (parent) {
obj.smtpServer = nodemailer.createTransport(options);
// Perform all e-mail substitution
function mailReplacements(text, domain, username, email, cookie) {
function mailReplacements(text, domain, username, email, options) {
var url;
if (domain.dns == null) {
// Default domain or subdomain of the default.
@ -42,7 +50,10 @@ module.exports.CreateMeshMain = function (parent) {
// Domain with a DNS name.
url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + domain.dns + ':' + obj.parent.args.port + domain.url;
}
if (cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + cookie) }
if (options) {
if (options.cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + options.cookie) }
if (options.meshid != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'meshagents?id=3&meshid=' + options.meshid.split('/')[2] + '&tag=mailto:' + EscapeHtml(email)) }
}
return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title);
}
@ -54,17 +65,24 @@ module.exports.CreateMeshMain = function (parent) {
// Send account check mail
obj.sendAccountCheckMail = function (domain, username, email) {
if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, no reset possible.
if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, no reset possible.
var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 }, obj.mailCookieEncryptionKey);
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) });
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 }) });
sendNextMail();
}
// Send account reset mail
obj.sendAccountResetMail = function (domain, username, email) {
if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, don't validate the email address.
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.
var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
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) });
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 }) });
sendNextMail();
}
// Send agent invite mail
obj.sendAgentInviteMail = function (domain, username, email, meshid) {
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.
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 }) });
sendNextMail();
}

View File

@ -427,7 +427,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
if ((command.meshtype == 1) || (command.meshtype == 2)) {
// Create a type 1 agent-less Intel AMT mesh.
obj.parent.crypto.randomBytes(48, function (err, buf) {
var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
var links = {}
links[user._id] = { name: user.name, rights: 0xFFFFFFFF };
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) {
});
break;
}
case 'inviteAgent':
{
if (obj.parent.parent.mailserver == null) return; // This operation requires the email server
if ((obj.parent.parent.certificates.CommonName == null) || (obj.parent.parent.certificates.CommonName == 'un-configured')) return; // Server name must be configured
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Get the mesh
var mesh = obj.parent.meshes[command.meshid];
if (mesh) {
if (mesh.mtype != 2) return; // This operation is only allowed for mesh type 2, agent mesh
// Check if this user has rights to do this
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
// Perform email invitation
obj.parent.parent.mailserver.sendAgentInviteMail(domain, user.name, command.email, command.meshid);
}
break;
}
}
});

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.1.2-s",
"version": "0.1.3-c",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -1283,9 +1283,10 @@
}
function ondockeydown(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop) return desktop.m.handleKeyDown(e);
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyDown(e);
if (!xxdialogMode && xxcurrentView == 11 && desktop) { return desktop.m.handleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
if (!xxdialogMode && xxcurrentView == 15) { return agentConsoleHandleKeys(e); }
if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
var processed = 0;
if (Q('viewselect').value < 3) {
@ -1460,6 +1461,9 @@
}
if (mesh.mtype == 2) {
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>';
if (features & 64) {
r += ' <a style=cursor:pointer;font-size:10px title="Invite someone to install the mesh agent." onclick=inviteAgentToMesh(\"' + mesh._id + '\")>Invite</a>';
}
}
return r;
}
@ -1568,6 +1572,33 @@
QV('dlgAddCira2', val == 2);
}
// Return true is the input string looks like an email address
function checkEmail(str) {
var x = str.split('@');
var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
return ok;
}
function inviteAgentToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid];
var meshidx = meshid.substring(5);
if (meshidx[0] == '/') meshidx = meshidx.substring(1);
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 />";
x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>');
setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid);
validateAgentInvite();
}
function validateAgentInvite() {
QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
}
function performAgentInvite(button, meshid) {
meshserver.Send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value });
}
function addAgentToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid];
@ -1580,7 +1611,7 @@
//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 />";
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 />";
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank">Windows executable (.exe)</a>');
//x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>');
if (debugmode == true) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
x += "</div>";
// Linux agent install
@ -2491,7 +2522,9 @@
// Attribute: Mesh Agent Tag
if ((node.agent != null) && (node.agent.tag != null)) {
x += addDeviceAttribute('Agent Tag', node.agent.tag);
var tag = EscapeHtml(node.agent.tag);
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
x += addDeviceAttribute('Agent Tag', tag);
}
// Attribute: Intel AMT
@ -3664,7 +3697,6 @@
if (e.keyCode == 13 && consoleFocus == 0) { p15consoleSend(e); processed = 1; }
else if (e.keyCode == 8 && consoleFocus == 0) { var x = box.value; box.value = x.substring(0, x.length - 1); processed = 1; }
else if (e.keyCode == 27) { box.value = ''; processed = 1; }
else if (e.key.length === 1 && consoleFocus == 0) { box.value = ((box.value + e.key)); processed = 1; }
else if ((e.keyCode == 38) || (e.keyCode == 40)) { // Arrow up || Arrow down
var hindex = consoleHistory.indexOf(box.value);
//console.log(hindex, consoleHistory);
@ -3673,12 +3705,27 @@
else if ((e.keyCode == 40) && (hindex == 0)) { box.value = ''; }
processed = 1;
}
else if (e.key.length === 1) {
//box.value = ((box.value + e.key));
insertTextAtCursor(box, e.key);
processed = 1;
}
} else {
if (e.charCode != 0 && consoleFocus == 0) { box.value = ((box.value + String.fromCharCode(e.charCode))); processed = 1; }
}
if (processed > 0) { return haltEvent(e); }
}
// Insert text at the cursor location on the
function insertTextAtCursor(ctrl, val) {
if (document.selection) { ctrl.focus(); sel = document.selection.createRange(); sel.text = val; }
else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
var start = ctrl.selectionStart, end = ctrl.selectionEnd;
ctrl.value = ctrl.value.substring(0, start) + val + ctrl.value.substring(end, ctrl.value.length);
ctrl.setSelectionRange(end + 1, end + 1);
} else { ctrl.value += myValue; }
}
var consoleNode;
function setupConsole() {
// Setup the console

View File

@ -675,6 +675,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
user = obj.users[req.session.userid]
logoutcontrol = 'Welcome ' + user.name + '.';
}
// Give the web page a list of supported server features
var features = 0;
if (obj.args.wanonly == true) { features += 1; } // WAN-only mode
if (obj.args.lanonly == true) { features += 2; } // LAN-only mode
@ -682,6 +684,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
if (domain.userQuota == -1) { features += 8; } // No server files mode
if (obj.args.tlsoffload == true) { features += 16; } // No mutual-auth CIRA
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName != 'un-configured')) { features += 64; } // Email invites
// Send the master web application
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
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 });
} else {
@ -1426,7 +1431,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
if (xdomain != '') xdomain += "/";
var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
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"; }
if (req.query.tag != true) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
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 });
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 });
});