mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-23 21:55:52 -05:00
Merge branch 'master' into master
This commit is contained in:
commit
27c34b9540
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -423,6 +423,8 @@ function createMeshCore(agent) {
|
||||
tunnel.on('error', function (e) { sendConsoleText('ERROR: ' + JSON.stringify(e)); });
|
||||
tunnel.sessionid = data.sessionid;
|
||||
tunnel.rights = data.rights;
|
||||
tunnel.consent = data.consent;
|
||||
tunnel.username = data.username;
|
||||
tunnel.state = 0;
|
||||
tunnel.url = xurl;
|
||||
tunnel.protocol = 0;
|
||||
@ -706,6 +708,11 @@ function createMeshCore(agent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform notification if needed
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 2)) {
|
||||
require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.');
|
||||
}
|
||||
|
||||
// Remote terminal using native pipes
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
@ -759,14 +766,16 @@ function createMeshCore(agent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform notification if needed
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
|
||||
require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.');
|
||||
}
|
||||
|
||||
// Remote desktop using native pipes
|
||||
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
|
||||
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
|
||||
this.desktop = this.httprequest.desktop;
|
||||
|
||||
// Display a toast message
|
||||
//require('toaster').Toast('MeshCentral', 'Remote Desktop Control Started.');
|
||||
|
||||
this.end = function () {
|
||||
--this.desktop.kvm.connectionCount;
|
||||
|
||||
@ -811,6 +820,11 @@ function createMeshCore(agent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform notification if needed
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 4)) {
|
||||
require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file access.');
|
||||
}
|
||||
|
||||
// Setup files
|
||||
// NOP
|
||||
}
|
||||
|
2
agents/meshcore.min.js
vendored
2
agents/meshcore.min.js
vendored
File diff suppressed because one or more lines are too long
206
agents/meshcore_diagnostic.js
Normal file
206
agents/meshcore_diagnostic.js
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
Copyright 2019 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.
|
||||
*/
|
||||
|
||||
require('MeshAgent').on('Connected', function (status)
|
||||
{
|
||||
if (status == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.timeout = setTimeout(start, 10000);
|
||||
});
|
||||
|
||||
|
||||
|
||||
function sendServerLog(msg)
|
||||
{
|
||||
require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'log', value: msg } });
|
||||
}
|
||||
function getMeshAgentService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var ret = require('service-manager').manager.getService(process.platform == 'win32' ? 'mesh agent' : 'meshagent');
|
||||
return(ret);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
function getARCHID() {
|
||||
var ret = 0;
|
||||
switch (process.platform) {
|
||||
case 'linux':
|
||||
// Need to detect Architecture ID
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
|
||||
child.stdin.write("uname -m\nexit\n");
|
||||
child.waitExit();
|
||||
switch (child.stdout.str.trim()) {
|
||||
case 'x86_64':
|
||||
case 'amd64':
|
||||
ret = 6;
|
||||
break;
|
||||
case 'x86':
|
||||
case 'i686':
|
||||
case 'i586':
|
||||
case 'i386':
|
||||
ret = 5;
|
||||
break;
|
||||
case 'armv6l':
|
||||
case 'armv7l':
|
||||
ret = 25;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'darwin':
|
||||
ret = 16;
|
||||
break;
|
||||
case 'win32':
|
||||
ret = process.arch == 'x64' ? 4 : 3;
|
||||
break;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function DownloadAgentBinary(path, ID)
|
||||
{
|
||||
var options = require('http').parseUri(require('MeshAgent').ServerInfo.ServerUri);
|
||||
var downloadUri = 'https://' + options.host + ':' + options.port + '/meshagents?id=' + (ID != null ? ID : getARCHID());
|
||||
sendServerLog('Diagnostic: Attempting to downlod agent from: ' + downloadUri);
|
||||
|
||||
return (wget(downloadUri, path, { rejectUnauthorized: false }));
|
||||
}
|
||||
|
||||
function giveup()
|
||||
{
|
||||
sendServerLog('Diagnostic: Unable to diagnose Mesh Agent');
|
||||
finished();
|
||||
}
|
||||
function finished()
|
||||
{
|
||||
sendServerLog('Diagnostic: End');
|
||||
require('service-manager').manager.getService('meshagentDiagnostic').stop();
|
||||
}
|
||||
|
||||
function ConfigureAgent(agent)
|
||||
{
|
||||
sendServerLog('...Configuring Agent...');
|
||||
var info = require('MeshAgent').ServerInfo;
|
||||
|
||||
var msh = 'MeshID=0x' + info.MeshID + '\n' + 'ServerID=' + info.ServerID + '\n' + 'MeshServer=' + info.ServerUri + '\n';
|
||||
var cfg = require('global-tunnel').proxyConfig;
|
||||
if(cfg == null)
|
||||
{
|
||||
msh += 'ignoreProxyFile=1\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
msh += ('WebProxy=' + cfg.host + ':' + cfg.port + '\n');
|
||||
}
|
||||
if(process.platform == 'win32')
|
||||
{
|
||||
require('fs').writeFileSync(agent.appLocation().replace('.exe', '.msh'), msh);
|
||||
}
|
||||
else
|
||||
{
|
||||
require('fs').writeFileSync(agent.appLocation() + '.msh', msh);
|
||||
}
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
sendServerLog('Diagnostic: Start');
|
||||
|
||||
var id = getARCHID();
|
||||
var s = getMeshAgentService();
|
||||
if (s == null)
|
||||
{
|
||||
DownloadAgentBinary('agent_temporary.bin').then(function ()
|
||||
{
|
||||
// SUCCESS
|
||||
try
|
||||
{
|
||||
var agent = require('service-manager').manager.installService(
|
||||
{
|
||||
name: process.platform == 'win32' ? 'Mesh Agent' : 'meshagent',
|
||||
target: 'meshagent',
|
||||
description: 'Mesh Central Agent v2 Background Service',
|
||||
displayName: 'Mesh Agent v2 Background Service',
|
||||
servicePath: 'agent_temporary.bin',
|
||||
startType: 'DEMAND_START'
|
||||
});
|
||||
require('fs').unlinkSync('agent_temporary.bin');
|
||||
ConfigureAgent(agent);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
giveup();
|
||||
}
|
||||
},
|
||||
function ()
|
||||
{
|
||||
// FAILURE
|
||||
giveup();
|
||||
});
|
||||
}
|
||||
if(s!=null)
|
||||
{
|
||||
// Mesh Agent Installation Found
|
||||
sendServerLog('Diagnostic: Mesh Agent Service => ' + (s.isRunning() ? 'RUNNING' : 'NOT-RUNNING'));
|
||||
if(s.isRunning())
|
||||
{
|
||||
finished();
|
||||
}
|
||||
else
|
||||
{
|
||||
sendServerLog('Diagnostic: Attempting to start Mesh Agent');
|
||||
s.start();
|
||||
sendServerLog('Diagnostic: ' + (s.isRunning() ? '(SUCCESS)' : '(FAILED)'));
|
||||
if (s.isRunning())
|
||||
{
|
||||
finished();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadAgentBinary(s.appLocation()).then(
|
||||
function () {
|
||||
sendServerLog('Diagnostic: Downloaded Successfully');
|
||||
sendServerLog('Diagnostic: Attempting to start Mesh Agent');
|
||||
s.start();
|
||||
sendServerLog('Diagnostic: ' + (s.isRunning() ? '(SUCCESS)' : '(FAILED)'));
|
||||
if (s.isRunning()) {
|
||||
finished();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
giveup();
|
||||
}
|
||||
},
|
||||
function () {
|
||||
sendServerLog('Diagnostic: Download Failed');
|
||||
giveup();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -152,7 +152,7 @@ DownloadAgent() {
|
||||
then
|
||||
# upstart
|
||||
echo -e "start on runlevel [2345]\nstop on runlevel [016]\n\nrespawn\n\nchdir /usr/local/mesh\nexec /usr/local/mesh/meshagent\n\n" > /etc/init/meshagent.conf
|
||||
service meshagent start
|
||||
initctl start meshagent
|
||||
echo 'meshagent installed as upstart/init.d service.'
|
||||
echo 'To start service: sudo initctl start meshagent'
|
||||
echo 'To stop service: sudo initctl stop meshagent'
|
||||
@ -193,7 +193,7 @@ UninstallAgent() {
|
||||
rm -f /sbin/meshcmd /etc/init.d/meshagent
|
||||
elif [ $starttype -eq 2 ]; then
|
||||
# upstart
|
||||
service meshagent stop
|
||||
initctl stop meshagent
|
||||
rm -f /sbin/meshcmd
|
||||
rm -f /etc/init/meshagent.conf
|
||||
rm -f /etc/rc2.d/S20mesh /etc/rc3.d/S20mesh /etc/rc5.d/S20mesh
|
||||
|
@ -109,10 +109,10 @@ module.exports.setup = function(binary, startvars) {
|
||||
var argcount = ReadShort(obj.script, obj.ip + 4);
|
||||
var argptr = obj.ip + 6;
|
||||
var args = [];
|
||||
|
||||
|
||||
// Clear all temp variables (This is optional)
|
||||
for (var i in obj.variables) { if (i.startsWith('__')) { delete obj.variables[i]; } }
|
||||
|
||||
|
||||
// Loop on each argument, moving forward by the argument length each time
|
||||
for (var i = 0; i < argcount; i++) {
|
||||
var arglen = ReadShort(obj.script, argptr);
|
||||
@ -122,7 +122,7 @@ module.exports.setup = function(binary, startvars) {
|
||||
if (argtyp < 2) {
|
||||
// Get the value and replace all {var} with variable values
|
||||
argval = argval.toString();
|
||||
while (argval.split("{").length > 1) { var t = argval.split("{").pop().split("}").shift(); argval = argval.replace('{' + t + '}', obj.getVar(t)); }
|
||||
if (argval != null) { while (argval.split("{").length > 1) { var t = argval.split("{").pop().split("}").shift(); argval = argval.replace('{' + t + '}', obj.getVar(t)); } }
|
||||
if (argtyp == 1) { obj.variables['__' + i] = decodeURI(argval); argval = '__' + i; } // If argtyp is 1, this is a literal. Store in temp variable.
|
||||
args.push(argval);
|
||||
}
|
||||
@ -132,7 +132,7 @@ module.exports.setup = function(binary, startvars) {
|
||||
}
|
||||
argptr += (2 + arglen);
|
||||
}
|
||||
|
||||
|
||||
// Move instruction pointer forward by command size
|
||||
obj.ip += cmdlen;
|
||||
|
||||
|
2
agents/modules_meshcmd_min/amt-script.min.js
vendored
2
agents/modules_meshcmd_min/amt-script.min.js
vendored
File diff suppressed because one or more lines are too long
@ -145,7 +145,7 @@ function WindowsConsole()
|
||||
this.TrayIcon.remove();
|
||||
handled = true;
|
||||
}
|
||||
if (!handled) { console.log(msg); }
|
||||
//if (!handled) { console.log(msg); }
|
||||
}
|
||||
});
|
||||
retVal.remove = function remove()
|
||||
|
@ -1 +1 @@
|
||||
var TrayIconFlags={NIF_MESSAGE:1,NIF_ICON:2,NIF_TIP:4,NIF_STATE:8,NIF_INFO:16,NIF_GUID:32,NIF_REALTIME:64,NIF_SHOWTIP:128,NIM_ADD:0,NIM_MODIFY:1,NIM_DELETE:2,NIM_SETFOCUS:3,NIM_SETVERSION:4};var NOTIFYICON_VERSION_4=4;var MessageTypes={WM_APP:32768,WM_USER:1024};function WindowsConsole(){if(process.platform=="win32"){this._ObjectID="win-console";this._Marshal=require("_GenericMarshal");this._kernel32=this._Marshal.CreateNativeProxy("kernel32.dll");this._user32=this._Marshal.CreateNativeProxy("user32.dll");this._kernel32.CreateMethod("GetConsoleWindow");this._kernel32.CreateMethod("GetCurrentThread");this._user32.CreateMethod("ShowWindow");this._user32.CreateMethod("LoadImageA");this._user32.CreateMethod({method:"GetMessageA",threadDispatch:1});this._shell32=this._Marshal.CreateNativeProxy("Shell32.dll");this._shell32.CreateMethod("Shell_NotifyIconA");this._handle=this._kernel32.GetConsoleWindow();this.minimize=function(){this._user32.ShowWindow(this._handle,6)};this.restore=function(){this._user32.ShowWindow(this._handle,9)};this.hide=function(){this._user32.ShowWindow(this._handle,0)};this.show=function(){this._user32.ShowWindow(this._handle,5)};this._loadicon=function(c){var b=this._user32.LoadImageA(0,this._Marshal.CreateVariable(c),1,0,0,16|32768|64);return(b)};this.SetTrayIcon=function a(h){var b=this._Marshal.CreateVariable(this._Marshal.PointerSize==4?508:528);b.toBuffer().writeUInt32LE(b._size,0);var n=TrayIconFlags.NIF_TIP|TrayIconFlags.NIF_MESSAGE;h.filter=MessageTypes.WM_APP+1;b.Deref(this._Marshal.PointerSize==4?16:24,4).toBuffer().writeUInt32LE(h.filter);if(!h.noBalloon){n|=TrayIconFlags.NIF_INFO}if(h.icon){n|=TrayIconFlags.NIF_ICON;var c=b.Deref(this._Marshal.PointerSize==4?20:32,this._Marshal.PointerSize);h.icon.pointerBuffer().copy(c.toBuffer())}b.Deref(this._Marshal.PointerSize*2,4).toBuffer().writeUInt32LE(1);b.Deref(this._Marshal.PointerSize==4?12:20,4).toBuffer().writeUInt32LE(n);b.Deref(this._Marshal.PointerSize==4?416:432,4).toBuffer().writeUInt32LE(NOTIFYICON_VERSION_4);var m=b.Deref(this._Marshal.PointerSize==4?24:40,128);var k=b.Deref(this._Marshal.PointerSize==4?160:176,256);var l=b.Deref(this._Marshal.PointerSize==4?420:436,64);if(h.szTip){Buffer.from(h.szTip).copy(m.toBuffer())}if(h.szInfo){Buffer.from(h.szInfo).copy(k.toBuffer())}if(h.szInfoTitle){Buffer.from(h.szInfoTitle).copy(l.toBuffer())}var d=require("win-message-pump");retVal={_ObjectID:"WindowsConsole.TrayIcon",MessagePump:new d(h)};var j=require("events").inherits(retVal);j.createEvent("ToastClicked");j.createEvent("IconHover");j.createEvent("ToastDismissed");retVal.Options=h;retVal.MessagePump.TrayIcon=retVal;retVal.MessagePump.NotifyData=b;retVal.MessagePump.WindowsConsole=this;retVal.MessagePump.on("exit",function e(o){console.log("Pump Exited");if(this.TrayIcon){this.TrayIcon.remove()}});retVal.MessagePump.on("hwnd",function f(o){h.hwnd=o;o.pointerBuffer().copy(this.NotifyData.Deref(this.WindowsConsole._Marshal.PointerSize,this.WindowsConsole._Marshal.PointerSize).toBuffer());if(this.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_ADD,this.NotifyData).Val==0){}});retVal.MessagePump.on("message",function g(p){if(p.message==this.TrayIcon.Options.filter){var o=false;if(p.wparam==1&&p.lparam==1029){this.TrayIcon.emit("ToastClicked");o=true}if(p.wparam==1&&p.lparam==512){this.TrayIcon.emit("IconHover");o=true}if(this.TrayIcon.Options.balloonOnly&&p.wparam==1&&(p.lparam==1028||p.lparam==1029)){this.TrayIcon.emit("ToastDismissed");this.TrayIcon.remove();o=true}if(!o){console.log(p)}}});retVal.remove=function i(){this.MessagePump.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_DELETE,this.MessagePump.NotifyData);this.MessagePump.stop();delete this.MessagePump.TrayIcon;delete this.MessagePump};return(retVal)}}}module.exports=new WindowsConsole();
|
||||
var TrayIconFlags={NIF_MESSAGE:1,NIF_ICON:2,NIF_TIP:4,NIF_STATE:8,NIF_INFO:16,NIF_GUID:32,NIF_REALTIME:64,NIF_SHOWTIP:128,NIM_ADD:0,NIM_MODIFY:1,NIM_DELETE:2,NIM_SETFOCUS:3,NIM_SETVERSION:4};var NOTIFYICON_VERSION_4=4;var MessageTypes={WM_APP:32768,WM_USER:1024};function WindowsConsole(){if(process.platform=="win32"){this._ObjectID="win-console";this._Marshal=require("_GenericMarshal");this._kernel32=this._Marshal.CreateNativeProxy("kernel32.dll");this._user32=this._Marshal.CreateNativeProxy("user32.dll");this._kernel32.CreateMethod("GetConsoleWindow");this._kernel32.CreateMethod("GetCurrentThread");this._user32.CreateMethod("ShowWindow");this._user32.CreateMethod("LoadImageA");this._user32.CreateMethod({method:"GetMessageA",threadDispatch:1});this._shell32=this._Marshal.CreateNativeProxy("Shell32.dll");this._shell32.CreateMethod("Shell_NotifyIconA");this._handle=this._kernel32.GetConsoleWindow();this.minimize=function(){this._user32.ShowWindow(this._handle,6)};this.restore=function(){this._user32.ShowWindow(this._handle,9)};this.hide=function(){this._user32.ShowWindow(this._handle,0)};this.show=function(){this._user32.ShowWindow(this._handle,5)};this._loadicon=function(c){var b=this._user32.LoadImageA(0,this._Marshal.CreateVariable(c),1,0,0,16|32768|64);return(b)};this.SetTrayIcon=function a(h){var b=this._Marshal.CreateVariable(this._Marshal.PointerSize==4?508:528);b.toBuffer().writeUInt32LE(b._size,0);var n=TrayIconFlags.NIF_TIP|TrayIconFlags.NIF_MESSAGE;h.filter=MessageTypes.WM_APP+1;b.Deref(this._Marshal.PointerSize==4?16:24,4).toBuffer().writeUInt32LE(h.filter);if(!h.noBalloon){n|=TrayIconFlags.NIF_INFO}if(h.icon){n|=TrayIconFlags.NIF_ICON;var c=b.Deref(this._Marshal.PointerSize==4?20:32,this._Marshal.PointerSize);h.icon.pointerBuffer().copy(c.toBuffer())}b.Deref(this._Marshal.PointerSize*2,4).toBuffer().writeUInt32LE(1);b.Deref(this._Marshal.PointerSize==4?12:20,4).toBuffer().writeUInt32LE(n);b.Deref(this._Marshal.PointerSize==4?416:432,4).toBuffer().writeUInt32LE(NOTIFYICON_VERSION_4);var m=b.Deref(this._Marshal.PointerSize==4?24:40,128);var k=b.Deref(this._Marshal.PointerSize==4?160:176,256);var l=b.Deref(this._Marshal.PointerSize==4?420:436,64);if(h.szTip){Buffer.from(h.szTip).copy(m.toBuffer())}if(h.szInfo){Buffer.from(h.szInfo).copy(k.toBuffer())}if(h.szInfoTitle){Buffer.from(h.szInfoTitle).copy(l.toBuffer())}var d=require("win-message-pump");retVal={_ObjectID:"WindowsConsole.TrayIcon",MessagePump:new d(h)};var j=require("events").inherits(retVal);j.createEvent("ToastClicked");j.createEvent("IconHover");j.createEvent("ToastDismissed");retVal.Options=h;retVal.MessagePump.TrayIcon=retVal;retVal.MessagePump.NotifyData=b;retVal.MessagePump.WindowsConsole=this;retVal.MessagePump.on("exit",function e(o){console.log("Pump Exited");if(this.TrayIcon){this.TrayIcon.remove()}});retVal.MessagePump.on("hwnd",function f(o){h.hwnd=o;o.pointerBuffer().copy(this.NotifyData.Deref(this.WindowsConsole._Marshal.PointerSize,this.WindowsConsole._Marshal.PointerSize).toBuffer());if(this.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_ADD,this.NotifyData).Val==0){}});retVal.MessagePump.on("message",function g(p){if(p.message==this.TrayIcon.Options.filter){var o=false;if(p.wparam==1&&p.lparam==1029){this.TrayIcon.emit("ToastClicked");o=true}if(p.wparam==1&&p.lparam==512){this.TrayIcon.emit("IconHover");o=true}if(this.TrayIcon.Options.balloonOnly&&p.wparam==1&&(p.lparam==1028||p.lparam==1029)){this.TrayIcon.emit("ToastDismissed");this.TrayIcon.remove();o=true}}});retVal.remove=function i(){this.MessagePump.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_DELETE,this.MessagePump.NotifyData);this.MessagePump.stop();delete this.MessagePump.TrayIcon;delete this.MessagePump};return(retVal)}}}module.exports=new WindowsConsole();
|
@ -128,10 +128,11 @@ module.exports.escapeHtml = function (string) { return String(string).replace(/[
|
||||
module.exports.escapeHtmlBreaks = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=', '\r': '<br />', '\n': '' }[s]; }); };
|
||||
|
||||
// Lowercase all the names in a object recursively
|
||||
module.exports.objKeysToLower = function (obj) {
|
||||
// Allow for exception keys, child of exceptions will not get lower-cased.
|
||||
module.exports.objKeysToLower = function (obj, exceptions) {
|
||||
for (var i in obj) {
|
||||
if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names
|
||||
if (typeof obj[i] == 'object') { module.exports.objKeysToLower(obj[i]); } // LowerCase all key names in the child object
|
||||
if ((typeof obj[i] == 'object') && ((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1))) { module.exports.objKeysToLower(obj[i], exceptions); } // LowerCase all key names in the child object
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
23
db.js
23
db.js
@ -281,7 +281,27 @@ module.exports.CreateDB = function (parent) {
|
||||
|
||||
// Database actions on the main collection
|
||||
obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); };
|
||||
obj.Get = function (id, func) { obj.file.find({ _id: id }, func); };
|
||||
obj.Get = function (id, func)
|
||||
{
|
||||
if (arguments.length > 2)
|
||||
{
|
||||
var parms = [func];
|
||||
for (var parmx = 2; parmx < arguments.length; ++parmx) { parms.push(arguments[parmx]); }
|
||||
var func2 = function _func2(arg1, arg2)
|
||||
{
|
||||
var userCallback = _func2.userArgs.shift();
|
||||
_func2.userArgs.unshift(arg2);
|
||||
_func2.userArgs.unshift(arg1);
|
||||
userCallback.apply(obj, _func2.userArgs);
|
||||
};
|
||||
func2.userArgs = parms;
|
||||
obj.file.find({ _id: id }, func2);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.file.find({ _id: id }, func);
|
||||
}
|
||||
};
|
||||
obj.GetAll = function (func) { obj.file.find({}, func); };
|
||||
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }, func); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }, func); };
|
||||
@ -422,6 +442,7 @@ module.exports.CreateDB = function (parent) {
|
||||
|
||||
// This is used to rate limit a number of operation per day. Returns a startValue each new days, but you can substract it and save the value in the db.
|
||||
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); };
|
||||
obj.escapeBase64 = function escapeBase64(val) { return (val.replace(/\+/g, '@').replace(/\//g, '$')); }
|
||||
|
||||
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
|
||||
|
||||
|
169
meshagent.js
169
meshagent.js
@ -522,6 +522,18 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if ((obj.authenticated != 1) || (obj.meshid == null) || obj.pendingCompleteAgentConnection || (obj.agentInfo == null)) { return; }
|
||||
obj.pendingCompleteAgentConnection = true;
|
||||
|
||||
// If this is a recovery agent
|
||||
if (obj.agentInfo.capabilities & 0x40) {
|
||||
// Inform mesh agent that it's authenticated.
|
||||
delete obj.pendingCompleteAgentConnection;
|
||||
obj.authenticated = 2;
|
||||
obj.send(common.ShortToStr(4));
|
||||
|
||||
// Ask for mesh core hash.
|
||||
obj.send(common.ShortToStr(11) + common.ShortToStr(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have too many agent sessions
|
||||
if (typeof domain.limits.maxagentsessions == 'number') {
|
||||
// Count the number of agent sessions for this domain
|
||||
@ -647,6 +659,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if (mesh.flags && (mesh.flags & 2) && (device.name != obj.agentInfo.computerName)) { device.name = obj.agentInfo.computerName; change = 1; } // We want the server name to be sync'ed to the hostname
|
||||
|
||||
if (change == 1) {
|
||||
// Do some clean up if needed, these values should not be in the database.
|
||||
if (device.conn != null) { delete device.conn; }
|
||||
if (device.pwr != null) { delete device.pwr; }
|
||||
if (device.agct != null) { delete device.agct; }
|
||||
if (device.cict != null) { delete device.cict; }
|
||||
|
||||
// Save the updated device in the database
|
||||
db.Set(device);
|
||||
|
||||
// If this is a temporary device, don't log changes
|
||||
@ -700,40 +719,25 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
// Not sure why, but in rare cases, obj.agentInfo is undefined here.
|
||||
if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case.
|
||||
|
||||
if ((obj.agentInfo.capabilities & 64) != 0) {
|
||||
// This is a recovery agent
|
||||
obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
|
||||
} else {
|
||||
// Check if we need to make an native update check
|
||||
obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
|
||||
const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
|
||||
if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
|
||||
// Check if we need to make an native update check
|
||||
obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
|
||||
const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
|
||||
if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
|
||||
|
||||
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
|
||||
// Ask the agent for it's executable binary hash
|
||||
obj.send(common.ShortToStr(12) + common.ShortToStr(0));
|
||||
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
|
||||
// Ask the agent for it's executable binary hash
|
||||
obj.send(common.ShortToStr(12) + common.ShortToStr(0));
|
||||
} else {
|
||||
// Check the mesh core, if the agent is capable of running one
|
||||
if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
|
||||
obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
|
||||
} else {
|
||||
// Check the mesh core, if the agent is capable of running one
|
||||
if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
|
||||
obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
|
||||
} else {
|
||||
agentCoreIsStable(); // No updates needed, agent is ready to go.
|
||||
}
|
||||
agentCoreIsStable(); // No updates needed, agent is ready to go.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function recoveryAgentCoreIsStable() {
|
||||
// Recovery agent is doing ok, lets perform main agent checking.
|
||||
|
||||
// TODO
|
||||
console.log('recoveryAgentCoreIsStable()');
|
||||
|
||||
// Close the recovery agent connection when done.
|
||||
//obj.close(1);
|
||||
}
|
||||
|
||||
// Take a basic Intel AMT policy and add all server information to it, making it ready to send to this agent.
|
||||
function completeIntelAmtPolicy(amtPolicy) {
|
||||
if (amtPolicy == null) return null;
|
||||
@ -764,6 +768,30 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
}
|
||||
}
|
||||
|
||||
function recoveryAgentCoreIsStable(mesh) {
|
||||
// Recovery agent is doing ok, lets perform main agent checking.
|
||||
//console.log('recoveryAgentCoreIsStable()');
|
||||
|
||||
// Fetch the the real agent nodeid
|
||||
db.Get('da' + obj.dbNodeKey, function (err, nodes, self)
|
||||
{
|
||||
if (nodes.length == 1)
|
||||
{
|
||||
self.realNodeKey = nodes[0].raid;
|
||||
|
||||
// Get agent connection state
|
||||
var agentConnected = false;
|
||||
var state = parent.parent.GetConnectivityState(self.realNodeKey);
|
||||
if (state) { agentConnected = ((state.connectivity & 1) != 0) }
|
||||
|
||||
self.send(JSON.stringify({ action: 'diagnostic', value: { command: 'query', value: self.realNodeKey, agent: agentConnected } }));
|
||||
} else
|
||||
{
|
||||
self.send(JSON.stringify({ action: 'diagnostic', value: { command: 'query', value: null } }));
|
||||
}
|
||||
}, obj);
|
||||
}
|
||||
|
||||
function agentCoreIsStable() {
|
||||
// Check that the mesh exists
|
||||
const mesh = parent.meshes[obj.dbMeshKey];
|
||||
@ -772,6 +800,20 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
return; // Probably not worth doing anything else. Hold this agent.
|
||||
}
|
||||
|
||||
// Check if this is a recovery agent
|
||||
if (obj.agentInfo.capabilities & 0x40) {
|
||||
recoveryAgentCoreIsStable(mesh);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the the real agent nodeid
|
||||
db.Get('ra' + obj.dbNodeKey, function (err, nodes) {
|
||||
if (nodes.length == 1) {
|
||||
obj.diagnosticNodeKey = nodes[0].daid;
|
||||
obj.send(JSON.stringify({ action: 'diagnostic', value: { command: 'query', value: obj.diagnosticNodeKey } }));
|
||||
}
|
||||
});
|
||||
|
||||
// Send Intel AMT policy
|
||||
if (obj.agentExeInfo && (obj.agentExeInfo.amt == true) && (mesh.amt != null)) { // Only send Intel AMT policy to agents what could have AMT.
|
||||
try { obj.send(JSON.stringify({ action: 'amtPolicy', amtPolicy: completeIntelAmtPolicy(common.Clone(mesh.amt)) })); } catch (ex) { }
|
||||
@ -1066,6 +1108,56 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'diagnostic':
|
||||
{
|
||||
if (typeof command.value == 'object') {
|
||||
switch (command.value.command) {
|
||||
case 'register': {
|
||||
// Only main agent can do this
|
||||
if (((obj.agentInfo.capabilities & 0x40) == 0) && (typeof command.value.value == 'string') && (command.value.value.length == 64))
|
||||
{
|
||||
// Store links to diagnostic agent id
|
||||
var daNodeKey = 'node/' + domain.id + '/' + db.escapeBase64(command.value.value);
|
||||
db.Set({ _id: 'da' + daNodeKey, domain: domain.id, time: obj.connectTime, raid: obj.dbNodeKey }); // DiagnosticAgent --> Agent
|
||||
db.Set({ _id: 'ra' + obj.dbNodeKey, domain: domain.id, time: obj.connectTime, daid: daNodeKey }); // Agent --> DiagnosticAgent
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'query': {
|
||||
// Only the diagnostic agent can do
|
||||
if ((obj.agentInfo.capabilities & 0x40) != 0) {
|
||||
// Return nodeid of main agent + connection status
|
||||
db.Get('da' + obj.dbNodeKey, function (err, nodes) {
|
||||
if (nodes.length == 1) {
|
||||
obj.realNodeKey = nodes[0].raid;
|
||||
|
||||
// Get agent connection state
|
||||
var agentConnected = false;
|
||||
var state = parent.parent.GetConnectivityState(obj.realNodeKey);
|
||||
if (state) { agentConnected = ((state.connectivity & 1) != 0) }
|
||||
|
||||
obj.send(JSON.stringify({ action: 'diagnostic', value: { command: 'query', value: obj.realNodeKey, agent: agentConnected } }));
|
||||
} else {
|
||||
obj.send(JSON.stringify({ action: 'diagnostic', value: { command: 'query', value: null } }));
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'log': {
|
||||
// Only the diagnostic agent can do
|
||||
if (((obj.agentInfo.capabilities & 0x40) != 0) && (typeof command.value.value == 'string') && (command.value.value.length < 256))
|
||||
{
|
||||
// Log a value in the event log of the main again
|
||||
var event = { etype: 'node', action: 'diagnostic', nodeid: obj.realNodeKey, domain: domain.id, msg: command.value.value };
|
||||
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log('Unknown agent action (' + obj.remoteaddrport + '): ' + command.action + '.');
|
||||
break;
|
||||
@ -1076,6 +1168,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Change the current core information string and event it
|
||||
function ChangeAgentCoreInfo(command) {
|
||||
if (obj.agentInfo.capabilities & 0x40) return;
|
||||
if ((command == null) || (command == null)) return; // Safety, should never happen.
|
||||
|
||||
// Check that the mesh exists
|
||||
@ -1119,6 +1212,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// If there are changes, event the new device
|
||||
if (change == 1) {
|
||||
// Do some clean up if needed, these values should not be in the database.
|
||||
if (device.conn != null) { delete device.conn; }
|
||||
if (device.pwr != null) { delete device.pwr; }
|
||||
if (device.agct != null) { delete device.agct; }
|
||||
if (device.cict != null) { delete device.cict; }
|
||||
|
||||
// Save to the database
|
||||
db.Set(device);
|
||||
|
||||
@ -1137,6 +1236,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Change the current core information string and event it
|
||||
function ChangeAgentLocationInfo(command) {
|
||||
if (obj.agentInfo.capabilities & 0x40) return;
|
||||
if ((command == null) || (command == null)) { return; } // Safety, should never happen.
|
||||
|
||||
// Check that the mesh exists
|
||||
@ -1156,6 +1256,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// If there are changes, save and event
|
||||
if (change == 1) {
|
||||
// Do some clean up if needed, these values should not be in the database.
|
||||
if (device.conn != null) { delete device.conn; }
|
||||
if (device.pwr != null) { delete device.pwr; }
|
||||
if (device.agct != null) { delete device.agct; }
|
||||
if (device.cict != null) { delete device.cict; }
|
||||
|
||||
// Save the device
|
||||
db.Set(device);
|
||||
|
||||
// Event the node change
|
||||
@ -1172,6 +1279,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Update the mesh agent tab in the database
|
||||
function ChangeAgentTag(tag) {
|
||||
if (obj.agentInfo.capabilities & 0x40) return;
|
||||
if (tag.length == 0) { tag = null; }
|
||||
// Get the node and change it if needed
|
||||
db.Get(obj.dbNodeKey, function (err, nodes) {
|
||||
@ -1179,6 +1287,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
const device = nodes[0];
|
||||
if (device.agent) {
|
||||
if (device.agent.tag != tag) {
|
||||
// Do some clean up if needed, these values should not be in the database.
|
||||
if (device.conn != null) { delete device.conn; }
|
||||
if (device.pwr != null) { delete device.pwr; }
|
||||
if (device.agct != null) { delete device.agct; }
|
||||
if (device.cict != null) { delete device.cict; }
|
||||
|
||||
// Set the new tag
|
||||
device.agent.tag = tag;
|
||||
db.Set(device);
|
||||
|
||||
|
@ -479,7 +479,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Lower case all keys in the config file
|
||||
try {
|
||||
require('./common.js').objKeysToLower(config2);
|
||||
require('./common.js').objKeysToLower(config2, ["ldapoptions"]);
|
||||
} catch (ex) {
|
||||
console.log('CRITICAL ERROR: Unable to access the file \"./common.js\".\r\nCheck folder & file permissions.');
|
||||
process.exit();
|
||||
@ -543,8 +543,9 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.config.domains[''].dns != null) { console.log("ERROR: Default domain can't have a DNS name."); return; }
|
||||
var xdomains = {}; for (i in obj.config.domains) { if (obj.config.domains[i].title == null) { obj.config.domains[i].title = 'MeshCentral'; } if (obj.config.domains[i].title2 == null) { obj.config.domains[i].title2 = '2.0 Beta 2'; } xdomains[i.toLowerCase()] = obj.config.domains[i]; } obj.config.domains = xdomains;
|
||||
var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
|
||||
for (i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in ./data/config.json."); return; } } }
|
||||
for (i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in config.json."); return; } } }
|
||||
for (i in obj.config.domains) {
|
||||
if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); }
|
||||
if (obj.config.domains[i].limits == null) { obj.config.domains[i].limits = {}; }
|
||||
if (obj.config.domains[i].dns == null) { obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); } else { obj.config.domains[i].url = '/'; }
|
||||
obj.config.domains[i].id = i;
|
||||
@ -552,6 +553,12 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (typeof obj.config.domains[i].userblockedip == 'string') { if (obj.config.domains[i].userblockedip == '') { obj.config.domains[i].userblockedip = null; } else { obj.config.domains[i].userblockedip = obj.config.domains[i].userallowedip.split(','); } }
|
||||
if (typeof obj.config.domains[i].agentallowedip == 'string') { if (obj.config.domains[i].agentallowedip == '') { obj.config.domains[i].agentallowedip = null; } else { obj.config.domains[i].agentallowedip = obj.config.domains[i].agentallowedip.split(','); } }
|
||||
if (typeof obj.config.domains[i].agentblockedip == 'string') { if (obj.config.domains[i].agentblockedip == '') { obj.config.domains[i].agentblockedip = null; } else { obj.config.domains[i].agentblockedip = obj.config.domains[i].agentblockedip.split(','); } }
|
||||
if ((obj.config.domains[i].auth == 'ldap') && (typeof obj.config.domains[i].ldapoptions != 'object')) {
|
||||
if (i == '') { console.log("ERROR: Default domain is LDAP, but is missing LDAPOptions."); } else { console.log("ERROR: Domain '" + i + "' is LDAP, but is missing LDAPOptions."); }
|
||||
process.exit();
|
||||
return;
|
||||
}
|
||||
if ((obj.config.domains[i].auth == 'ldap') || (obj.config.domains[i].auth == 'sspi')) { obj.config.domains[i].newaccounts = 0; } // No new accounts allowed in SSPI/LDAP authentication modes.
|
||||
}
|
||||
|
||||
// Log passed arguments into Windows Service Log
|
||||
@ -1197,8 +1204,8 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Read the agent recovery core if present
|
||||
var meshAgentRecoveryCore = null;
|
||||
if (obj.fs.existsSync(obj.path.join(__dirname, 'agents', 'agentrecoverycore.js')) == true) {
|
||||
try { meshAgentRecoveryCore = obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'agentrecoverycore.js')).toString(); } catch (ex) { }
|
||||
if (obj.fs.existsSync(obj.path.join(__dirname, 'agents', 'meshcore_diagnostic.js')) == true) {
|
||||
try { meshAgentRecoveryCore = obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'meshcore_diagnostic.js')).toString(); } catch (ex) { }
|
||||
if (meshAgentRecoveryCore != null) {
|
||||
modulesAdd['windows-agentrecovery'] = ['var addedModules = [];\r\n'];
|
||||
modulesAdd['linux-agentrecovery'] = ['var addedModules = [];\r\n'];
|
||||
@ -1618,11 +1625,12 @@ function getConfig(createSampleConfig) {
|
||||
|
||||
// Lower case all keys in the config file
|
||||
try {
|
||||
require('./common.js').objKeysToLower(config);
|
||||
require('./common.js').objKeysToLower(config, ["ldapoptions"]);
|
||||
} catch (ex) {
|
||||
console.log('CRITICAL ERROR: Unable to access the file \"./common.js\".\r\nCheck folder & file permissions.');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -1680,16 +1688,24 @@ function mainStart(args) {
|
||||
var config = getConfig(false);
|
||||
if (config == null) { process.exit(); }
|
||||
|
||||
// Lowercase the auth value is present
|
||||
for (var i in config.domains) { if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); } }
|
||||
|
||||
// Check is Windows SSPI and YubiKey OTP will be used
|
||||
var sspi = false;
|
||||
var ldap = false;
|
||||
var allsspi = true;
|
||||
var yubikey = false;
|
||||
if (require('os').platform() == 'win32') { for (var i in config.domains) { if (config.domains[i].auth == 'sspi') { sspi = true; } else { allsspi = false; } } } else { allsspi = false; }
|
||||
for (var i in config.domains) { if (config.domains[i].yubikey != null) { yubikey = true; } }
|
||||
for (var i in config.domains) {
|
||||
if (config.domains[i].yubikey != null) { yubikey = true; }
|
||||
if (config.domains[i].auth == 'ldap') { ldap = true; }
|
||||
}
|
||||
|
||||
// Build the list of required modules
|
||||
var modules = ['ws', 'nedb', 'https', 'yauzl', 'xmldom', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-handlebars'];
|
||||
if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
|
||||
if (ldap == true) { modules.push('ldapauth-fork'); }
|
||||
if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules
|
||||
if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB
|
||||
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
|
||||
|
12
meshrelay.js
12
meshrelay.js
@ -53,7 +53,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
};
|
||||
|
||||
obj.sendAgentMessage = function (command, userid, domainid) {
|
||||
var rights;
|
||||
var rights, mesh;
|
||||
if (command.nodeid == null) return false;
|
||||
var user = obj.parent.users[userid];
|
||||
if (user == null) return false;
|
||||
@ -66,9 +66,13 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
if (agent != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
rights = user.links[agent.dbMeshKey];
|
||||
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
|
||||
mesh = parent.meshes[agent.dbMeshKey];
|
||||
if ((rights != null) && (mesh != null) || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
|
||||
command.sessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
command.consent = mesh.consent; // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
command.username = user.name; // Add user name
|
||||
delete command.nodeid; // Remove the nodeid since it's implyed.
|
||||
agent.send(JSON.stringify(command));
|
||||
return true;
|
||||
@ -79,9 +83,13 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
if (routing != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
rights = user.links[routing.meshid];
|
||||
mesh = parent.meshes[routing.meshid];
|
||||
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
|
||||
command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
command.consent = mesh.consent; // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
command.username = user.name; // Add user name
|
||||
obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
|
||||
return true;
|
||||
}
|
||||
|
104
meshuser.js
104
meshuser.js
@ -19,6 +19,24 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
const path = require('path');
|
||||
const common = parent.common;
|
||||
|
||||
// Mesh Rights
|
||||
const MESHRIGHT_EDITMESH = 1;
|
||||
const MESHRIGHT_MANAGEUSERS = 2;
|
||||
const MESHRIGHT_MANAGECOMPUTERS = 4;
|
||||
const MESHRIGHT_REMOTECONTROL = 8;
|
||||
const MESHRIGHT_AGENTCONSOLE = 16;
|
||||
const MESHRIGHT_SERVERFILES = 32;
|
||||
const MESHRIGHT_WAKEDEVICE = 64;
|
||||
const MESHRIGHT_SETNOTES = 128;
|
||||
|
||||
// Site rights
|
||||
const SITERIGHT_SERVERBACKUP = 1;
|
||||
const SITERIGHT_MANAGEUSERS = 2;
|
||||
const SITERIGHT_SERVERRESTORE = 4;
|
||||
const SITERIGHT_FILEACCESS = 8;
|
||||
const SITERIGHT_SERVERUPDATE = 16;
|
||||
const SITERIGHT_LOCKED = 32;
|
||||
|
||||
var obj = {};
|
||||
obj.user = user;
|
||||
obj.domain = domain;
|
||||
@ -107,10 +125,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (agent != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
var rights = user.links[agent.dbMeshKey];
|
||||
if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
|
||||
command.sessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
var mesh = parent.meshes[agent.dbMeshKey];
|
||||
if ((rights != null) && (mesh != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
|
||||
command.sessionid = ws.sessionId; // Set the session id, required for responses
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
delete command.nodeid; // Remove the nodeid since it's implyed.
|
||||
command.consent = mesh.consent; // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
command.username = user.name; // Add user name
|
||||
delete command.nodeid; // Remove the nodeid since it's implied
|
||||
try { agent.send(JSON.stringify(command)); } catch (ex) { }
|
||||
}
|
||||
} else {
|
||||
@ -119,9 +141,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (routing != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
var rights = user.links[routing.meshid];
|
||||
if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
|
||||
command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
var mesh = parent.meshes[agent.dbMeshKey];
|
||||
if ((rights != null) && (mesh != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
|
||||
command.fromSessionid = ws.sessionId; // Set the session id, required for responses
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
command.consent = mesh.consent; // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
command.username = user.name; // Add user name
|
||||
parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
|
||||
}
|
||||
}
|
||||
@ -233,8 +259,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
var httpport = ((args.aliasport != null) ? args.aliasport : args.port);
|
||||
|
||||
// Build server information object
|
||||
var serverinfo = { name: parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi')), domainauth: (domain.auth == 'sspi') };
|
||||
var serverinfo = { name: parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap')), domainauth: ((domain.auth == 'sspi') || (domain.auth == 'ldap')) };
|
||||
if (args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = args.redirport; }
|
||||
if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; }
|
||||
|
||||
// Send server information
|
||||
try { ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: serverinfo })); } catch (ex) { }
|
||||
@ -309,6 +336,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
db.GetAllTypeNoTypeFieldMeshFiltered(links, domain.id, 'node', command.id, function (err, docs) {
|
||||
var r = {};
|
||||
for (i in docs) {
|
||||
// Remove any connectivity and power state information, that should not be in the database anyway.
|
||||
// TODO: Find why these are sometimes saves in the db.
|
||||
if (docs[i].conn != null) { delete docs[i].conn; }
|
||||
if (docs[i].pwr != null) { delete docs[i].pwr; }
|
||||
if (docs[i].agct != null) { delete docs[i].agct; }
|
||||
if (docs[i].cict != null) { delete docs[i].cict; }
|
||||
|
||||
// Add the connection state
|
||||
var state = parent.parent.GetConnectivityState(docs[i]._id);
|
||||
if (state) {
|
||||
@ -690,7 +724,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
case 'changeemail':
|
||||
{
|
||||
// Change the email address
|
||||
if (domain.auth == 'sspi') return;
|
||||
if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) return;
|
||||
if (common.validateEmail(command.email, 1, 256) == false) return;
|
||||
if (parent.users[req.session.userid].email != command.email) {
|
||||
// Check if this email is already validated on a different account
|
||||
@ -715,7 +749,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, message);
|
||||
|
||||
// Send the verification email
|
||||
if ((parent.parent.mailserver != null) && (domain.auth != 'sspi')) { parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
|
||||
if (parent.parent.mailserver != null) { parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -724,7 +758,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
case 'verifyemail':
|
||||
{
|
||||
// Send a account email verification email
|
||||
if (domain.auth == 'sspi') return;
|
||||
if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) return;
|
||||
if (common.validateString(command.email, 3, 1024) == false) return;
|
||||
if ((parent.parent.mailserver != null) && (parent.users[req.session.userid].email == command.email)) {
|
||||
// Send the verification email
|
||||
@ -853,20 +887,43 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
case 'edituser':
|
||||
{
|
||||
// Edit a user account, may involve changing email or administrator permissions
|
||||
if (((user.siteadmin & 2) != 0) || (user.name == command.name)) {
|
||||
var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = parent.users[chguserid];
|
||||
if (((user.siteadmin & 2) != 0) || (user._id == command.id)) {
|
||||
var chguser = parent.users[command.id];
|
||||
change = 0;
|
||||
if (chguser) {
|
||||
if (common.validateString(command.email, 1, 256) && (chguser.email != command.email)) { chguser.email = command.email; change = 1; }
|
||||
if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; }
|
||||
if ((common.validateInt(command.quota, 0) || command.quota == null) && (command.quota != chguser.quota)) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
|
||||
if ((user.siteadmin == 0xFFFFFFFF) && common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1; }
|
||||
|
||||
if ((Array.isArray(command.groups)) && (user._id != command.id)) {
|
||||
if (command.groups.length == 0) {
|
||||
// Remove the user groups
|
||||
if (chguser.groups != null) { delete chguser.groups; change = 1; }
|
||||
} else {
|
||||
// Arrange the user groups
|
||||
var groups2 = [];
|
||||
for (var i in command.groups) {
|
||||
if (typeof command.groups[i] == 'string') {
|
||||
var gname = command.groups[i].trim().toLowerCase();
|
||||
if ((gname.length > 0) && (gname.length <= 64) && (groups2.indexOf(gname) == -1)) { groups2.push(gname); }
|
||||
}
|
||||
}
|
||||
groups2.sort();
|
||||
|
||||
// Set the user groups
|
||||
if (chguser.groups != groups2) { chguser.groups = groups2; change = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
if (change == 1) {
|
||||
// Update the user
|
||||
db.SetUser(chguser);
|
||||
parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
|
||||
parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id });
|
||||
parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id });
|
||||
}
|
||||
if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
|
||||
// If the user is locked out of this account, disconnect now
|
||||
parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions
|
||||
}
|
||||
}
|
||||
@ -1044,7 +1101,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 64) != 0)) break;
|
||||
|
||||
// In some situations, we need a verified email address to create a device group.
|
||||
if ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (user.emailVerified !== true) && (user.siteadmin != 0xFFFFFFFF)) return; // User must verify it's email first.
|
||||
if ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != 0xFFFFFFFF)) return; // User must verify it's email first.
|
||||
|
||||
// Create mesh
|
||||
if (common.validateString(command.meshname, 1, 64) == false) break; // Meshname is between 1 and 64 characters
|
||||
@ -1122,6 +1179,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
|
||||
mesh = parent.meshes[command.meshid];
|
||||
change = '';
|
||||
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) return;
|
||||
@ -1130,7 +1188,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if ((common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Group name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
|
||||
if ((common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Group "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
|
||||
if ((common.validateInt(command.flags) == true) && (command.flags != mesh.flags)) { if (change != '') change += ' and flags changed'; else change += 'Group "' + mesh.name + '" flags changed'; mesh.flags = command.flags; }
|
||||
if (change != '') { db.Set(common.escapeLinksFieldName(mesh)); parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }); }
|
||||
if ((common.validateInt(command.consent) == true) && (command.consent != mesh.consent)) { if (change != '') change += ' and consent changed'; else change += 'Group "' + mesh.name + '" consent changed'; mesh.consent = command.consent; }
|
||||
if (change != '') { db.Set(common.escapeLinksFieldName(mesh)); parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1161,7 +1220,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
|
||||
|
||||
// Add a user to the mesh
|
||||
mesh.links[newuserid] = { name: newuser.name, rights: command.meshadmin };
|
||||
mesh.links[newuserid] = { userid: newuser.id, name: newuser.name, rights: command.meshadmin };
|
||||
db.Set(common.escapeLinksFieldName(mesh));
|
||||
|
||||
// Notify mesh change
|
||||
@ -1224,7 +1283,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
change = '';
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
if ((mesh.links[user._id] == null) || (mesh.links[user._id].rights != 0xFFFFFFFF)) return;
|
||||
if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) return;
|
||||
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
// TODO: Check if this is a change from the existing policy
|
||||
@ -1378,6 +1437,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
db.RemoveSMBIOS(node._id); // Remove SMBios data
|
||||
db.RemoveAllNodeEvents(node._id); // Remove all events for this node
|
||||
db.removeAllPowerEventsForNode(node._id); // Remove all power events for this node
|
||||
db.Get('ra' + obj.dbNodeKey, function (err, nodes) {
|
||||
if (nodes.length == 1) { db.Remove('da' + nodes[0].daid); } // Remove diagnostic agent to real agent link
|
||||
db.Remove('ra' + node._id); // Remove real agent to diagnostic agent link
|
||||
});
|
||||
|
||||
// Event node deletion
|
||||
parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id });
|
||||
@ -1598,10 +1661,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (command.intelamt.tls && (command.intelamt.tls != node.intelamt.tls)) { change = 1; node.intelamt.tls = command.intelamt.tls; changes.push('Intel AMT TLS'); }
|
||||
}
|
||||
if (command.tags) { // Node grouping tag, this is a array of strings that can't be empty and can't contain a comma
|
||||
var ok = true;
|
||||
var ok = true, group2 = [];
|
||||
if (common.validateString(command.tags, 0, 4096) == true) { command.tags = command.tags.split(','); }
|
||||
if (common.validateStrArray(command.tags, 1, 256) == true) { var groupTags = command.tags; for (var i in groupTags) { groupTags[i] = groupTags[i].trim(); if ((groupTags[i] == '') || (groupTags[i].indexOf(',') >= 0)) { ok = false; } } }
|
||||
if (ok == true) { groupTags.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); node.tags = groupTags; change = 1; }
|
||||
for (var i in command.tags) { var tname = command.tags[i].trim(); if ((tname.length > 0) && (tname.length < 64) && (group2.indexOf(tname) == -1)) { group2.push(tname); } }
|
||||
group2.sort();
|
||||
if (node.tags != group2) { node.tags = group2; change = 1; }
|
||||
} else if ((command.tags === '') && node.tags) { delete node.tags; change = 1; }
|
||||
|
||||
if (change == 1) {
|
||||
@ -1696,7 +1760,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
|
||||
if (nodes.length == 1) {
|
||||
meshlinks = user.links[nodes[0].meshid];
|
||||
if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & parent.MESHRIGHT_REMOTECONTROL != 0)) {
|
||||
if ((meshlinks) && (meshlinks.rights) && ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) != 0)) {
|
||||
// Add a user authentication cookie to a url
|
||||
var cookieContent = { userid: user._id, domainid: user.domain };
|
||||
if (command.nodeid) { cookieContent.nodeid = command.nodeid; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.3.1-x",
|
||||
"version": "0.3.2-m",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
@ -35,6 +35,7 @@
|
||||
"express-handlebars": "^3.0.0",
|
||||
"express-ws": "^4.0.0",
|
||||
"ipcheck": "^0.1.0",
|
||||
"ldapauth-fork": "^4.2.0",
|
||||
"meshcentral": "*",
|
||||
"minimist": "^1.2.0",
|
||||
"multiparty": "^4.2.1",
|
||||
|
@ -43,7 +43,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
|
||||
obj.socket.onclose = obj.xxOnSocketClosed;
|
||||
obj.xxStateChange(1);
|
||||
//obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
||||
obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid });
|
||||
obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid, usage: obj.protocol });
|
||||
//obj.debug("Agent Redir Start: " + url);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
var _TermLineWrap = true;
|
||||
var _termx = 0;
|
||||
var _termy = 0;
|
||||
var _termsavex = 0;
|
||||
var _termsavey = 0;
|
||||
var _termstate = 0;
|
||||
var _escNumber = [];
|
||||
var _escNumberPtr = 0;
|
||||
@ -110,7 +112,31 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
_altKeypadMode = false;
|
||||
_termstate = 0;
|
||||
break;
|
||||
case '7':
|
||||
// Save Cursor
|
||||
_termsavex = _termx;
|
||||
_termsavey = _termy;
|
||||
_termstate = 0;
|
||||
break;
|
||||
case '8':
|
||||
// Restore Cursor
|
||||
_termx = _termsavex;
|
||||
_termy = _termsavey;
|
||||
_termstate = 0;
|
||||
break;
|
||||
case 'M':
|
||||
// Scroll down one
|
||||
var x = 1;
|
||||
for (var y = _scrollRegion[1]; y >= _scrollRegion[0] + x; y--) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y - x][z]; _scratt[y][z] = _scratt[y - x][z]; }
|
||||
}
|
||||
for (var y = _scrollRegion[0] + x - 1; y > _scrollRegion[0] - 1; y--) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
|
||||
}
|
||||
_termstate = 0;
|
||||
break;
|
||||
default:
|
||||
console.log('unknown terminal short code', b);
|
||||
_termstate = 0;
|
||||
break;
|
||||
}
|
||||
@ -203,7 +229,8 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
case 'P': // Delete X Character(s), default 1 char
|
||||
var x = 1;
|
||||
if (argslen == 1) { x = args[0]; }
|
||||
for (i = _termx; i < (_termx + x) ; i++) { _tscreen[_termy][i] = ' '; _scratt[_termy][i] = (7 << 6); }
|
||||
for (i = _termx; i < 80 - x; i++) { _tscreen[_termy][i] = _tscreen[_termy][i + x]; _scratt[_termy][i] = _scratt[_termy][i + x]; }
|
||||
for (i = (80 - x); i < 80; i++) { _tscreen[_termy][i] = ' '; _scratt[_termy][i] = (7 << 6); }
|
||||
break;
|
||||
case 'L': // Insert X Line(s), default 1 char
|
||||
var linecount = 1;
|
||||
@ -244,8 +271,7 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
if (args[1] > obj.width) args[1] = obj.width;
|
||||
_termy = args[0] - 1;
|
||||
_termx = args[1] - 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_termy = 0;
|
||||
_termx = 0;
|
||||
}
|
||||
@ -330,6 +356,16 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
|
||||
}
|
||||
break;
|
||||
case 'M': // Delete X lines, default 1
|
||||
var x = 1;
|
||||
if (argslen == 1) { x = args[0] }
|
||||
for (var y = _termy; y <= _scrollRegion[1] - x; y++) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y + x][z]; _scratt[y][z] = _scratt[y + x][z]; }
|
||||
}
|
||||
for (var y = _scrollRegion[1] - x + 1; y < _scrollRegion[1]; y++) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
|
||||
}
|
||||
break;
|
||||
case 'T': // Scroll down the scroll region X lines, default 1
|
||||
var x = 1;
|
||||
if (argslen == 1) { x = args[0] }
|
||||
@ -340,9 +376,14 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
|
||||
}
|
||||
break;
|
||||
case 'X': // Erase X characters, default 1 (untested)
|
||||
var x = 1;
|
||||
if (argslen == 1) { x = args[0] }
|
||||
while ((x > 0) && (_termx > 0)) { _tscreen[_termy][_termx] = ' '; _termx--; x--; }
|
||||
break;
|
||||
default:
|
||||
//if (code != '@') alert(code);
|
||||
//console.log('unknown terminal code', code, args, mode);
|
||||
console.log('unknown terminal code', code, args, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -614,6 +655,13 @@ var CreateAmtRemoteTerminal = function (divid) {
|
||||
if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 91, 66)); return true; }; // Down
|
||||
}
|
||||
|
||||
if (e.which == 33) { obj.TermSendKeys(String.fromCharCode(27, 91, 53, 126)); return true; }; // PageUp
|
||||
if (e.which == 34) { obj.TermSendKeys(String.fromCharCode(27, 91, 54, 126)); return true; }; // PageDown
|
||||
if (e.which == 35) { obj.TermSendKeys(String.fromCharCode(27, 91, 70)); return true; }; // End
|
||||
if (e.which == 36) { obj.TermSendKeys(String.fromCharCode(27, 91, 72)); return true; }; // Home
|
||||
if (e.which == 45) { obj.TermSendKeys(String.fromCharCode(27, 91, 50, 126)); return true; }; // Insert
|
||||
if (e.which == 46) { obj.TermSendKeys(String.fromCharCode(27, 91, 51, 126)); return true; }; // Delete
|
||||
|
||||
if (e.which == 9) { obj.TermSendKeys("\t"); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return true; }; // TAB
|
||||
|
||||
// F1 to F12 keys
|
||||
|
1600
public/styles/style-old.css
Normal file
1600
public/styles/style-old.css
Normal file
File diff suppressed because it is too large
Load Diff
@ -124,6 +124,27 @@ body {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#page_content {
|
||||
/*max-height: calc(100vh - 108px);*/
|
||||
}
|
||||
.fullscreen #page_content {
|
||||
position: absolute;
|
||||
top: 66px;
|
||||
left: 90px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
.arg_hide #page_content {
|
||||
left: 0px;
|
||||
}
|
||||
.fulldesk #page_content {
|
||||
position: static;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#page_leftbar {
|
||||
height: calc(100vh - 66px);
|
||||
width: 90px;
|
||||
|
@ -49,13 +49,15 @@
|
||||
"_NewAccountEmailDomains": [ "sample.com" ],
|
||||
"Footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
||||
"_CertUrl": "https://192.168.2.106:443/",
|
||||
"_PasswordRequirements": { "min": 8, "max": 128, "upper": 1, "lower": 1, "numeric": 1, "nonalpha": 1, "reset": 90 },
|
||||
"_PasswordRequirements": { "min": 8, "max": 128, "upper": 1, "lower": 1, "numeric": 1, "nonalpha": 1, "reset": 90, "force2factor": true },
|
||||
"_AgentNoProxy": true,
|
||||
"_GeoLocation": true,
|
||||
"_UserAllowedIP": "127.0.0.1,192.168.1.0/24",
|
||||
"_UserBlockedIP": "127.0.0.1,::1,192.168.0.100",
|
||||
"_AgentAllowedIP": "192.168.0.100/24",
|
||||
"_AgentBlockedIP": "127.0.0.1,::1",
|
||||
"__UserConsentFlags__" : "Set to: 1 for desktop, 2 for terminal, 3 for files, 7 for all",
|
||||
"_UserConsentFlags" : 7,
|
||||
"_Limits": {
|
||||
"_MaxUserAccounts": 100,
|
||||
"_MaxUserSessions": 100,
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -18,7 +18,7 @@
|
||||
<script type="text/javascript" src="scripts/zlib-adler32.js"></script>
|
||||
<script type="text/javascript" src="scripts/zlib-crc32.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script>
|
||||
<title>MeshCentral</title>
|
||||
<title>{{{title}}}</title>
|
||||
<style>
|
||||
a {
|
||||
color: #036;
|
||||
@ -249,10 +249,10 @@
|
||||
<br style=clear:both />
|
||||
</div>
|
||||
<strong>Device Groups</strong>
|
||||
( <a onclick=account_createMesh() style=cursor:pointer><img src="images/icon-addnew.png" width=12 height=12 border=0 /> New</a> )
|
||||
<span id="p3createMeshLink1">( <a onclick=account_createMesh() style=cursor:pointer><img src="images/icon-addnew.png" width=12 height=12 border=0 /> New</a> )</span>
|
||||
<br /><br />
|
||||
<div id=p3meshes></div>
|
||||
<div id=p3noMeshFound style=margin-left:9px;display:none>No device groups. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a></div>
|
||||
<div id=p3noMeshFound style=margin-left:9px;display:none>No device groups.<span id="p3createMeshLink2"> <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a></span></div>
|
||||
<br style=clear:both />
|
||||
</div>
|
||||
</div>
|
||||
@ -655,6 +655,10 @@
|
||||
QV('manageAuthApp', features & 4096);
|
||||
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
|
||||
|
||||
// On the mobile app, don't allow group creation (for now).
|
||||
QV('p3createMeshLink1', false);
|
||||
QV('p3createMeshLink2', false);
|
||||
|
||||
if (typeof userinfo.passchange == 'number') {
|
||||
if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||||
else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
|
||||
@ -809,7 +813,7 @@
|
||||
}
|
||||
case 'createmesh': {
|
||||
// A new mesh was created
|
||||
if (message.event.links['user/' + domain + '/' + userinfo.name.toLowerCase()] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
|
||||
if (message.event.links[userinfo._id] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
|
||||
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
|
||||
updateMeshes();
|
||||
updateDevices();
|
||||
@ -830,7 +834,7 @@
|
||||
meshes[message.event.meshid].links = message.event.links;
|
||||
|
||||
// Check if we lost rights to this mesh in this change.
|
||||
if (meshes[message.event.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()] == null) {
|
||||
if (meshes[message.event.meshid].links[userinfo._id] == null) {
|
||||
if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
|
||||
delete meshes[message.event.meshid];
|
||||
|
||||
@ -1165,8 +1169,14 @@
|
||||
function account_createMesh() {
|
||||
if (xxdialogMode) return;
|
||||
|
||||
// Check if we are allowed to create a new device group
|
||||
if ((userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "New Device Group", 1, null, "Unable to create a new device group until the email address is verified. Go to the \"My Account\" menu option to change and verify an email address."); return; }
|
||||
// Check if we are disallowed from creating a device group
|
||||
if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "New Device Group", 1, null, "This account does not have the rights to create a new device group."); return; }
|
||||
|
||||
// Remind the user to verify the email address
|
||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
|
||||
// We are allowed, let's prompt to information
|
||||
var x = addHtmlValue('Name', '<input id=dp3meshname style=width:170px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
|
||||
@ -1240,7 +1250,7 @@
|
||||
count++;
|
||||
|
||||
// Mesh rights
|
||||
var meshrights = meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = meshes[i].links[userinfo._id].rights;
|
||||
var rights = 'Partial Rights';
|
||||
if (meshrights == 0xFFFFFFFF) rights = 'Full Administrator'; else if (meshrights == 0) rights = 'No Rights';
|
||||
|
||||
@ -1531,7 +1541,7 @@
|
||||
// Go thru the list of nodes and display them
|
||||
for (var i in nodes) {
|
||||
if (nodes[i].v == false) continue;
|
||||
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||||
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links[userinfo._id];
|
||||
if (meshlinks == null) continue;
|
||||
var meshrights = meshlinks.rights;
|
||||
|
||||
@ -1602,7 +1612,7 @@
|
||||
// Display all empty meshes, we need to do this because users can add devices to these at any time.
|
||||
if (sort == 0) {
|
||||
for (var i in meshes) {
|
||||
var mesh = meshes[i], meshlink = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||||
var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
|
||||
if (meshlink != null) {
|
||||
var meshrights = meshlink.rights;
|
||||
if (displayedMeshes[mesh._id] == null) {
|
||||
@ -1690,7 +1700,7 @@
|
||||
|
||||
function getNodeRights(nodeid) {
|
||||
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
|
||||
return mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
return mesh.links[userinfo._id].rights;
|
||||
}
|
||||
|
||||
var currentDevicePanel = 0;
|
||||
@ -1701,11 +1711,18 @@
|
||||
var powerTimeline = null;
|
||||
function getCurrentNode() { return currentNode; };
|
||||
function gotoDevice(nodeid, panel, refresh) {
|
||||
|
||||
// Remind the user to verify the email address
|
||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" and look at the \"Account Security\" section."); return; }
|
||||
|
||||
var node = getNodeFromId(nodeid);
|
||||
if (node == null) { goBack(); return; }
|
||||
var mesh = meshes[node.meshid];
|
||||
if (mesh == null) { goBack(); return; }
|
||||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = mesh.links[userinfo._id].rights;
|
||||
if (!currentNode || currentNode._id != node._id || refresh == true) {
|
||||
currentNode = node;
|
||||
|
||||
@ -1865,7 +1882,7 @@
|
||||
|
||||
function setupDeviceMenu(op, obj) {
|
||||
var meshrights = 0;
|
||||
if (currentNode) { meshrights = meshes[currentNode.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; }
|
||||
if (currentNode) { meshrights = meshes[currentNode.meshid].links[userinfo._id].rights; }
|
||||
if (op != null) { currentDevicePanel = op; }
|
||||
QV('p10general', currentDevicePanel == 0);
|
||||
QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
|
||||
@ -1879,7 +1896,7 @@
|
||||
|
||||
function deviceActionFunction() {
|
||||
if (xxdialogMode) return;
|
||||
var meshrights = meshes[currentNode.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
|
||||
var x = "Select an operation to perform on this device.<br /><br />";
|
||||
var y = '<select id=d2deviceop style=float:right;width:170px>';
|
||||
if ((meshrights & 64) != 0) { y += '<option value=100>Wake-up</option>'; } // Wake-up permission
|
||||
@ -2022,7 +2039,7 @@
|
||||
function p10showiconselector() {
|
||||
if (xxdialogMode) return;
|
||||
var mesh = meshes[currentNode.meshid];
|
||||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = mesh.links[userinfo._id].rights;
|
||||
if ((meshrights & 4) == 0) return;
|
||||
|
||||
var x = '<table align=center><td>';
|
||||
@ -2100,7 +2117,7 @@
|
||||
var mesh = meshes[currentNode.meshid];
|
||||
var deskState = 0;
|
||||
if (desktop != null) { deskState = desktop.State; }
|
||||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = mesh.links[userinfo._id].rights;
|
||||
|
||||
// Show the right buttons
|
||||
QV('disconnectbutton1', (deskState != 0));
|
||||
@ -2842,7 +2859,7 @@
|
||||
if (currentMesh == null) return;
|
||||
QH('p20meshName', EscapeHtml(currentMesh.name));
|
||||
var meshtype = 'Unknown #' + currentMesh.mtype;
|
||||
var meshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = currentMesh.links[userinfo._id].rights;
|
||||
if (currentMesh.mtype == 1) meshtype = 'Intel® AMT group';
|
||||
if (currentMesh.mtype == 2) meshtype = 'Software agent group';
|
||||
|
||||
@ -2855,7 +2872,7 @@
|
||||
//x += '<br><input type=button value=Notes title="View notes about this mesh" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
|
||||
|
||||
x += '<br style=clear:both><br>';
|
||||
var currentMeshLinks = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||||
var currentMeshLinks = currentMesh.links[userinfo._id];
|
||||
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<div style=margin-bottom:6px><a onclick=p20showAddMeshUserDialog() style=cursor:pointer><img src=images/icon-addnew.png border=0 height=12 width=12> Add User</a></div>'; }
|
||||
|
||||
/*
|
||||
@ -2971,7 +2988,7 @@
|
||||
}
|
||||
|
||||
function p20validateAddMeshUserDialog() {
|
||||
var meshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||||
var meshrights = currentMesh.links[userinfo._id].rights;
|
||||
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
|
||||
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
||||
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
|
||||
@ -3010,7 +3027,7 @@
|
||||
function p20viewuser(userid) {
|
||||
if (xxdialogMode) return;
|
||||
userid = decodeURIComponent(userid);
|
||||
var r = '', cmeshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights, meshrights = currentMesh.links[userid].rights;
|
||||
var r = '', cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
|
||||
if (meshrights == 0xFFFFFFFF) r = ', Full Administrator'; else {
|
||||
if ((meshrights & 1) != 0) r += ', Edit Device Group';
|
||||
if ((meshrights & 2) != 0) r += ', Manage Device Group Users';
|
||||
@ -3029,7 +3046,7 @@
|
||||
if (r == '') { r = 'No Rights'; }
|
||||
var buttons = 1, x = addHtmlValue('User', EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
||||
x += addHtmlValue('Permissions', r);
|
||||
if ((('user/' + domain + '/' + userinfo.name.toLowerCase()) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
|
||||
if (((userinfo._id) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
|
||||
setDialogMode(2, "Mesh User", buttons, p20viewuserEx, x, userid);
|
||||
}
|
||||
|
||||
|
@ -3554,6 +3554,7 @@
|
||||
|
||||
// Remind the user to verify the email address
|
||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; }
|
||||
|
||||
@ -5754,6 +5755,7 @@
|
||||
|
||||
// Remind the user to verify the email address
|
||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||||
|
||||
// Remind the user to add two factor authentication
|
||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; }
|
||||
|
||||
@ -5919,6 +5921,7 @@
|
||||
meshFeatures = meshFeatures.join(', ');
|
||||
if (meshFeatures == '') { meshFeatures = '<i>None</i>'; }
|
||||
x += addHtmlValue('Features', addLinkConditional(meshFeatures, 'p20editmeshfeatures()', meshrights & 1));
|
||||
|
||||
// Display user consent
|
||||
meshFeatures = [];
|
||||
var consent = 0;
|
||||
@ -6893,7 +6896,6 @@
|
||||
if (user.groups) { userGroups = ''; for (var i in user.groups) { userGroups += '<span class="tagSpan">' + user.groups[i] + '</span>'; } }
|
||||
x += addDeviceAttribute('User Groups', addLinkConditional(userGroups, 'showUserGroupDialog(event,\"' + userid + '\")', ((userinfo.groups == null) && (userinfo.siteadmin & 2) && (userinfo._id != user._id))));
|
||||
|
||||
|
||||
var multiFactor = 0;
|
||||
if ((user.otpsecret > 0) || (user.otphkeys > 0)) {
|
||||
multiFactor = 1;
|
||||
@ -7586,8 +7588,8 @@
|
||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40);
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 115: 'ServerConsole' };
|
||||
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 115: 'ServerConsole' };
|
||||
for (var i in panels) {
|
||||
QC(panels[i]).remove('style3x');
|
||||
QC(panels[i]).remove('style3sel');
|
||||
|
File diff suppressed because one or more lines are too long
@ -22,7 +22,7 @@
|
||||
<div id=topbar class="noselect style3">
|
||||
<div id=toggle title="Toggle full width" onclick="toggleFullScreen(1)">↔</div>
|
||||
</div>
|
||||
<div id=column_l>
|
||||
<div id=column_l style="height:calc(100vh - 111px)">
|
||||
<h1>Welcome</h1>
|
||||
<div id="welcomeText" style="display:none">Connect to your home or office devices from anywhere in the world using <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>, the real time, open source remote monitoring and management web site. You will need to download and install a management agent on your computers. Once installed, computers will show up in the "My Devices" section of this web site and you will be able to monitor them and take control of them.</div>
|
||||
<table id="centralTable" style="">
|
||||
|
File diff suppressed because one or more lines are too long
192
webserver.js
192
webserver.js
@ -217,36 +217,144 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.authenticate = function (name, pass, domain, fn) {
|
||||
if ((typeof (name) != 'string') || (typeof (pass) != 'string') || (typeof (domain) != 'object')) { fn(new Error('invalid fields')); return; }
|
||||
if (!module.parent) console.log('authenticating %s:%s:%s', domain.id, name, pass);
|
||||
var user = obj.users['user/' + domain.id + '/' + name.toLowerCase()];
|
||||
// Query the db for the given username
|
||||
if (!user) { fn(new Error('cannot find user')); return; }
|
||||
// Apply the same algorithm to the POSTed password, applying the hash against the pass / salt, if there is a match we found the user
|
||||
if (user.salt == null) {
|
||||
fn(new Error('invalid password'));
|
||||
} else {
|
||||
if (user.passtype != null) {
|
||||
// IIS default clear or weak password hashing (SHA-1)
|
||||
require('./pass').iishash(user.passtype, pass, user.salt, function (err, hash) {
|
||||
if (err) return fn(err);
|
||||
if (hash == user.hash) {
|
||||
// Update the password to the stronger format.
|
||||
require('./pass').hash(pass, function (err, salt, hash) { if (err) throw err; user.salt = salt; user.hash = hash; delete user.passtype; obj.db.SetUser(user); });
|
||||
|
||||
if (domain.auth == 'ldap') {
|
||||
if (domain.ldapoptions.url == 'test') {
|
||||
// Fake LDAP login
|
||||
var xxuser = domain.ldapoptions[name.toLowerCase()];
|
||||
if (xxuser == null) {
|
||||
fn(new Error('invalid password'));
|
||||
return;
|
||||
} else {
|
||||
var username = xxuser['displayName'];
|
||||
if (domain.ldapusername) { username = xxuser[domain.ldapusername]; }
|
||||
var shortname = null;
|
||||
if (domain.ldapuserbinarykey) {
|
||||
// Use a binary key as the userid
|
||||
if (xxuser[domain.ldapuserbinarykey]) { shortname = Buffer.from(xxuser[domain.ldapuserbinarykey], 'binary').toString('hex'); }
|
||||
} else if (domain.ldapuserkey) {
|
||||
// Use a string key as the userid
|
||||
if (xxuser[domain.ldapuserkey]) { shortname = xxuser[domain.ldapuserkey]; }
|
||||
} else {
|
||||
// Use the default key as the userid
|
||||
if (xxuser.objectSid) { shortname = Buffer.from(xxuser.objectSid, 'binary').toString('hex').toLowerCase(); }
|
||||
else if (xxuser.objectGUID) { shortname = Buffer.from(xxuser.objectGUID, 'binary').toString('hex').toLowerCase(); }
|
||||
else if (xxuser.name) { shortname = xxuser.name; }
|
||||
else if (xxuser.cn) { shortname = xxuser.cn; }
|
||||
}
|
||||
if (username == null) { fn(new Error('no user name')); return; }
|
||||
if (shortname == null) { fn(new Error('no user identifier')); return; }
|
||||
var userid = 'user/' + domain.id + '/' + shortname;
|
||||
var user = obj.users[userid];
|
||||
|
||||
if (user == null) {
|
||||
// Create a new user
|
||||
var user = { type: 'user', _id: userid, name: username, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
|
||||
var usercount = 0;
|
||||
for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
|
||||
if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts === 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
|
||||
obj.users[user._id] = user;
|
||||
obj.db.SetUser(user);
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: userid, username: username, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, name is ' + name, domain: domain.id });
|
||||
return fn(null, user._id);
|
||||
} else {
|
||||
// This is an existing user
|
||||
// If the display username has changes, update it.
|
||||
if (user.name != username) {
|
||||
user.name = username;
|
||||
db.SetUser(user);
|
||||
parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id });
|
||||
}
|
||||
// If user is locker out, block here.
|
||||
if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
|
||||
return fn(null, user._id);
|
||||
}
|
||||
fn(new Error('invalid password'), null, user.passhint);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Default strong password hashing (pbkdf2 SHA384)
|
||||
require('./pass').hash(pass, user.salt, function (err, hash) {
|
||||
if (err) return fn(err);
|
||||
if (hash == user.hash) {
|
||||
// LDAP login
|
||||
var LdapAuth = require('ldapauth-fork');
|
||||
var ldap = new LdapAuth(domain.ldapoptions);
|
||||
ldap.authenticate(name, pass, function (err, xxuser) {
|
||||
try { ldap.close(); } catch (ex) { console.log(ex); } // Close the LDAP object
|
||||
if (err) { fn(new Error('invalid password')); return; }
|
||||
var shortname = null;
|
||||
var username = xxuser['displayName'];
|
||||
if (domain.ldapusername) { username = xxuser[domain.ldapusername]; }
|
||||
if (domain.ldapuserbinarykey) {
|
||||
// Use a binary key as the userid
|
||||
if (xxuser[domain.ldapuserbinarykey]) { shortname = Buffer.from(xxuser[domain.ldapuserbinarykey], 'binary').toString('hex').toLowerCase(); }
|
||||
} else if (domain.ldapuserkey) {
|
||||
// Use a string key as the userid
|
||||
if (xxuser[domain.ldapuserkey]) { shortname = xxuser[domain.ldapuserkey]; }
|
||||
} else {
|
||||
// Use the default key as the userid
|
||||
if (xxuser.objectSid) { shortname = Buffer.from(xxuser.objectSid, 'binary').toString('hex').toLowerCase(); }
|
||||
else if (xxuser.objectGUID) { shortname = Buffer.from(xxuser.objectGUID, 'binary').toString('hex').toLowerCase(); }
|
||||
else if (xxuser.name) { shortname = xxuser.name; }
|
||||
else if (xxuser.cn) { shortname = xxuser.cn; }
|
||||
}
|
||||
if (username == null) { fn(new Error('no user name')); return; }
|
||||
if (shortname == null) { fn(new Error('no user identifier')); return; }
|
||||
var userid = 'user/' + domain.id + '/' + shortname;
|
||||
var user = obj.users[userid];
|
||||
|
||||
if (user == null) {
|
||||
// This user does not exist, create a new account.
|
||||
var user = { type: 'user', _id: userid, name: shortname, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
|
||||
var usercount = 0;
|
||||
for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
|
||||
if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts === 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
|
||||
obj.users[user._id] = user;
|
||||
obj.db.SetUser(user);
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, name is ' + name, domain: domain.id });
|
||||
return fn(null, user._id);
|
||||
} else {
|
||||
// This is an existing user
|
||||
// If the display username has changes, update it.
|
||||
if (user.name != username) {
|
||||
user.name = username;
|
||||
db.SetUser(user);
|
||||
parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id });
|
||||
}
|
||||
// If user is locker out, block here.
|
||||
if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
|
||||
return fn(null, user._id);
|
||||
}
|
||||
fn(new Error('invalid password'), null, user.passhint);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Regular login
|
||||
var user = obj.users['user/' + domain.id + '/' + name.toLowerCase()];
|
||||
// Query the db for the given username
|
||||
if (!user) { fn(new Error('cannot find user')); return; }
|
||||
// Apply the same algorithm to the POSTed password, applying the hash against the pass / salt, if there is a match we found the user
|
||||
if (user.salt == null) {
|
||||
fn(new Error('invalid password'));
|
||||
} else {
|
||||
if (user.passtype != null) {
|
||||
// IIS default clear or weak password hashing (SHA-1)
|
||||
require('./pass').iishash(user.passtype, pass, user.salt, function (err, hash) {
|
||||
if (err) return fn(err);
|
||||
if (hash == user.hash) {
|
||||
// Update the password to the stronger format.
|
||||
require('./pass').hash(pass, function (err, salt, hash) { if (err) throw err; user.salt = salt; user.hash = hash; delete user.passtype; obj.db.SetUser(user); });
|
||||
if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
|
||||
return fn(null, user._id);
|
||||
}
|
||||
fn(new Error('invalid password'), null, user.passhint);
|
||||
});
|
||||
} else {
|
||||
// Default strong password hashing (pbkdf2 SHA384)
|
||||
require('./pass').hash(pass, user.salt, function (err, hash) {
|
||||
if (err) return fn(err);
|
||||
if (hash == user.hash) {
|
||||
if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
|
||||
return fn(null, user._id);
|
||||
}
|
||||
fn(new Error('invalid password'), null, user.passhint);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -611,7 +719,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
function handleCreateAccountRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if ((domain == null) || (domain.auth == 'sspi')) return;
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(401); return; }
|
||||
|
||||
if ((domain.newaccounts === 0) || (domain.newaccounts === false)) { res.sendStatus(401); return; }
|
||||
|
||||
@ -684,8 +792,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.db.SetUser(user);
|
||||
|
||||
// Send the verification email
|
||||
if ((obj.parent.mailserver != null) && (domain.auth != 'sspi') && (obj.common.validateEmail(user.email, 1, 256) == true)) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
|
||||
|
||||
if ((obj.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (obj.common.validateEmail(user.email, 1, 256) == true)) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
|
||||
});
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id });
|
||||
}
|
||||
@ -702,7 +809,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
|
||||
// Check everything is ok
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
|
||||
delete req.session.loginmode;
|
||||
delete req.session.tokenusername;
|
||||
delete req.session.tokenpassword;
|
||||
@ -776,7 +883,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Called to process an account reset request
|
||||
function handleResetAccountRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if ((domain == null) || (domain.auth == 'sspi')) return;
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(401); return; }
|
||||
|
||||
// Get the email from the body or session.
|
||||
var email = req.body.email;
|
||||
@ -840,7 +947,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Called to process a web based email verification request
|
||||
function handleCheckMailRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if ((domain == null) || (domain.auth == 'sspi')) return;
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(401); return; }
|
||||
|
||||
if (req.query.c != null) {
|
||||
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
|
||||
@ -927,7 +1034,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
function handleDeleteAccountRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if ((domain == null) || (domain.auth == 'sspi')) return;
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(401); return; }
|
||||
|
||||
// Check if the user is logged and we have all required parameters
|
||||
if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
||||
@ -998,7 +1105,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Handle password changes
|
||||
function handlePasswordChangeRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if ((domain == null) || (domain.auth == 'sspi')) return;
|
||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(401); return; }
|
||||
|
||||
// Check if the user is logged and we have all required parameters
|
||||
if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
||||
@ -1038,15 +1145,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
domain.sspi.authenticate(req, res, function (err) { if ((err != null) || (req.connection.user == null)) { res.end('Authentication Required...'); } else { handleRootRequestEx(req, res, domain); } });
|
||||
} else if (req.query.user && req.query.pass) {
|
||||
// User credentials are being passed in the URL. WARNING: Putting credentials in a URL is not good security... but people are requesting this option.
|
||||
var userid = 'user/' + domain.id + '/' + req.query.user.toLowerCase();
|
||||
if (obj.users[userid] != null) {
|
||||
obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
|
||||
req.session.userid = userid;
|
||||
req.session.domainid = domain.id;
|
||||
req.session.currentNode = '';
|
||||
handleRootRequestEx(req, res, domain);
|
||||
});
|
||||
}
|
||||
obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
|
||||
req.session.userid = userid;
|
||||
req.session.domainid = domain.id;
|
||||
req.session.currentNode = '';
|
||||
handleRootRequestEx(req, res, domain);
|
||||
});
|
||||
} else {
|
||||
// Login using a different system
|
||||
handleRootRequestEx(req, res, domain);
|
||||
@ -1174,6 +1278,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (domain.geolocation == true) { features += 0x00008000; } // Enable geo-location features
|
||||
if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { features += 0x00010000; } // Enable password hints
|
||||
if ((parent.config.settings.no2factorauth !== true) && (obj.f2l != null)) { features += 0x00020000; } // Enable WebAuthn/FIDO2 support
|
||||
if ((obj.args.nousers != true) && (domain.passwordrequirements != null) && (domain.passwordrequirements.force2factor === true)) { features += 0x00040000; } // Force 2-factor auth
|
||||
|
||||
// Create a authentication cookie
|
||||
const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
|
||||
@ -1185,14 +1290,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (obj.args.minify && !req.query.nominify) {
|
||||
// Try to server the minified version if we can.
|
||||
try {
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile-min' : 'default-min'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile-min' : 'default-min'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
} catch (ex) {
|
||||
// In case of an exception, serve the non-minified version.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
} else {
|
||||
// Serve non-minified version of web pages.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
} else {
|
||||
// Send back the login application
|
||||
@ -2184,6 +2289,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.db.Get(req.query.nodeid, function (err, nodes) {
|
||||
if (nodes.length != 1) { res.sendStatus(401); return; }
|
||||
var node = nodes[0];
|
||||
|
||||
// Create the meshaction.txt file for meshcmd.exe
|
||||
var meshaction = {
|
||||
action: req.query.meshaction,
|
||||
@ -2194,7 +2300,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
username: '',
|
||||
password: '',
|
||||
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
|
||||
serverHttpsHash: Buffer.from(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
serverHttpsHash: Buffer.from(obj.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
debugLevel: 0
|
||||
};
|
||||
if (user != null) { meshaction.username = user.name; }
|
||||
@ -2209,7 +2315,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
username: '',
|
||||
password: '',
|
||||
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
|
||||
serverHttpsHash: Buffer.from(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
serverHttpsHash: Buffer.from(obj.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
debugLevel: 0
|
||||
};
|
||||
if (user != null) { meshaction.username = user.name; }
|
||||
|
Loading…
Reference in New Issue
Block a user