diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe index cad927b7..9400b575 100644 Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ diff --git a/agents/MeshCmd64-signed.exe b/agents/MeshCmd64-signed.exe index 0e7392b6..aa0818a4 100644 Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ diff --git a/agents/MeshService-signed.exe b/agents/MeshService-signed.exe index a04335e5..15e20346 100644 Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ diff --git a/agents/MeshService64-signed.exe b/agents/MeshService64-signed.exe index f499154d..6a24af09 100644 Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ diff --git a/agents/meshcore.js b/agents/meshcore.js index 75c8f226..af31e2f1 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -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 } diff --git a/agents/meshcore.min.js b/agents/meshcore.min.js index 5ceee0c2..0a08d7ba 100644 --- a/agents/meshcore.min.js +++ b/agents/meshcore.min.js @@ -1 +1 @@ -process.on("uncaughtException",function(a){require("MeshAgent").SendCommand({action:"msg",type:"console",value:"uncaughtException1: "+a})});var MESHRIGHT_EDITMESH=1;var MESHRIGHT_MANAGEUSERS=2;var MESHRIGHT_MANAGECOMPUTERS=4;var MESHRIGHT_REMOTECONTROL=8;var MESHRIGHT_AGENTCONSOLE=16;var MESHRIGHT_SERVERFILES=32;var MESHRIGHT_WAKEDEVICE=64;var MESHRIGHT_SETNOTES=128;var MESHRIGHT_REMOTEVIEW=256;var MESHRIGHT_NOTERMINAL=512;var MESHRIGHT_NOFILES=1024;var MESHRIGHT_NOAMT=2048;var MESHRIGHT_LIMITEDINPUT=4096;function createMeshCore(agent){var obj={};var meshCoreObj={action:"coreinfo",value:"MeshCore v6",caps:14};try{require("os").name().then(function(v){meshCoreObj.osdesc=v})}catch(ex){}var meshServerConnectionState=0;var tunnels={};var lastMeInfo=null;var lastNetworkInfo=null;var lastPublicLocationInfo=null;var selfInfoUpdateTimer=null;var http=require("http");var net=require("net");var fs=require("fs");var rtc=require("ILibWebRTC");var amt=null;var processManager=require("process-manager");var wifiScannerLib=null;var wifiScanner=null;var networkMonitor=null;var amtscanner=null;var nextTunnelIndex=1;var amtPolicy=null;if(agent==null){db=require("SimpleDataStore").Shared();sha=require("SHA256Stream");mesh=require("MeshAgent");childProcess=require("child_process");if(mesh.hasKVM==1){try{if((process.platform=="win32")||(process.platform=="darwin")||(require("monitor-info").kvm_x11_support)){meshCoreObj.caps|=1}}catch(ex){}}}else{meshCoreObj.value+="-NodeJS";meshCoreObj.caps=8;mesh=agent.getMeshApi()}try{var AMTScannerModule=require("amt-scanner");amtscanner=new AMTScannerModule()}catch(ex){amtscanner=null}var SMBiosTables=null;var SMBiosTablesRaw=null;try{var SMBiosModule=null;try{SMBiosModule=require("smbios")}catch(ex){}if(SMBiosModule!=null){SMBiosModule.get(function(data){if(data!=null){SMBiosTablesRaw=data;SMBiosTables=require("smbios").parse(data);if(mesh.isControlChannelConnected){mesh.SendCommand({action:"smbios",value:SMBiosTablesRaw})}if(SMBiosTables.amtInfo&&(SMBiosTables.amtInfo.AMT==true)){var amtmodule=require("amt-manage");amt=new amtmodule(mesh,db,true);amt.onStateChange=function(state){if(state==2){sendPeriodicServerUpdate(1)}};if(amtPolicy!=null){amt.setPolicy(amtPolicy)}amt.start()}}})}}catch(ex){sendConsoleText("ex1: "+ex)}try{var wifiScannerLib=require("wifi-scanner");wifiScanner=new wifiScannerLib();wifiScanner.on("accessPoint",function(data){sendConsoleText("wifiScanner: "+data)})}catch(ex){wifiScannerLib=null;wifiScanner=null}var getIpLocationDataExInProgress=false;var getIpLocationDataExCounts=[0,0];function getIpLocationDataEx(func){if(getIpLocationDataExInProgress==true){return false}try{getIpLocationDataExInProgress=true;getIpLocationDataExCounts[0]++;var options=http.parseUri("http://ipinfo.io/json");options.method="GET";http.request(options,function(resp){if(resp.statusCode==200){var geoData="";resp.data=function(geoipdata){geoData+=geoipdata};resp.end=function(){var location=null;try{if(typeof geoData=="string"){var result=JSON.parse(geoData);if(result.ip&&result.loc){location=result}}}catch(e){}if(func){getIpLocationDataExCounts[1]++;func(location)}}}else{func(null)}getIpLocationDataExInProgress=false}).end();return true}catch(e){return false}}function clearGatewayMac(str){if(str==null){return null}var x=JSON.parse(str);for(var i in x.netif){if(x.netif[i].gatewaymac){delete x.netif[i].gatewaymac}}return JSON.stringify(x)}function getIpLocationData(func){var publicLocationInfo=db.Get("publicLocationInfo");if(publicLocationInfo!=null){publicLocationInfo=JSON.parse(publicLocationInfo)}if(publicLocationInfo==null){getIpLocationDataEx(function(locationData){if(locationData!=null){publicLocationInfo={};publicLocationInfo.netInfoStr=lastNetworkInfo;publicLocationInfo.locationData=locationData;var x=db.Put("publicLocationInfo",JSON.stringify(publicLocationInfo));if(func){func(locationData)}}else{if(func){func(null)}}})}else{if(clearGatewayMac(publicLocationInfo.netInfoStr)==clearGatewayMac(lastNetworkInfo)){if(func){func(publicLocationInfo.locationData)}}else{getIpLocationDataEx(function(locationData){if(locationData!=null){publicLocationInfo={};publicLocationInfo.netInfoStr=lastNetworkInfo;publicLocationInfo.locationData=locationData;var x=db.Put("publicLocationInfo",JSON.stringify(publicLocationInfo));if(func){func(locationData)}}else{if(func){func(publicLocationInfo.locationData)}}})}}}if(!String.prototype.endsWith){String.prototype.endsWith=function(searchString,position){var subjectString=this.toString();if(typeof position!=="number"||!isFinite(position)||Math.floor(position)!==position||position>subjectString.length){position=subjectString.length}position-=searchString.length;var lastIndex=subjectString.lastIndexOf(searchString,position);return lastIndex!==-1&&lastIndex===position}}obj.path={join:function(){var x=[];for(var i in arguments){var w=arguments[i];if(w!=null){while(w.endsWith("/")||w.endsWith("\\")){w=w.substring(0,w.length-1)}if(i!=0){while(w.startsWith("/")||w.startsWith("\\")){w=w.substring(1)}}x.push(w)}}if(x.length==0){return"/"}return x.join("/")}};function toNumberIfNumber(x){if((typeof x=="string")&&(+parseInt(x)===x)){x=parseInt(x)}return x}function char2hex(i){return(i+256).toString(16).substr(-2).toUpperCase()}function rstr2hex(input){var r="",i;for(i=0;i8){return"[...]"}if(x==undefined){return"[undefined]"}if(typeof x=="string"){if(p==0){return x}return'"'+x+'"'}if(typeof x=="buffer"){return"[buffer]"}if(typeof x!="object"){return x}var r="{"+(ret?"\r\n":" ");for(var i in x){if(i!="_ObjectID"){r+=(addPad(p+2,pad)+i+": "+objToString(x[i],p+2,pad,ret)+(ret?"\r\n":" "))}}return r+addPad(p,pad)+"}"}function addPad(p,ret){var r="";for(var i=0;i2&&x[0]=="-"&&x[1]=="-"){if(current!=null){results[current]=true}current=x.substring(2)}else{if(current!=null){results[current]=toNumberIfNumber(x);current=null}else{results._.push(toNumberIfNumber(x))}}}if(current!=null){results[current]=true}return results}function getServerTargetUrl(path){var x=mesh.ServerUrl;if(x==null){return null}if(path==null){path=""}x=http.parseUri(x);if(x==null){return null}return x.protocol+"//"+x.host+":"+x.port+"/"+path}function getServerTargetUrlEx(url){if(url.substring(0,2)=="*/"){return getServerTargetUrl(url.substring(2))}return url}function sendWakeOnLan(hexMac){var count=0;try{var interfaces=require("os").networkInterfaces();var magic="FFFFFFFFFFFF";for(var x=1;x<=16;++x){magic+=hexMac}var magicbin=Buffer.from(magic,"hex");for(var adapter in interfaces){if(interfaces.hasOwnProperty(adapter)){for(var i=0;i0){sendNextBlock--;var buf=new Buffer(4096);var len=fs.readSync(this.filedownload.f,buf,4,4092,null);this.filedownload.ptr+=len;if(len<4092){buf.writeInt32BE(16777217,0);fs.closeSync(this.filedownload.f);delete this.filedownload;sendNextBlock=0}else{buf.writeInt32BE(16777216,0)}this.write(buf.slice(0,len+4))}break;case"upload":if(this.httprequest.uploadFile!=undefined){fs.closeSync(this.httprequest.uploadFile);this.httprequest.uploadFile=undefined}if(cmd.path==undefined){break}var filepath=cmd.name?obj.path.join(cmd.path,cmd.name):cmd.path;try{this.httprequest.uploadFile=fs.openSync(filepath,"wbN")}catch(e){this.write(new Buffer(JSON.stringify({action:"uploaderror",reqid:cmd.reqid})));break}this.httprequest.uploadFileid=cmd.reqid;if(this.httprequest.uploadFile){this.write(new Buffer(JSON.stringify({action:"uploadstart",reqid:this.httprequest.uploadFileid})))}break;case"copy":for(var i in cmd.names){var sc=obj.path.join(cmd.scpath,cmd.names[i]),ds=obj.path.join(cmd.dspath,cmd.names[i]);if(sc!=ds){try{fs.copyFileSync(sc,ds)}catch(e){}}}break;case"move":for(var i in cmd.names){var sc=obj.path.join(cmd.scpath,cmd.names[i]),ds=obj.path.join(cmd.dspath,cmd.names[i]);if(sc!=ds){try{fs.copyFileSync(sc,ds);fs.unlinkSync(sc)}catch(e){}}}break;default:break}}}}}}}function deleteFolderRecursive(path,rec){if(fs.existsSync(path)){if(rec==true){fs.readdirSync(obj.path.join(path,"*")).forEach(function(file,index){var curPath=obj.path.join(path,file);if(fs.statSync(curPath).isDirectory()){deleteFolderRecursive(curPath,true)}else{fs.unlinkSync(curPath)}})}fs.unlinkSync(path)}}function onTunnelWebRTCControlData(data){if(typeof data!="string"){return}var obj;try{obj=JSON.parse(data)}catch(e){sendConsoleText("Invalid control JSON on WebRTC: "+data);return}if(obj.type=="close"){try{this.close()}catch(e){}try{this.xrtc.close()}catch(e){}}}function onTunnelControlData(data,ws){var obj;if(ws==null){ws=this}if(typeof data=="string"){try{obj=JSON.parse(data)}catch(e){sendConsoleText("Invalid control JSON: "+data);return}}else{if(typeof data=="object"){obj=data}else{return}}if(obj.action){switch(obj.action){case"lock":try{if(process.platform=="win32"){var child=require("child_process");child.execFile(process.env.windir+"\\system32\\cmd.exe",["/c","RunDll32.exe user32.dll,LockWorkStation"],{type:1})}}catch(e){}break;default:break}return}if(obj.type=="close"){try{ws.close()}catch(e){}}else{if(obj.type=="webrtc0"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.httprequest._term.unpipe(ws)}else{ws.httprequest.process.stdout.unpipe(ws);ws.httprequest.process.stderr.unpipe(ws)}}else{if(ws.httprequest.protocol==2){ws.httprequest.desktop.kvm.unpipe(ws)}else{ws.rtcchannel.httprequest=ws.httprequest;ws.rtcchannel.removeAllListeners("data");ws.rtcchannel.on("data",onTunnelData)}}ws.write('{"ctrlChannel":"102938","type":"webrtc1"}')}else{if(obj.type=="webrtc1"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.unpipe(ws.httprequest._term);ws.rtcchannel.pipe(ws.httprequest._term,{dataTypeSkip:1})}else{ws.unpipe(ws.httprequest.process.stdin);ws.rtcchannel.pipe(ws.httprequest.process.stdin,{dataTypeSkip:1})}ws.resume()}else{if(ws.httprequest.protocol==2){ws.unpipe(ws.httprequest.desktop.kvm);try{ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm,{dataTypeSkip:1,end:false})}catch(e){sendConsoleText("EX2")}ws.resume()}}ws.write('{"ctrlChannel":"102938","type":"webrtc2"}')}else{if(obj.type=="webrtc2"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.httprequest._term.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false})}else{ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false});ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false})}}else{if(ws.httprequest.protocol==2){ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1})}}}else{if(obj.type=="offer"){if(ws.httprequest.protocol==1){return}ws.webrtc=rtc.createConnection();ws.webrtc.websocket=ws;ws.webrtc.on("connected",function(){});ws.webrtc.on("disconnected",function(){});ws.webrtc.on("dataChannel",function(rtcchannel){rtcchannel.xrtc=this;rtcchannel.websocket=this.websocket;this.rtcchannel=rtcchannel;this.websocket.rtcchannel=rtcchannel;this.websocket.rtcchannel.on("data",onTunnelWebRTCControlData);this.websocket.rtcchannel.on("end",function(){if(this.websocket.desktop&&this.websocket.desktop.kvm){this.unpipe(this.websocket.desktop.kvm);this.websocket.httprequest.desktop.kvm.unpipe(this)}});this.websocket.write('{"ctrlChannel":"102938","type":"webrtc0"}')});var sdp=null;try{sdp=ws.webrtc.setOffer(obj.sdp)}catch(ex){}if(sdp!=null){ws.write({type:"answer",ctrlChannel:"102938",sdp:sdp})}}}}}}}var consoleWebSockets={};var consoleHttpRequest=null;function consoleHttpResponse(response){response.data=function(data){sendConsoleText(rstr2hex(buf2rstr(data)),this.sessionid);consoleHttpRequest=null};response.close=function(){sendConsoleText("httprequest.response.close",this.sessionid);consoleHttpRequest=null}}function openUserDesktopUrl(url){var child=null;try{switch(process.platform){case"win32":child=require("child_process").execFile(process.env.windir+"\\system32\\cmd.exe",["/c","start",url],{type:childProcess.SpawnTypes.USER});break;case"linux":child=require("child_process").execFile("/usr/bin/xdg-open",["xdg-open",url],{uid:require("user-sessions").consoleUid()});break;case"darwin":child=require("child_process").execFile("/usr/bin/open",["open",url],{uid:require("user-sessions").consoleUid()});break;default:break}}catch(ex){}return child}function processConsoleCommand(cmd,args,rights,sessionid){try{var response=null;switch(cmd){case"help":response="Available commands: help, info, osinfo,args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendcaps, openurl, amtreset, amtccm, amtdeactivate,\r\namtpolicy, getscript, getclip, setclip.";break;case"getclip":if(require("MeshAgent").isService){require("clipboard").dispatchRead().then(function(str){sendConsoleText(str,sessionid)})}else{require("clipboard").read().then(function(str){sendConsoleText(str,sessionid)})}break;case"setclip":if(args._.length!=1){response='Proper usage: setclip "sample text"'}else{if(require("MeshAgent").isService){require("clipboard").dispatchWrite(args._[0]);response='Setting clipboard to: "'+args._[0]+'"'}else{require("clipboard")(args._[0]);response='Setting clipboard to: "'+args._[0]+'"'}}break;case"amtreset":if(amt!=null){amt.reset();response="Done."}break;case"amtlmsreset":if(amt!=null){amt.lmsreset();response="Done."}break;case"amtccm":if(amt==null){response="Intel AMT not supported."}else{if(args._.length!=1){response="Proper usage: amtccm (adminPassword)"}else{amt.setPolicy({type:0});amt.activeToCCM(args._[0])}}break;case"amtdeactivate":if(amt==null){response="Intel AMT not supported."}else{amt.setPolicy({type:0});amt.deactivateCCM()}break;case"amtpolicy":if(amtPolicy==null){response="No Intel(R) AMT policy."}else{response=JSON.stringify(amtPolicy)}break;case"openurl":if(args._.length!=1){response="Proper usage: openurl (url)"}else{if(openUserDesktopUrl(args._[0])==null){response="Failed."}else{response="Success."}}break;case"users":if(meshCoreObj.users==null){response="Active users are unknown."}else{response="Active Users: "+meshCoreObj.users.join(", ")+"."}require("user-sessions").enumerateUsers().then(function(u){for(var i in u){sendConsoleText(u[i])}});break;case"toast":if(process.platform=="win32"){if(args._.length<1){response='Proper usage: toast "message"'}else{require("toaster").Toast("MeshCentral",args._[0]);response="ok"}}else{response="Only supported on Windows."}break;case"setdebug":if(args._.length<1){response="Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile"}else{if(args._[0]=="*"){console.setDestination(2)}else{console.setDestination(parseInt(args._[0]),sessionid)}}break;case"ps":processManager.getProcesses(function(plist){var x="";for(var i in plist){x+=i+", "+plist[i].cmd+((plist[i].user)?(", "+plist[i].user):"")+"\r\n"}sendConsoleText(x,sessionid)});break;case"kill":if((args._.length<1)){response="Proper usage: kill [pid]"}else{process.kill(parseInt(args._[0]));response="Killed process "+args._[0]+"."}break;case"smbios":if(SMBiosTables==null){response="SMBios tables not available."}else{response=objToString(SMBiosTables,0," ",true)}break;case"rawsmbios":if(SMBiosTablesRaw==null){response="SMBios tables not available."}else{response="";for(var i in SMBiosTablesRaw){var header=false;for(var j in SMBiosTablesRaw[i]){if(SMBiosTablesRaw[i][j].length>0){if(header==false){response+=("Table type #"+i+((require("smbios").smTableTypes[i]==null)?"":(", "+require("smbios").smTableTypes[i])))+"\r\n";header=true}response+=(" "+SMBiosTablesRaw[i][j].toString("hex"))+"\r\n"}}}}break;case"eval":if(args._.length<1){response='Proper usage: eval "JavaScript code"'}else{response=JSON.stringify(mesh.eval(args._[0]))}break;case"notify":if(args._.length!=1){response='Proper usage: notify "message" [--session]'}else{var notification={action:"msg",type:"notify",value:args._[0],tag:"console"};if(args.session){notification.sessionid=sessionid}mesh.SendCommand(notification);response="ok"}break;case"info":response="Current Core: "+meshCoreObj.value+".\r\nAgent Time: "+Date()+".\r\nUser Rights: 0x"+rights.toString(16)+".\r\nPlatform: "+process.platform+".\r\nCapabilities: "+meshCoreObj.caps+".\r\nServer URL: "+mesh.ServerUrl+".";if(amt!=null){response+="\r\nBuilt-in LMS: "+["Disabled","Connecting..","Connected"][amt.lmsstate]+"."}if(meshCoreObj.osdesc){response+="\r\nOS: "+meshCoreObj.osdesc+"."}response+="\r\nModules: "+addedModules.join(", ")+".";response+="\r\nServer Connection: "+mesh.isControlChannelConnected+", State: "+meshServerConnectionState+".";response+="\rlastMeInfo: "+lastMeInfo+".";var oldNodeId=db.Get("OldNodeId");if(oldNodeId!=null){response+="\r\nOldNodeID: "+oldNodeId+"."}if(process.platform!="win32"){response+="\r\nX11 support: "+require("monitor-info").kvm_x11_support+"."}break;case"osinfo":var i=1;if(args._.length>0){i=parseInt(args._[0]);if(i>8){i=8}response="Calling "+i+" times."}for(var j=0;j0){meshCoreObj.osdesc=args._[0];mesh.SendCommand(meshCoreObj);response=JSON.stringify(meshCoreObj)}else{response="Proper usage: sendosdesc [os description]"}break;case"args":response="args "+objToString(args,0," ",true);break;case"print":var r=[];for(var i in args._){r.push(args._[i])}console.log(r.join(" "));response="Message printed on agent console.";break;case"type":if(args._.length==0){response="Proper usage: type (filepath) [maxlength]"}else{var max=4096;if((args._.length>1)&&(typeof args._[1]=="number")){max=args._[1]}if(max>4096){max=4096}var buf=Buffer.alloc(max),fd=fs.openSync(args._[0],"r"),r=fs.readSync(fd,buf,0,max);response=buf.toString();var i=response.indexOf("\n");if((i>0)&&(response[i-1]!="\r")){response=response.split("\n").join("\r\n")}if(r==max){response+="..."}fs.closeSync(fd)}break;case"dbkeys":response=JSON.stringify(db.Keys);break;case"dbget":if(db==null){response="Database not accessible.";break}if(args._.length!=1){response="Proper usage: dbget (key)"}else{response=db.Get(args._[0])}break;case"dbset":if(db==null){response="Database not accessible.";break}if(args._.length!=2){response="Proper usage: dbset (key) (value)"}else{var r=db.Put(args._[0],args._[1]);response="Key set: "+r}break;case"dbcompact":if(db==null){response="Database not accessible.";break}var r=db.Compact();response="Database compacted: "+r;break;case"httpget":if(consoleHttpRequest!=null){response="HTTP operation already in progress."}else{if(args._.length!=1){response="Proper usage: httpget (url)"}else{var options=http.parseUri(args._[0]);options.method="GET";if(options==null){response="Invalid url."}else{try{consoleHttpRequest=http.request(options,consoleHttpResponse)}catch(e){response="Invalid HTTP GET request"}consoleHttpRequest.sessionid=sessionid;if(consoleHttpRequest!=null){consoleHttpRequest.end();response="HTTPGET "+options.protocol+"//"+options.host+":"+options.port+options.path}}}}break;case"wslist":response="";for(var i in consoleWebSockets){var httprequest=consoleWebSockets[i];response+="Websocket #"+i+", "+httprequest.url+"\r\n"}if(response==""){response="no websocket sessions."}break;case"wsconnect":if(args._.length==0){response="Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc"}else{var httprequest=null;try{var options=http.parseUri(args._[0]);options.rejectUnauthorized=0;httprequest=http.request(options)}catch(e){response="Invalid HTTP websocket request"}if(httprequest!=null){httprequest.upgrade=onWebSocketUpgrade;httprequest.on("error",function(e){sendConsoleText("ERROR: "+JSON.stringify(e))});var index=1;while(consoleWebSockets[index]){index++}httprequest.sessionid=sessionid;httprequest.index=index;httprequest.url=args._[0];consoleWebSockets[index]=httprequest;response="New websocket session #"+index}}break;case"wssend":if(args._.length==0){response="Proper usage: wssend (socketnumber)\r\n";for(var i in consoleWebSockets){var httprequest=consoleWebSockets[i];response+="Websocket #"+i+", "+httprequest.url+"\r\n"}}else{var i=parseInt(args._[0]);var httprequest=consoleWebSockets[i];if(httprequest!=undefined){httprequest.s.write(args._[1]);response="ok"}else{response="Invalid web socket number"}}break;case"wsclose":if(args._.length==0){response="Proper usage: wsclose (socketnumber)"}else{var i=parseInt(args._[0]);var httprequest=consoleWebSockets[i];if(httprequest!=undefined){if(httprequest.s!=null){httprequest.s.end()}else{httprequest.end()}response="ok"}else{response="Invalid web socket number"}}break;case"tunnels":response="";for(var i in tunnels){response+="Tunnel #"+i+", "+tunnels[i].url+"\r\n"}if(response==""){response="No websocket sessions."}break;case"ls":response="";var xpath="*";if(args._.length>0){xpath=obj.path.join(args._[0],"*")}response="List of "+xpath+"\r\n";var results=fs.readdirSync(xpath);for(var i=0;i0){var r="",pstates=["NotActivated","InActivation","Activated"];for(var i in data){var x=data[i];if(r!=""){r+="\r\n"}r+=x.address+" - Intel AMT v"+x.majorVersion+"."+x.minorVersion;if(x.provisioningState<3){r+=(", "+pstates[x.provisioningState])}if(x.provisioningState==2){r+=(", "+x.openPorts.join(", "))}r+="."}}else{r="No Intel AMT found."}sendConsoleText(r)})}}else{response="Intel AMT scanner module not present."}break;case"modules":response=JSON.stringify(addedModules);break;case"getscript":if(args._.length!=1){response="Proper usage: getscript [scriptNumber]."}else{mesh.SendCommand({action:"getScript",type:args._[0]})}break;default:response='Unknown command "'+cmd+'", type "help" for list of avaialble commands.';break}}catch(e){response="Command returned an exception error: "+e;console.log(e)}if(response!=null){sendConsoleText(response,sessionid)}}function sendConsoleText(text,sessionid){if(typeof text=="object"){text=JSON.stringify(text)}mesh.SendCommand({action:"msg",type:"console",value:text,sessionid:sessionid})}function handleServerConnection(state){meshServerConnectionState=state;if(meshServerConnectionState==0){if(selfInfoUpdateTimer!=null){clearInterval(selfInfoUpdateTimer);selfInfoUpdateTimer=null}lastSelfInfo=null}else{var oldNodeId=db.Get("OldNodeId");if(oldNodeId!=null){mesh.SendCommand({action:"mc1migration",oldnodeid:oldNodeId})}mesh.SendCommand(meshCoreObj);if(SMBiosTablesRaw!=null){mesh.SendCommand({action:"smbios",value:SMBiosTablesRaw})}meInfoStr=null;sendPeriodicServerUpdate()}}var sendNetworkUpdateNagleTimer=null;function sendNetworkUpdateNagle(){if(sendNetworkUpdateNagleTimer!=null){clearTimeout(sendNetworkUpdateNagleTimer);sendNetworkUpdateNagleTimer=null}sendNetworkUpdateNagleTimer=setTimeout(sendNetworkUpdate,5000)}function sendNetworkUpdate(force){sendNetworkUpdateNagleTimer=null;var netInfo=mesh.NetInfo;netInfo.action="netinfo";var netInfoStr=JSON.stringify(netInfo);if((force==true)||(clearGatewayMac(netInfoStr)!=clearGatewayMac(lastNetworkInfo))){mesh.SendCommand(netInfo);lastNetworkInfo=netInfoStr}}function sendPeriodicServerUpdate(flags){if(meshServerConnectionState==0){return}if(!flags){flags=4294967295}if((flags&1)&&(amt!=null)){amt.getAmtInfo(function(meinfo){try{if(meinfo==null){return}var intelamt={},p=false;if(meinfo.Versions&&meinfo.Versions.AMT){intelamt.ver=meinfo.Versions.AMT;p=true}if(meinfo.ProvisioningState){intelamt.state=meinfo.ProvisioningState;p=true}if(meinfo.Flags){intelamt.flags=meinfo.Flags;p=true}if(meinfo.OsHostname){intelamt.host=meinfo.OsHostname;p=true}if(meinfo.UUID){intelamt.uuid=meinfo.UUID;p=true}if(p==true){var meInfoStr=JSON.stringify(intelamt);if(meInfoStr!=lastMeInfo){meshCoreObj.intelamt=intelamt;mesh.SendCommand(meshCoreObj);lastMeInfo=meInfoStr}}}catch(ex){}})}if(flags&2){sendNetworkUpdateNagle(false)}}obj.start=function(){mesh.AddCommandHandler(handleServerCommand);mesh.AddConnectHandler(handleServerConnection);try{var userSession=require("user-sessions");userSession.on("changed",function onUserSessionChanged(){userSession.enumerateUsers().then(function(users){var u=[],a=users.Active;for(var i=0;isubjectString.length){position=subjectString.length}position-=searchString.length;var lastIndex=subjectString.lastIndexOf(searchString,position);return lastIndex!==-1&&lastIndex===position}}obj.path={join:function(){var x=[];for(var i in arguments){var w=arguments[i];if(w!=null){while(w.endsWith("/")||w.endsWith("\\")){w=w.substring(0,w.length-1)}if(i!=0){while(w.startsWith("/")||w.startsWith("\\")){w=w.substring(1)}}x.push(w)}}if(x.length==0){return"/"}return x.join("/")}};function toNumberIfNumber(x){if((typeof x=="string")&&(+parseInt(x)===x)){x=parseInt(x)}return x}function char2hex(i){return(i+256).toString(16).substr(-2).toUpperCase()}function rstr2hex(input){var r="",i;for(i=0;i8){return"[...]"}if(x==undefined){return"[undefined]"}if(typeof x=="string"){if(p==0){return x}return'"'+x+'"'}if(typeof x=="buffer"){return"[buffer]"}if(typeof x!="object"){return x}var r="{"+(ret?"\r\n":" ");for(var i in x){if(i!="_ObjectID"){r+=(addPad(p+2,pad)+i+": "+objToString(x[i],p+2,pad,ret)+(ret?"\r\n":" "))}}return r+addPad(p,pad)+"}"}function addPad(p,ret){var r="";for(var i=0;i2&&x[0]=="-"&&x[1]=="-"){if(current!=null){results[current]=true}current=x.substring(2)}else{if(current!=null){results[current]=toNumberIfNumber(x);current=null}else{results._.push(toNumberIfNumber(x))}}}if(current!=null){results[current]=true}return results}function getServerTargetUrl(path){var x=mesh.ServerUrl;if(x==null){return null}if(path==null){path=""}x=http.parseUri(x);if(x==null){return null}return x.protocol+"//"+x.host+":"+x.port+"/"+path}function getServerTargetUrlEx(url){if(url.substring(0,2)=="*/"){return getServerTargetUrl(url.substring(2))}return url}function sendWakeOnLan(hexMac){var count=0;try{var interfaces=require("os").networkInterfaces();var magic="FFFFFFFFFFFF";for(var x=1;x<=16;++x){magic+=hexMac}var magicbin=Buffer.from(magic,"hex");for(var adapter in interfaces){if(interfaces.hasOwnProperty(adapter)){for(var i=0;i0){sendNextBlock--;var buf=new Buffer(4096);var len=fs.readSync(this.filedownload.f,buf,4,4092,null);this.filedownload.ptr+=len;if(len<4092){buf.writeInt32BE(16777217,0);fs.closeSync(this.filedownload.f);delete this.filedownload;sendNextBlock=0}else{buf.writeInt32BE(16777216,0)}this.write(buf.slice(0,len+4))}break;case"upload":if(this.httprequest.uploadFile!=undefined){fs.closeSync(this.httprequest.uploadFile);this.httprequest.uploadFile=undefined}if(cmd.path==undefined){break}var filepath=cmd.name?obj.path.join(cmd.path,cmd.name):cmd.path;try{this.httprequest.uploadFile=fs.openSync(filepath,"wbN")}catch(e){this.write(new Buffer(JSON.stringify({action:"uploaderror",reqid:cmd.reqid})));break}this.httprequest.uploadFileid=cmd.reqid;if(this.httprequest.uploadFile){this.write(new Buffer(JSON.stringify({action:"uploadstart",reqid:this.httprequest.uploadFileid})))}break;case"copy":for(var i in cmd.names){var sc=obj.path.join(cmd.scpath,cmd.names[i]),ds=obj.path.join(cmd.dspath,cmd.names[i]);if(sc!=ds){try{fs.copyFileSync(sc,ds)}catch(e){}}}break;case"move":for(var i in cmd.names){var sc=obj.path.join(cmd.scpath,cmd.names[i]),ds=obj.path.join(cmd.dspath,cmd.names[i]);if(sc!=ds){try{fs.copyFileSync(sc,ds);fs.unlinkSync(sc)}catch(e){}}}break;default:break}}}}}}}function deleteFolderRecursive(path,rec){if(fs.existsSync(path)){if(rec==true){fs.readdirSync(obj.path.join(path,"*")).forEach(function(file,index){var curPath=obj.path.join(path,file);if(fs.statSync(curPath).isDirectory()){deleteFolderRecursive(curPath,true)}else{fs.unlinkSync(curPath)}})}fs.unlinkSync(path)}}function onTunnelWebRTCControlData(data){if(typeof data!="string"){return}var obj;try{obj=JSON.parse(data)}catch(e){sendConsoleText("Invalid control JSON on WebRTC: "+data);return}if(obj.type=="close"){try{this.close()}catch(e){}try{this.xrtc.close()}catch(e){}}}function onTunnelControlData(data,ws){var obj;if(ws==null){ws=this}if(typeof data=="string"){try{obj=JSON.parse(data)}catch(e){sendConsoleText("Invalid control JSON: "+data);return}}else{if(typeof data=="object"){obj=data}else{return}}if(obj.action){switch(obj.action){case"lock":try{if(process.platform=="win32"){var child=require("child_process");child.execFile(process.env.windir+"\\system32\\cmd.exe",["/c","RunDll32.exe user32.dll,LockWorkStation"],{type:1})}}catch(e){}break;default:break}return}if(obj.type=="close"){try{ws.close()}catch(e){}}else{if(obj.type=="webrtc0"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.httprequest._term.unpipe(ws)}else{ws.httprequest.process.stdout.unpipe(ws);ws.httprequest.process.stderr.unpipe(ws)}}else{if(ws.httprequest.protocol==2){ws.httprequest.desktop.kvm.unpipe(ws)}else{ws.rtcchannel.httprequest=ws.httprequest;ws.rtcchannel.removeAllListeners("data");ws.rtcchannel.on("data",onTunnelData)}}ws.write('{"ctrlChannel":"102938","type":"webrtc1"}')}else{if(obj.type=="webrtc1"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.unpipe(ws.httprequest._term);ws.rtcchannel.pipe(ws.httprequest._term,{dataTypeSkip:1})}else{ws.unpipe(ws.httprequest.process.stdin);ws.rtcchannel.pipe(ws.httprequest.process.stdin,{dataTypeSkip:1})}ws.resume()}else{if(ws.httprequest.protocol==2){ws.unpipe(ws.httprequest.desktop.kvm);try{ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm,{dataTypeSkip:1,end:false})}catch(e){sendConsoleText("EX2")}ws.resume()}}ws.write('{"ctrlChannel":"102938","type":"webrtc2"}')}else{if(obj.type=="webrtc2"){if(ws.httprequest.protocol==1){if(process.platform=="win32"){ws.httprequest._term.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false})}else{ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false});ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1,end:false})}}else{if(ws.httprequest.protocol==2){ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel,{dataTypeSkip:1})}}}else{if(obj.type=="offer"){if(ws.httprequest.protocol==1){return}ws.webrtc=rtc.createConnection();ws.webrtc.websocket=ws;ws.webrtc.on("connected",function(){});ws.webrtc.on("disconnected",function(){});ws.webrtc.on("dataChannel",function(rtcchannel){rtcchannel.xrtc=this;rtcchannel.websocket=this.websocket;this.rtcchannel=rtcchannel;this.websocket.rtcchannel=rtcchannel;this.websocket.rtcchannel.on("data",onTunnelWebRTCControlData);this.websocket.rtcchannel.on("end",function(){if(this.websocket.desktop&&this.websocket.desktop.kvm){this.unpipe(this.websocket.desktop.kvm);this.websocket.httprequest.desktop.kvm.unpipe(this)}});this.websocket.write('{"ctrlChannel":"102938","type":"webrtc0"}')});var sdp=null;try{sdp=ws.webrtc.setOffer(obj.sdp)}catch(ex){}if(sdp!=null){ws.write({type:"answer",ctrlChannel:"102938",sdp:sdp})}}}}}}}var consoleWebSockets={};var consoleHttpRequest=null;function consoleHttpResponse(response){response.data=function(data){sendConsoleText(rstr2hex(buf2rstr(data)),this.sessionid);consoleHttpRequest=null};response.close=function(){sendConsoleText("httprequest.response.close",this.sessionid);consoleHttpRequest=null}}function openUserDesktopUrl(url){var child=null;try{switch(process.platform){case"win32":child=require("child_process").execFile(process.env.windir+"\\system32\\cmd.exe",["/c","start",url],{type:childProcess.SpawnTypes.USER});break;case"linux":child=require("child_process").execFile("/usr/bin/xdg-open",["xdg-open",url],{uid:require("user-sessions").consoleUid()});break;case"darwin":child=require("child_process").execFile("/usr/bin/open",["open",url],{uid:require("user-sessions").consoleUid()});break;default:break}}catch(ex){}return child}function processConsoleCommand(cmd,args,rights,sessionid){try{var response=null;switch(cmd){case"help":response="Available commands: help, info, osinfo,args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendcaps, openurl, amtreset, amtccm, amtdeactivate,\r\namtpolicy, getscript, getclip, setclip.";break;case"getclip":if(require("MeshAgent").isService){require("clipboard").dispatchRead().then(function(str){sendConsoleText(str,sessionid)})}else{require("clipboard").read().then(function(str){sendConsoleText(str,sessionid)})}break;case"setclip":if(args._.length!=1){response='Proper usage: setclip "sample text"'}else{if(require("MeshAgent").isService){require("clipboard").dispatchWrite(args._[0]);response='Setting clipboard to: "'+args._[0]+'"'}else{require("clipboard")(args._[0]);response='Setting clipboard to: "'+args._[0]+'"'}}break;case"amtreset":if(amt!=null){amt.reset();response="Done."}break;case"amtlmsreset":if(amt!=null){amt.lmsreset();response="Done."}break;case"amtccm":if(amt==null){response="Intel AMT not supported."}else{if(args._.length!=1){response="Proper usage: amtccm (adminPassword)"}else{amt.setPolicy({type:0});amt.activeToCCM(args._[0])}}break;case"amtdeactivate":if(amt==null){response="Intel AMT not supported."}else{amt.setPolicy({type:0});amt.deactivateCCM()}break;case"amtpolicy":if(amtPolicy==null){response="No Intel(R) AMT policy."}else{response=JSON.stringify(amtPolicy)}break;case"openurl":if(args._.length!=1){response="Proper usage: openurl (url)"}else{if(openUserDesktopUrl(args._[0])==null){response="Failed."}else{response="Success."}}break;case"users":if(meshCoreObj.users==null){response="Active users are unknown."}else{response="Active Users: "+meshCoreObj.users.join(", ")+"."}require("user-sessions").enumerateUsers().then(function(u){for(var i in u){sendConsoleText(u[i])}});break;case"toast":if(process.platform=="win32"){if(args._.length<1){response='Proper usage: toast "message"'}else{require("toaster").Toast("MeshCentral",args._[0]);response="ok"}}else{response="Only supported on Windows."}break;case"setdebug":if(args._.length<1){response="Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile"}else{if(args._[0]=="*"){console.setDestination(2)}else{console.setDestination(parseInt(args._[0]),sessionid)}}break;case"ps":processManager.getProcesses(function(plist){var x="";for(var i in plist){x+=i+", "+plist[i].cmd+((plist[i].user)?(", "+plist[i].user):"")+"\r\n"}sendConsoleText(x,sessionid)});break;case"kill":if((args._.length<1)){response="Proper usage: kill [pid]"}else{process.kill(parseInt(args._[0]));response="Killed process "+args._[0]+"."}break;case"smbios":if(SMBiosTables==null){response="SMBios tables not available."}else{response=objToString(SMBiosTables,0," ",true)}break;case"rawsmbios":if(SMBiosTablesRaw==null){response="SMBios tables not available."}else{response="";for(var i in SMBiosTablesRaw){var header=false;for(var j in SMBiosTablesRaw[i]){if(SMBiosTablesRaw[i][j].length>0){if(header==false){response+=("Table type #"+i+((require("smbios").smTableTypes[i]==null)?"":(", "+require("smbios").smTableTypes[i])))+"\r\n";header=true}response+=(" "+SMBiosTablesRaw[i][j].toString("hex"))+"\r\n"}}}}break;case"eval":if(args._.length<1){response='Proper usage: eval "JavaScript code"'}else{response=JSON.stringify(mesh.eval(args._[0]))}break;case"notify":if(args._.length!=1){response='Proper usage: notify "message" [--session]'}else{var notification={action:"msg",type:"notify",value:args._[0],tag:"console"};if(args.session){notification.sessionid=sessionid}mesh.SendCommand(notification);response="ok"}break;case"info":response="Current Core: "+meshCoreObj.value+".\r\nAgent Time: "+Date()+".\r\nUser Rights: 0x"+rights.toString(16)+".\r\nPlatform: "+process.platform+".\r\nCapabilities: "+meshCoreObj.caps+".\r\nServer URL: "+mesh.ServerUrl+".";if(amt!=null){response+="\r\nBuilt-in LMS: "+["Disabled","Connecting..","Connected"][amt.lmsstate]+"."}if(meshCoreObj.osdesc){response+="\r\nOS: "+meshCoreObj.osdesc+"."}response+="\r\nModules: "+addedModules.join(", ")+".";response+="\r\nServer Connection: "+mesh.isControlChannelConnected+", State: "+meshServerConnectionState+".";response+="\rlastMeInfo: "+lastMeInfo+".";var oldNodeId=db.Get("OldNodeId");if(oldNodeId!=null){response+="\r\nOldNodeID: "+oldNodeId+"."}if(process.platform!="win32"){response+="\r\nX11 support: "+require("monitor-info").kvm_x11_support+"."}break;case"osinfo":var i=1;if(args._.length>0){i=parseInt(args._[0]);if(i>8){i=8}response="Calling "+i+" times."}for(var j=0;j0){meshCoreObj.osdesc=args._[0];mesh.SendCommand(meshCoreObj);response=JSON.stringify(meshCoreObj)}else{response="Proper usage: sendosdesc [os description]"}break;case"args":response="args "+objToString(args,0," ",true);break;case"print":var r=[];for(var i in args._){r.push(args._[i])}console.log(r.join(" "));response="Message printed on agent console.";break;case"type":if(args._.length==0){response="Proper usage: type (filepath) [maxlength]"}else{var max=4096;if((args._.length>1)&&(typeof args._[1]=="number")){max=args._[1]}if(max>4096){max=4096}var buf=Buffer.alloc(max),fd=fs.openSync(args._[0],"r"),r=fs.readSync(fd,buf,0,max);response=buf.toString();var i=response.indexOf("\n");if((i>0)&&(response[i-1]!="\r")){response=response.split("\n").join("\r\n")}if(r==max){response+="..."}fs.closeSync(fd)}break;case"dbkeys":response=JSON.stringify(db.Keys);break;case"dbget":if(db==null){response="Database not accessible.";break}if(args._.length!=1){response="Proper usage: dbget (key)"}else{response=db.Get(args._[0])}break;case"dbset":if(db==null){response="Database not accessible.";break}if(args._.length!=2){response="Proper usage: dbset (key) (value)"}else{var r=db.Put(args._[0],args._[1]);response="Key set: "+r}break;case"dbcompact":if(db==null){response="Database not accessible.";break}var r=db.Compact();response="Database compacted: "+r;break;case"httpget":if(consoleHttpRequest!=null){response="HTTP operation already in progress."}else{if(args._.length!=1){response="Proper usage: httpget (url)"}else{var options=http.parseUri(args._[0]);options.method="GET";if(options==null){response="Invalid url."}else{try{consoleHttpRequest=http.request(options,consoleHttpResponse)}catch(e){response="Invalid HTTP GET request"}consoleHttpRequest.sessionid=sessionid;if(consoleHttpRequest!=null){consoleHttpRequest.end();response="HTTPGET "+options.protocol+"//"+options.host+":"+options.port+options.path}}}}break;case"wslist":response="";for(var i in consoleWebSockets){var httprequest=consoleWebSockets[i];response+="Websocket #"+i+", "+httprequest.url+"\r\n"}if(response==""){response="no websocket sessions."}break;case"wsconnect":if(args._.length==0){response="Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc"}else{var httprequest=null;try{var options=http.parseUri(args._[0]);options.rejectUnauthorized=0;httprequest=http.request(options)}catch(e){response="Invalid HTTP websocket request"}if(httprequest!=null){httprequest.upgrade=onWebSocketUpgrade;httprequest.on("error",function(e){sendConsoleText("ERROR: "+JSON.stringify(e))});var index=1;while(consoleWebSockets[index]){index++}httprequest.sessionid=sessionid;httprequest.index=index;httprequest.url=args._[0];consoleWebSockets[index]=httprequest;response="New websocket session #"+index}}break;case"wssend":if(args._.length==0){response="Proper usage: wssend (socketnumber)\r\n";for(var i in consoleWebSockets){var httprequest=consoleWebSockets[i];response+="Websocket #"+i+", "+httprequest.url+"\r\n"}}else{var i=parseInt(args._[0]);var httprequest=consoleWebSockets[i];if(httprequest!=undefined){httprequest.s.write(args._[1]);response="ok"}else{response="Invalid web socket number"}}break;case"wsclose":if(args._.length==0){response="Proper usage: wsclose (socketnumber)"}else{var i=parseInt(args._[0]);var httprequest=consoleWebSockets[i];if(httprequest!=undefined){if(httprequest.s!=null){httprequest.s.end()}else{httprequest.end()}response="ok"}else{response="Invalid web socket number"}}break;case"tunnels":response="";for(var i in tunnels){response+="Tunnel #"+i+", "+tunnels[i].url+"\r\n"}if(response==""){response="No websocket sessions."}break;case"ls":response="";var xpath="*";if(args._.length>0){xpath=obj.path.join(args._[0],"*")}response="List of "+xpath+"\r\n";var results=fs.readdirSync(xpath);for(var i=0;i0){var r="",pstates=["NotActivated","InActivation","Activated"];for(var i in data){var x=data[i];if(r!=""){r+="\r\n"}r+=x.address+" - Intel AMT v"+x.majorVersion+"."+x.minorVersion;if(x.provisioningState<3){r+=(", "+pstates[x.provisioningState])}if(x.provisioningState==2){r+=(", "+x.openPorts.join(", "))}r+="."}}else{r="No Intel AMT found."}sendConsoleText(r)})}}else{response="Intel AMT scanner module not present."}break;case"modules":response=JSON.stringify(addedModules);break;case"getscript":if(args._.length!=1){response="Proper usage: getscript [scriptNumber]."}else{mesh.SendCommand({action:"getScript",type:args._[0]})}break;default:response='Unknown command "'+cmd+'", type "help" for list of avaialble commands.';break}}catch(e){response="Command returned an exception error: "+e;console.log(e)}if(response!=null){sendConsoleText(response,sessionid)}}function sendConsoleText(text,sessionid){if(typeof text=="object"){text=JSON.stringify(text)}mesh.SendCommand({action:"msg",type:"console",value:text,sessionid:sessionid})}function handleServerConnection(state){meshServerConnectionState=state;if(meshServerConnectionState==0){if(selfInfoUpdateTimer!=null){clearInterval(selfInfoUpdateTimer);selfInfoUpdateTimer=null}lastSelfInfo=null}else{var oldNodeId=db.Get("OldNodeId");if(oldNodeId!=null){mesh.SendCommand({action:"mc1migration",oldnodeid:oldNodeId})}mesh.SendCommand(meshCoreObj);if(SMBiosTablesRaw!=null){mesh.SendCommand({action:"smbios",value:SMBiosTablesRaw})}meInfoStr=null;sendPeriodicServerUpdate()}}var sendNetworkUpdateNagleTimer=null;function sendNetworkUpdateNagle(){if(sendNetworkUpdateNagleTimer!=null){clearTimeout(sendNetworkUpdateNagleTimer);sendNetworkUpdateNagleTimer=null}sendNetworkUpdateNagleTimer=setTimeout(sendNetworkUpdate,5000)}function sendNetworkUpdate(force){sendNetworkUpdateNagleTimer=null;var netInfo=mesh.NetInfo;netInfo.action="netinfo";var netInfoStr=JSON.stringify(netInfo);if((force==true)||(clearGatewayMac(netInfoStr)!=clearGatewayMac(lastNetworkInfo))){mesh.SendCommand(netInfo);lastNetworkInfo=netInfoStr}}function sendPeriodicServerUpdate(flags){if(meshServerConnectionState==0){return}if(!flags){flags=4294967295}if((flags&1)&&(amt!=null)){amt.getAmtInfo(function(meinfo){try{if(meinfo==null){return}var intelamt={},p=false;if(meinfo.Versions&&meinfo.Versions.AMT){intelamt.ver=meinfo.Versions.AMT;p=true}if(meinfo.ProvisioningState){intelamt.state=meinfo.ProvisioningState;p=true}if(meinfo.Flags){intelamt.flags=meinfo.Flags;p=true}if(meinfo.OsHostname){intelamt.host=meinfo.OsHostname;p=true}if(meinfo.UUID){intelamt.uuid=meinfo.UUID;p=true}if(p==true){var meInfoStr=JSON.stringify(intelamt);if(meInfoStr!=lastMeInfo){meshCoreObj.intelamt=intelamt;mesh.SendCommand(meshCoreObj);lastMeInfo=meInfoStr}}}catch(ex){}})}if(flags&2){sendNetworkUpdateNagle(false)}}obj.start=function(){mesh.AddCommandHandler(handleServerCommand);mesh.AddConnectHandler(handleServerConnection);try{var userSession=require("user-sessions");userSession.on("changed",function onUserSessionChanged(){userSession.enumerateUsers().then(function(users){var u=[],a=users.Active;for(var i=0;i ' + (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(); + }); + } + } + } +}; diff --git a/agents/meshinstall-linux.sh b/agents/meshinstall-linux.sh index d18f0797..2b256187 100644 --- a/agents/meshinstall-linux.sh +++ b/agents/meshinstall-linux.sh @@ -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 diff --git a/agents/modules_meshcmd/amt-script.js b/agents/modules_meshcmd/amt-script.js index d00ed101..b52285be 100644 --- a/agents/modules_meshcmd/amt-script.js +++ b/agents/modules_meshcmd/amt-script.js @@ -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; diff --git a/agents/modules_meshcmd_min/amt-script.min.js b/agents/modules_meshcmd_min/amt-script.min.js index 244ee297..62a1a11e 100644 --- a/agents/modules_meshcmd_min/amt-script.min.js +++ b/agents/modules_meshcmd_min/amt-script.min.js @@ -1 +1 @@ -script_functionTable1=["nop","jump","set","print","dialog","getitem","substr","indexof","split","join","length","jsonparse","jsonstr","add","substract","parseint","wsbatchenum","wsput","wscreate","wsdelete","wsexec","scriptspeed","wssubscribe","wsunsubscribe","readchar","signwithdummyca"];script_functionTable2=["encodeuri","decodeuri","passwordcheck","atob","btoa","hex2str","str2hex","random","md5","maketoarray","readshort","readshortx","readint","readsint","readintx","shorttostr","shorttostrx","inttostr","inttostrx"];script_functionTableX2=[encodeURI,decodeURI,passwordcheck,atob,btoa,hex2rstr,rstr2hex,random,rstr_md5,MakeToArray,ReadShort,ReadShortX,ReadInt,ReadSInt,ReadIntX,ShortToStr,ShortToStrX,IntToStr,IntToStrX];function MakeToArray(a){if(!a||a==null||typeof a=="object"){return a}return[a]}function ReadShort(b,a){return(b[a]<<8)+b[a+1]}function ReadShortX(b,a){return(b[a+1]<<8)+b[a]}function ReadInt(b,a){return(b[a]*16777216)+(b[a+1]<<16)+(b[a+2]<<8)+b[a+3]}function ReadSInt(b,a){return(b[a]<<24)+(b[a+1]<<16)+(b[a+2]<<8)+b[a+3]}function ReadIntX(b,a){return(b[a+3]*16777216)+(b[a+2]<<16)+(b[a+1]<<8)+b[a]}function ShortToStr(a){return String.fromCharCode((a>>8)&255,a&255)}function ShortToStrX(a){return String.fromCharCode(a&255,(a>>8)&255)}function IntToStr(a){return String.fromCharCode((a>>24)&255,(a>>16)&255,(a>>8)&255,a&255)}function IntToStrX(a){return String.fromCharCode(a&255,(a>>8)&255,(a>>16)&255,(a>>24)&255)}function btoa(a){return Buffer.from(a).toString("base64")}function atob(b){var c=null;try{c=Buffer.from(b,"base64").toString()}catch(a){console.log(a)}return c}function passwordcheck(g){if(g.length<8){return false}var h=0,d=0,f=0,e=0;for(var b in g){var a=g.charCodeAt(b);if((a>64)&&(a<91)){h=1}else{if((a>96)&&(a<123)){d=1}else{if((a>47)&&(a<58)){f=1}else{e=1}}}}return((h+d+f+e)==4)}function hex2rstr(a){Buffer.from(a,"hex").toString()}function rstr2hex(a){Buffer.from(a).toString("hex")}function random(){return Math.floor(Math.random()*max)}function rstr_md5(a){return hex2rstr(hex_md5(a))}function getItem(b,c,d){for(var a in b){if(b[a][c]==d){return b[a]}}return null}var httpErrorTable={200:"OK",401:"Authentication Error",408:"Timeout Error",601:"WSMAN Parsing Error",602:"Unable to parse HTTP response header",603:"Unexpected HTTP enum response",604:"Unexpected HTTP pull response",998:"Invalid TLS certificate"};module.exports.setup=function(a,c){var b={startvars:c,onCompleted:null};if(a.length<6){console.error("Invalid script length");return null}if(ReadInt(a,0)!=612182341){console.error("Invalid binary script");return null}if(ReadShort(a,4)>1){console.error("Unsupported script version");return null}b.script=a.slice(6);b.reset=function(d){b.stop();b.ip=0;b.variables=c;b.state=1};b.start=function(d){b.stop();if(d==null){b.stepspeed=10}else{b.stepspeed=d}if(b.stepspeed>0){b.timer=setInterval(function(){b.step()},b.stepspeed)}};b.stop=function(){if(b.timer!=null){clearInterval(b.timer)}b.timer=null;b.stepspeed=0};b.getVar=function(d){if(d==undefined){return undefined}return b.getVarEx(d.split("."),b.variables)};b.getVarEx=function(f,g){try{if(f==undefined){return undefined}if(f.length==0){return g}return b.getVarEx(f.slice(1),g[f[0]])}catch(d){return null}};b.setVar=function(d,e){b.setVarEx(d.split("."),b.variables,e)};b.setVarEx=function(d,f,e){if(d.length==1){f[d[0]]=e}else{b.setVarEx(d.slice(1),f[d[0]],e)}};b.step=function(){if(b.state!=1){return}if(b.ip1){var r=l.split("{").pop().split("}").shift();l=l.replace("{"+r+"}",b.getVar(r))}if(k==1){b.variables["__"+p]=decodeURI(l);l="__"+p}h.push(l)}if(k==2||k==3){b.variables["__"+p]=ReadSInt(l,0);h.push("__"+p)}g+=(2+f)}b.ip+=n;var j=[];for(var p=0;p<10;p++){j.push(b.getVar(h[p]))}var q;try{if(m<10000){switch(m){case 0:break;case 1:if(j[2]){if((j[2]=="<"&&j[1]="&&j[1]>=j[3])||(j[2]==">"&&j[1]>j[3])){b.ip=j[0]}}else{b.ip=j[0]}break;case 2:if(h[1]==undefined){delete b.variables[h[0]]}else{b.setVar(h[0],j[1])}break;case 3:var s=b.toString(j[0]);if(s.indexOf("INFO: ")==0){s=s.substring(6)}if(s.indexOf("SUCCESS: ")==0){s=s.substring(9)}if(b.onConsole){b.onConsole(s,b)}else{console.log(s)}break;case 4:b.state=2;b.dialog=true;setDialogMode(11,j[0],j[2],b.xxStepDialogOk,j[1],b);break;case 5:for(var p in j[1]){if(j[1][p][j[2]]==j[3]){q=p}}break;case 6:q=j[1].substr(j[2],j[3]);break;case 7:q=j[1].indexOf(j[2]);break;case 8:q=j[1].split(j[2]);break;case 9:q=j[1].join(j[2]);break;case 10:if(j[1]==null){q=0}else{q=j[1].length}break;case 11:q=JSON.parse(j[1]);break;case 12:q=JSON.stringify(j[1]);break;case 13:q=(j[1]+j[2]);break;case 14:q=(j[1]-j[2]);break;case 15:q=parseInt(j[1]);break;case 16:b.state=2;b.amtstack.BatchEnum(j[0],j[1],b.xxWsmanReturn,b);break;case 17:b.state=2;b.amtstack.Put(j[0],j[1],b.xxWsmanReturn,b);break;case 18:b.state=2;b.amtstack.Create(j[0],j[1],b.xxWsmanReturn,b);break;case 19:b.state=2;b.amtstack.Delete(j[0],j[1],b.xxWsmanReturn,b);break;case 20:b.state=2;b.amtstack.Exec(j[0],j[1],j[2],b.xxWsmanReturn,b,0,j[3]);break;case 21:b.stepspeed=j[0];if(b.timer!=null){clearInterval(b.timer);b.timer=setInterval(function(){b.step()},b.stepspeed)}break;case 22:b.state=2;b.amtstack.Subscribe(j[0],j[1],j[2],b.xxWsmanReturn,b,0,j[3],j[4],j[5],j[6]);break;case 23:b.state=2;b.amtstack.UnSubscribe(j[0],b.xxWsmanReturn,b,0,j[1]);break;case 24:console.log(j[1],j[2],j[1].charCodeAt(j[2]));q=j[1].charCodeAt(j[2]);break;case 25:break;default:b.state=9;console.error("Script Error, unknown command: "+m)}}else{if(m<20000){q=script_functionTableX2[m-10000](j[1],j[2],j[3],j[4],j[5],j[6])}else{}}if(q!=undefined){b.setVar(h[0],q)}}catch(o){if(typeof o=="object"){o=o.message}b.setVar("_exception",o)}}if(b.state==1&&b.ip>=b.script.length){b.state=0;b.stop();if(b.onCompleted){b.onCompleted()}}if(b.onStep){b.onStep(b)}return b};b.xxStepDialogOk=function(d){b.variables.DialogSelect=d;b.state=1;b.dialog=false;if(b.onStep){b.onStep(b)}};b.xxWsmanReturn=function(f,d,e,g){b.setVar(d,e);b.setVar("wsman_result",g);b.setVar("wsman_result_str",((httpErrorTable[g])?(httpErrorTable[g]):("Error #"+g)));b.state=1;if(b.onStep){b.onStep(b)}};b.toString=function(d){if(typeof d=="object"){return JSON.stringify(d)}return d};b.reset();return b};module.exports.compile=function(o,l){var n="",q=o.split("\n"),h={},k=[],s=[];for(var d in q){var p=q[d];if(p.startsWith("##SWAP ")){var u=p.split(" ");if(u.length==3){s[u[1]]=u[2]}}if(p[0]=="#"||p.length==0){continue}for(var u in s){p=p.split(u).join(s[u])}var f=p.match(/"[^"]*"|[^\s"]+/g);if(f.length==0){continue}if(p[0]==":"){h[f[0].toUpperCase()]=n.length;continue}var c=script_functionTable1.indexOf(f[0].toLowerCase());if(c==-1){c=script_functionTable2.indexOf(f[0].toLowerCase());if(c>=0){c+=10000}}if(c==-1){if(l){l("Unabled to compile, unknown command: "+f[0])}return""}var b=ShortToStr(f.length-1);for(var e in f){if(e==0){continue}if(f[e][0]==":"){k.push([f[e],n.length+b.length+7]);b+=ShortToStr(5)+String.fromCharCode(3)+IntToStr(4294967295)}else{var a=parseInt(f[e]);if(a==f[e]){b+=ShortToStr(5)+String.fromCharCode(2)+IntToStr(a)}else{if(f[e][0]=='"'&&f[e][f[e].length-1]=='"'){b+=ShortToStr(f[e].length-1)+String.fromCharCode(1)+f[e].substring(1,f[e].length-1)}else{b+=ShortToStr(f[e].length+1)+String.fromCharCode(0)+f[e]}}}}b=ShortToStr(c)+ShortToStr(b.length+4)+b;n+=b}for(d in k){var g=k[d][0].toUpperCase(),m=k[d][1],t=h[g];if(t==undefined){if(l){l("Unabled to compile, unknown label: "+g)}return""}n=n.substr(0,m)+IntToStr(t)+n.substr(m+4)}return IntToStr(612182341)+ShortToStr(1)+n};module.exports.decompile=function(g,q){var t="",s=6,m=0,n={};if(q>=0){s=q}else{if(g.length<6){return"# Invalid script length"}var p=ReadInt(g,0);var w=ReadShort(g,4);if(p!=612182341){return"# Invalid binary script: "+p}if(w!=1){return"# Invalid script version"}}while(s=0)){t+=":label"+(s-6)+"\n"}for(var k=0;k=10000)&&(h<10000)){t+=script_functionTable2[h-10000]+d+"\n"}}s+=j;if(q>=0){return t}}var u=t.split("\n");t="";for(var k in u){var o=u[k];if(o[0]!=":"){t+=o+"\n"}else{if(n[o]){t+=o+"\n"}}}return t}; \ No newline at end of file +script_functionTable1=["nop","jump","set","print","dialog","getitem","substr","indexof","split","join","length","jsonparse","jsonstr","add","substract","parseint","wsbatchenum","wsput","wscreate","wsdelete","wsexec","scriptspeed","wssubscribe","wsunsubscribe","readchar","signwithdummyca"];script_functionTable2=["encodeuri","decodeuri","passwordcheck","atob","btoa","hex2str","str2hex","random","md5","maketoarray","readshort","readshortx","readint","readsint","readintx","shorttostr","shorttostrx","inttostr","inttostrx"];script_functionTableX2=[encodeURI,decodeURI,passwordcheck,atob,btoa,hex2rstr,rstr2hex,random,rstr_md5,MakeToArray,ReadShort,ReadShortX,ReadInt,ReadSInt,ReadIntX,ShortToStr,ShortToStrX,IntToStr,IntToStrX];function MakeToArray(a){if(!a||a==null||typeof a=="object"){return a}return[a]}function ReadShort(b,a){return(b[a]<<8)+b[a+1]}function ReadShortX(b,a){return(b[a+1]<<8)+b[a]}function ReadInt(b,a){return(b[a]*16777216)+(b[a+1]<<16)+(b[a+2]<<8)+b[a+3]}function ReadSInt(b,a){return(b[a]<<24)+(b[a+1]<<16)+(b[a+2]<<8)+b[a+3]}function ReadIntX(b,a){return(b[a+3]*16777216)+(b[a+2]<<16)+(b[a+1]<<8)+b[a]}function ShortToStr(a){return String.fromCharCode((a>>8)&255,a&255)}function ShortToStrX(a){return String.fromCharCode(a&255,(a>>8)&255)}function IntToStr(a){return String.fromCharCode((a>>24)&255,(a>>16)&255,(a>>8)&255,a&255)}function IntToStrX(a){return String.fromCharCode(a&255,(a>>8)&255,(a>>16)&255,(a>>24)&255)}function btoa(a){return Buffer.from(a).toString("base64")}function atob(b){var c=null;try{c=Buffer.from(b,"base64").toString()}catch(a){console.log(a)}return c}function passwordcheck(g){if(g.length<8){return false}var h=0,d=0,f=0,e=0;for(var b in g){var a=g.charCodeAt(b);if((a>64)&&(a<91)){h=1}else{if((a>96)&&(a<123)){d=1}else{if((a>47)&&(a<58)){f=1}else{e=1}}}}return((h+d+f+e)==4)}function hex2rstr(a){Buffer.from(a,"hex").toString()}function rstr2hex(a){Buffer.from(a).toString("hex")}function random(){return Math.floor(Math.random()*max)}function rstr_md5(a){return hex2rstr(hex_md5(a))}function getItem(b,c,d){for(var a in b){if(b[a][c]==d){return b[a]}}return null}var httpErrorTable={200:"OK",401:"Authentication Error",408:"Timeout Error",601:"WSMAN Parsing Error",602:"Unable to parse HTTP response header",603:"Unexpected HTTP enum response",604:"Unexpected HTTP pull response",998:"Invalid TLS certificate"};module.exports.setup=function(a,c){var b={startvars:c,onCompleted:null};if(a.length<6){console.error("Invalid script length");return null}if(ReadInt(a,0)!=612182341){console.error("Invalid binary script");return null}if(ReadShort(a,4)>1){console.error("Unsupported script version");return null}b.script=a.slice(6);b.reset=function(d){b.stop();b.ip=0;b.variables=c;b.state=1};b.start=function(d){b.stop();if(d==null){b.stepspeed=10}else{b.stepspeed=d}if(b.stepspeed>0){b.timer=setInterval(function(){b.step()},b.stepspeed)}};b.stop=function(){if(b.timer!=null){clearInterval(b.timer)}b.timer=null;b.stepspeed=0};b.getVar=function(d){if(d==undefined){return undefined}return b.getVarEx(d.split("."),b.variables)};b.getVarEx=function(f,g){try{if(f==undefined){return undefined}if(f.length==0){return g}return b.getVarEx(f.slice(1),g[f[0]])}catch(d){return null}};b.setVar=function(d,e){b.setVarEx(d.split("."),b.variables,e)};b.setVarEx=function(d,f,e){if(d.length==1){f[d[0]]=e}else{b.setVarEx(d.slice(1),f[d[0]],e)}};b.step=function(){if(b.state!=1){return}if(b.ip1){var r=l.split("{").pop().split("}").shift();l=l.replace("{"+r+"}",b.getVar(r))}}if(k==1){b.variables["__"+p]=decodeURI(l);l="__"+p}h.push(l)}if(k==2||k==3){b.variables["__"+p]=ReadSInt(l,0);h.push("__"+p)}g+=(2+f)}b.ip+=n;var j=[];for(var p=0;p<10;p++){j.push(b.getVar(h[p]))}var q;try{if(m<10000){switch(m){case 0:break;case 1:if(j[2]){if((j[2]=="<"&&j[1]="&&j[1]>=j[3])||(j[2]==">"&&j[1]>j[3])){b.ip=j[0]}}else{b.ip=j[0]}break;case 2:if(h[1]==undefined){delete b.variables[h[0]]}else{b.setVar(h[0],j[1])}break;case 3:var s=b.toString(j[0]);if(s.indexOf("INFO: ")==0){s=s.substring(6)}if(s.indexOf("SUCCESS: ")==0){s=s.substring(9)}if(b.onConsole){b.onConsole(s,b)}else{console.log(s)}break;case 4:b.state=2;b.dialog=true;setDialogMode(11,j[0],j[2],b.xxStepDialogOk,j[1],b);break;case 5:for(var p in j[1]){if(j[1][p][j[2]]==j[3]){q=p}}break;case 6:q=j[1].substr(j[2],j[3]);break;case 7:q=j[1].indexOf(j[2]);break;case 8:q=j[1].split(j[2]);break;case 9:q=j[1].join(j[2]);break;case 10:if(j[1]==null){q=0}else{q=j[1].length}break;case 11:q=JSON.parse(j[1]);break;case 12:q=JSON.stringify(j[1]);break;case 13:q=(j[1]+j[2]);break;case 14:q=(j[1]-j[2]);break;case 15:q=parseInt(j[1]);break;case 16:b.state=2;b.amtstack.BatchEnum(j[0],j[1],b.xxWsmanReturn,b);break;case 17:b.state=2;b.amtstack.Put(j[0],j[1],b.xxWsmanReturn,b);break;case 18:b.state=2;b.amtstack.Create(j[0],j[1],b.xxWsmanReturn,b);break;case 19:b.state=2;b.amtstack.Delete(j[0],j[1],b.xxWsmanReturn,b);break;case 20:b.state=2;b.amtstack.Exec(j[0],j[1],j[2],b.xxWsmanReturn,b,0,j[3]);break;case 21:b.stepspeed=j[0];if(b.timer!=null){clearInterval(b.timer);b.timer=setInterval(function(){b.step()},b.stepspeed)}break;case 22:b.state=2;b.amtstack.Subscribe(j[0],j[1],j[2],b.xxWsmanReturn,b,0,j[3],j[4],j[5],j[6]);break;case 23:b.state=2;b.amtstack.UnSubscribe(j[0],b.xxWsmanReturn,b,0,j[1]);break;case 24:console.log(j[1],j[2],j[1].charCodeAt(j[2]));q=j[1].charCodeAt(j[2]);break;case 25:break;default:b.state=9;console.error("Script Error, unknown command: "+m)}}else{if(m<20000){q=script_functionTableX2[m-10000](j[1],j[2],j[3],j[4],j[5],j[6])}else{}}if(q!=undefined){b.setVar(h[0],q)}}catch(o){if(typeof o=="object"){o=o.message}b.setVar("_exception",o)}}if(b.state==1&&b.ip>=b.script.length){b.state=0;b.stop();if(b.onCompleted){b.onCompleted()}}if(b.onStep){b.onStep(b)}return b};b.xxStepDialogOk=function(d){b.variables.DialogSelect=d;b.state=1;b.dialog=false;if(b.onStep){b.onStep(b)}};b.xxWsmanReturn=function(f,d,e,g){b.setVar(d,e);b.setVar("wsman_result",g);b.setVar("wsman_result_str",((httpErrorTable[g])?(httpErrorTable[g]):("Error #"+g)));b.state=1;if(b.onStep){b.onStep(b)}};b.toString=function(d){if(typeof d=="object"){return JSON.stringify(d)}return d};b.reset();return b};module.exports.compile=function(o,l){var n="",q=o.split("\n"),h={},k=[],s=[];for(var d in q){var p=q[d];if(p.startsWith("##SWAP ")){var u=p.split(" ");if(u.length==3){s[u[1]]=u[2]}}if(p[0]=="#"||p.length==0){continue}for(var u in s){p=p.split(u).join(s[u])}var f=p.match(/"[^"]*"|[^\s"]+/g);if(f.length==0){continue}if(p[0]==":"){h[f[0].toUpperCase()]=n.length;continue}var c=script_functionTable1.indexOf(f[0].toLowerCase());if(c==-1){c=script_functionTable2.indexOf(f[0].toLowerCase());if(c>=0){c+=10000}}if(c==-1){if(l){l("Unabled to compile, unknown command: "+f[0])}return""}var b=ShortToStr(f.length-1);for(var e in f){if(e==0){continue}if(f[e][0]==":"){k.push([f[e],n.length+b.length+7]);b+=ShortToStr(5)+String.fromCharCode(3)+IntToStr(4294967295)}else{var a=parseInt(f[e]);if(a==f[e]){b+=ShortToStr(5)+String.fromCharCode(2)+IntToStr(a)}else{if(f[e][0]=='"'&&f[e][f[e].length-1]=='"'){b+=ShortToStr(f[e].length-1)+String.fromCharCode(1)+f[e].substring(1,f[e].length-1)}else{b+=ShortToStr(f[e].length+1)+String.fromCharCode(0)+f[e]}}}}b=ShortToStr(c)+ShortToStr(b.length+4)+b;n+=b}for(d in k){var g=k[d][0].toUpperCase(),m=k[d][1],t=h[g];if(t==undefined){if(l){l("Unabled to compile, unknown label: "+g)}return""}n=n.substr(0,m)+IntToStr(t)+n.substr(m+4)}return IntToStr(612182341)+ShortToStr(1)+n};module.exports.decompile=function(g,q){var t="",s=6,m=0,n={};if(q>=0){s=q}else{if(g.length<6){return"# Invalid script length"}var p=ReadInt(g,0);var w=ReadShort(g,4);if(p!=612182341){return"# Invalid binary script: "+p}if(w!=1){return"# Invalid script version"}}while(s=0)){t+=":label"+(s-6)+"\n"}for(var k=0;k=10000)&&(h<10000)){t+=script_functionTable2[h-10000]+d+"\n"}}s+=j;if(q>=0){return t}}var u=t.split("\n");t="";for(var k in u){var o=u[k];if(o[0]!=":"){t+=o+"\n"}else{if(n[o]){t+=o+"\n"}}}return t}; \ No newline at end of file diff --git a/agents/modules_meshcore/win-console.js b/agents/modules_meshcore/win-console.js index 89e3c275..2a5a18f0 100644 --- a/agents/modules_meshcore/win-console.js +++ b/agents/modules_meshcore/win-console.js @@ -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() diff --git a/agents/modules_meshcore_min/win-console.min.js b/agents/modules_meshcore_min/win-console.min.js index d013e2a0..e2197744 100644 --- a/agents/modules_meshcore_min/win-console.min.js +++ b/agents/modules_meshcore_min/win-console.min.js @@ -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(); \ No newline at end of file +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(); \ No newline at end of file diff --git a/common.js b/common.js index 2db7f60b..bac385b6 100644 --- a/common.js +++ b/common.js @@ -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': '
', '\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; }; diff --git a/db.js b/db.js index 61428627..ae81441e 100644 --- a/db.js +++ b/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)); } diff --git a/meshagent.js b/meshagent.js index 2a2646d1..8bd468b0 100644 --- a/meshagent.js +++ b/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); diff --git a/meshcentral.js b/meshcentral.js index 7584a7bc..016bf177 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -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 diff --git a/meshrelay.js b/meshrelay.js index 2a4d8845..562313bf 100644 --- a/meshrelay.js +++ b/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; } diff --git a/meshuser.js b/meshuser.js index d434ba8c..dcf72728 100644 --- a/meshuser.js +++ b/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; } diff --git a/package.json b/package.json index 95fe0a6e..c47c5b64 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/public/scripts/agent-redir-ws-0.1.0.js b/public/scripts/agent-redir-ws-0.1.0.js index 26ca551f..e1088ab8 100644 --- a/public/scripts/agent-redir-ws-0.1.0.js +++ b/public/scripts/agent-redir-ws-0.1.0.js @@ -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); } diff --git a/public/scripts/amt-terminal-0.0.2.js b/public/scripts/amt-terminal-0.0.2.js index b65f7e37..0f71cd55 100644 --- a/public/scripts/amt-terminal-0.0.2.js +++ b/public/scripts/amt-terminal-0.0.2.js @@ -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 diff --git a/public/styles/style-old.css b/public/styles/style-old.css new file mode 100644 index 00000000..d236ca83 --- /dev/null +++ b/public/styles/style-old.css @@ -0,0 +1,1600 @@ +body { + margin: 0; + padding: 0; + border: 0; + color: black; + font-size: 13px; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; + background-color: #d3d9d6; + overflow-y: hidden; +} + +#container { + background-color: #fff; + width: 960px; + min-width: 960px; + max-height: 100vh; + margin: 0 auto; + border-top: 0; + border-right: 1px solid #b7b7b7; + border-bottom: 0; + border-left: 1px solid #b7b7b7; + padding: 0; +} + + .fullscreen #container { + width: 100%; + min-width: 700px; + min-height: 0px; + border-right: 0px none #b7b7b7; + border-left: 0px none #b7b7b7; + } + + .fulldesk #container { + width: 100%; + min-width: 700px; + min-height: 0px; + border-right: 0px none #b7b7b7; + border-left: 0px none #b7b7b7; + position: unset; + } + +#masthead { + width: auto; + margin: 0; + padding: 0; + overflow: hidden; + text-align: right; + background-color: #036; + background-image: url(../logo.png); + background-position-x: 0px; + background-position-y: 0px; + background-attachment: initial; + background-repeat: no-repeat; + width: 960px; + height: 66px; +} + + .fullscreen #masthead { + width: 100%; + } + + .fulldesk #masthead { + display: none; + } + .fulldesk #mastheadx { + display: none; + } + .fulldesk #p11deviceNameHeader { + display: none; + } + +#masthead .title { + float: left; + height: 66px; + color: #c8c8c8; + padding-left: 20px; + padding-top: 8px; + font-size: 46px; + font-family: Arial,Helvetica,sans-serif; + font-weight: bold; +} + +#masthead .title2 { + float: left; + height: 66px; + color: #c8c8c8; + padding-left: 5px; + padding-top: 14px; + font-size: 14px; + font-family: Arial,Helvetica,sans-serif; + 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; + position: absolute; + z-index: 1000; + background: #113962; + background: linear-gradient(to bottom, #104893 0%,#113962 100%); + color: white; +} + .fullscreen #page_leftbar { + display: block; + } + .arg_hide #page_leftbar { + display: none; + } + .fulldesk #page_leftbar { + display: none; + } + +#topbar { + /* height: 24px; */ + position: relative; +} + + .fulldesk #topbar { + display: none; + } + +.topbar_td { + width: 100px; + height: 24px; + cursor: pointer; +} +.topbar_td_end { + text-align: right; + height: 24px; +} + +#toggle { + cursor: pointer; + color: white; + position: absolute; + top: 3px; + right: 6px +} + +#MainMenuSpan, #MainSubMenu, #MeshSubMenu, #UserSubMenu, #ServerSubMenu, #UserDummyMenu { + width: 100%; + height: 22px +} + +#MainMenuSpan { + display: table; +} + .fullscreen #MainMenuSpan { + display: none; + } + .fulldesk #MainMenuSpan { + display: none; + } + +#column_l { + position: relative; + float: left; + width: 930px; + margin: 0; + padding: 0 15px; + background-color: #fff; + /*max-height: calc(100vh - 111px);*/ + min-width: unset; +} +.room4submenu { + max-height: calc(100vh - 159px) !important; +} + + .fullscreen #column_l { + height: calc(100vh - 135px); + width: calc(100% - 30px); + overflow-y: auto; + } + + .fulldesk #column_l { + width: 100%; + height: unset; + margin-left: unset; + overflow-y: unset; + padding: 0; + max-height: unset; + } + .fulldesk #column_l_bottomgap { + display: none; + } + +#centralTable { + width: 100%; +} + +#welcomeimage { + text-align: right; +} + +@media (max-width: 800px) { + .fullscreen #welcomeimage { + display: none; + } +} + +#welcomeimage img { + height: 310px; + width: 359px; +} + +#logincell { + text-align: center; +} + +#loginpanel, #createpanel, #resetpanel, #tokenpanel, #resettokenpanel, #resetpasswordpanel, #resetpasswordpanel { + display: inline-block; + margin: 0; + background-color: #979797; + border-radius: 16px; + width: 300px; + padding: 16px; + text-align: center; +} + +#passwordPolicyCallout, #rpasswordPolicyCallout { + left: -10px; + width: 100px; + position: absolute; + background-color: #FFC; + border-radius: 5px; + padding: 5px; + box-shadow: 0px 0px 15px #666; + font-size: 10px; +} + +#passWarning { + padding-top:6px; +} + +#footer { + clear: both; + overflow: auto; + width: 100%; + text-align: center; + background-color: #113962; + padding-top: 5px; + padding-bottom: 5px; +} + .fulldesk #footer { + display: none; + } + +/* Support for footer made with table */ +#footer table { + width:100%; + border-spacing: 10px; + border-collapse: separate; +} +#footer td:first-child { + text-align: left; + color:white; +} +#footer td { + padding: 0px; + text-align: right; + color: white; +} + +/* Support for new footer made with div (like masterhead) */ +.footer1 { + text-align: left; + float: left; + padding: 10px; + color: white; +} +.footer2 { + padding: 10px; + text-align: right; + color: white; +} + +#masthead img { + float: left; +} + +#masthead p { + font-size: 11px; + color: #fff; + margin: 10px 10px 0; +} + +#footer a { + color: #fff; + text-decoration: underline; +} + + #footer a:hover { + color: #fff; + text-decoration: none; + } + +#dialog { + z-index: 1000; + background-color: #EEE; + box-shadow: 0px 0px 15px #666; + font-family: Arial,Helvetica,sans-serif; + border-radius: 5px; + position: fixed; + top: 180px; + left: calc((100% / 2) - 200px); + width: 400px; +} + +#dialogHeader { + width: 100%; + background-color: #003366; + color: #FFF; + border-radius: 5px 5px 0 0; +} + +#dialogBody { + margin-right: 16px; + margin-left: 8px; +} + +.dialogText { + width: 100%; + max-height: 260px; + overflow-x: hidden; + overflow-y: auto; + line-height: 160% +} +.dialogTextLog { + font-size:10px +} + +#dialog1 { + margin: auto; + text-align: center; + margin: 3px; +} + +#id_dialogMessage { + padding:10px; +} + +#dialog2, #dialog3 { + margin: auto; + margin: 3px; +} + +#idx_dlgButtonBar { + padding: 10px; + margin-bottom: 20px; +} + +#idx_dlgCancelButton { + float: right; + width: 80px; + margin-left: 5px; +} + +#idx_dlgOkButton { + float: right; + width: 80px; +} + +#idx_dlgDeleteButton { + width: 80px; +} + +#ua_fileaccessquota { + width: 80px; + text-align: right +} + +#broadcastMessage { + width: 370px; + height: 100px; + resize: none; +} + +#idx_deskFullBtn2 { + float: left; + font-size: large; + cursor: pointer; + display: none; +} + .fulldesk #idx_deskFullBtn2 { + display: block; + } + .fulldesk #deskFullBtn { + display: none; + } + +#p0message { + margin: 50px; + text-align: center; +} + +#devListToolbarViewIcons { + float:right; +} + +#devListToolbarSpan { + width: 100%; + height: 24px; + background-color: #d3d9d6; + vertical-align: middle; + border-spacing: 0 +} + +#SearchInput { + width:120px; +} + +#devListToolbarView, #devListToolbarSort, #devListToolbarSize { + float: right; +} + +#refreshmap { + margin-left:5px; +} + +/* Example if is relplaced with

then image can be defined in css +#NoMeshesPanel { + background: url(../images/info.png) no-repeat 23px 20px; + height: 48px; + width: 47px; + width: 100%; + border: none; + margin: auto; + padding: 20px; +} + #NoMeshesPanel p { + display: inline-block; + vertical-align: middle; + margin-left: 60px; + } */ + + #NoMeshesPanel a { + cursor: pointer; + } + #NoMeshesPanel table { + width: 100%; + padding: 20px + } + NoMeshesPanel img { + height: 48px; + width: 47px; + } + +#xdevices { + max-height: calc(100vh - 239px); + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; +} + +#xdevicesmap { + height: calc(100vh - 239px); + width: 100%; + overflow: hidden; + position: relative; +} +#xmapSearchResultsDlg { + position: absolute; + max-height: 280px; + left: 5px; + top: 5px; + max-width: 250px; + z-index: 1000; + background-color: #EEE; + box-shadow: 0px 0px 15px #666; +} +#xmapSearchResultsBck { + width: 100%; + background-color: #003366; + color: #FFF; + border-radius: 5px 5px 0 0; +} + +#xmapSearchClose { + float: right; + padding: 5px; + cursor: pointer; +} + +.xmapItem { + overflow-y: auto; + width: 100%; + max-height: 240px +} +.xmapItemSel1 { + cursor: pointer; + padding: 5px; + background-color: #F5F5F5; +} +.xmapItemSel1 { + cursor: pointer; + padding: 5px; + background-color: #EBEBEB; +} + +#xmap-info-window { + text-shadow: 0px 0px 15px #FFF +} + +#p2 a, #p6 a, #p10 a { + cursor: pointer; +} + +#p2AccountImage { + width: 150px; + height: 103px; + margin-bottom: 10px; + margin-right: 20px; + float:right; +} + +.p2AccountActions { + width: 15px; + display: inline-block; +} +.p2AccountActions span { + color: green; + font-size: 10px; +} + +.newMeshBtn { + background: url(../images/icon-addnew.png) no-repeat 0px 0px; + height: 12px; + width: 12px; + cursor: pointer; + border: none; + padding-left: 15px; +} + +#p2noMeshFound, #p2ServerActionsBackup, #p2ServerActionsRestore, #p2ServerActionsVersion, #p2ServerActionsErrors, #serverStats { + margin-left:40px; +} + +.pTable { + width: 100%; + height: 24px; + background-color: #d3d9d6; + margin-bottom: 4px; + vertical-align: middle; + border-spacing: 0; + +} + +#p3users { + max-height: calc(100vh - 243px); + overflow-y: auto; +} +.p3usersTable { + width: 100%; + border-spacing: 0; + padding: 0; +} +.p3usersTable th { + color: gray; +} + +#p3events { + height: calc(100vh - 243px); + overflow-y: scroll +} + +.p3eventsTable { + width: 100%; + border-spacing: 0; + padding: 0; +} +.p3eventsTable { + width: 100%; + border-spacing: 0; + padding: 0; +} + +#p4name, #p4email, #p4pass1, #p4pass2 { + width: 230px; +} + +#p5filehead { + width: 100%; + background-color: #d3d9d6; + text-align: left; + padding: 4px; +} + +#p5filesubhead { + background-color: #E4E9E7; + height: 28px; +} + +#p5rightOfButtons { + float: right; + margin-top: 3px; +} + +#p5filetable { + width: 100%; + height: calc(100vh - 294px); + overflow: auto; + -webkit-user-select: none; + position: relative; +} + +#p5PublicShare { + display: none; + width: 100%; + overflow: auto; + -webkit-user-select: none; + background-color: lightsteelblue; +} + +#bigok { + width: 256px; + overflow: hidden; + position: absolute; + left: 337px; + top: 20px; + text-align: center; + font-size: 1600%; + color: #AAAAAA; +} + +#bigfail { + width: 256px; + overflow: hidden; + position: absolute; + left: 337px; + top: 20px; + text-align: center; + font-size: 1600%; + color: #AAAAAA; +} + +.chartViewCanvas { +<<<<<<< HEAD + width: 80px; +======= + width: 60px; +>>>>>>> b375b9fdb2584c2cd6311834bd6c540545d075b4 + display: inline-block; +} + +.chartViewText { + width: 160px; + display: inline-block; +} + +#serverCpuChart, #serverMemoryChart { + width: 60px; + height: 60px; +} + +#p10BackButton, #p11BackButton { + float:left +} + +#p10html2 table { + color: black; + background-color: #EEE; + border-color: #AAA; + border-width: 1px; + border-style: solid; + border-collapse: collapse; + width: 100%; +} + #p10html2 thead { + background-color:#AAAAAA; + font-weight:bold; + } + #p10html2 thead tr { + background-color:#AAAAAA; + font-weight:bold; + } + #p10html2 thead img { + float: right; + cursor: pointer; + padding: 3px; + } + #p10html2 .altBack { + background-color: #DDD; + } + +.pwState { + display: table-cell; + height: 16px; +} +.pwsYellow { background-color: yellow; } +.pwsTransparent { background-color: #00000000; } +.pwsBlack { background-color: black; } +.pwsBlue { background-color: blue; } +.pwsBlue2 { background-color: blue; } +.pwsLightblue { background-color: lightblue; } +.pwsBlueviolet { background-color: blueviolet; } +.pwsDarkgreen { background-color: darkgreen; } +.pwsLightseagreen { background-color: lightseagreen; } +.pwsLightseagreen2 { background-color: lightseagreen; } + +.p10html3right { + float: right; + font-size: x-small; +} + +.p10html3left { + font-size: x-small; +} + +#MainComputerImage { + border-width: 0px; + height: 200px; + width: 200px; +} + +#MainComputerState { + font-size: 12px; + font-weight: bold; + width: 100%; + text-align: center; +} + +#d2groupop { + float: right; + width: 250px; +} + +#p12warning, #p12warning2, #p14warning, #p14warning2 { + max-width: 100%; + display:none; + cursor: pointer; + margin-bottom: 5px; +} + +#MainMeshImage { + border-width: 0px; + height: 200px; + width: 200px; + float: right; +} + +#DeskTools { + position: absolute; + width: 400px; + height: 100%; + background-color: gray; + top: 0; + right: 0; + border-left: 2px solid lightgray; + display: none; +} +#DeskToolsRefreshButton { + float: right; + padding: 3px; + cursor: pointer; +} + +a { + color: #036; + text-decoration: underline; +} + +.i1 { + background: url(../images/icons50.png) 0px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.i2 { + background: url(../images/icons50.png) -50px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.i3 { + background: url(../images/icons50.png) -100px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.i4 { + background: url(../images/icons50.png) -150px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.i5 { + background: url(../images/icons50.png) -200px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.i6 { + background: url(../images/icons50.png) -250px 0px; + height: 50px; + width: 50px; + cursor: pointer; + border: none; +} + +.j1 { + background: url(../images/icons16.png) 0px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.j2 { + background: url(../images/icons16.png) -16px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.j3 { + background: url(../images/icons16.png) -32px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.j4 { + background: url(../images/icons16.png) -48px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.j5 { + background: url(../images/icons16.png) -64px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.j6 { + background: url(../images/icons16.png) -80px 0px; + height: 16px; + width: 16px; + cursor: pointer; + border: none; +} + +.lbbutton { + width:74px; + height:74px; + border-radius:5px; + background-color:white; + margin-left:8px; + margin-top:8px; + position:relative; + cursor:pointer; + opacity:0.5; +} + +.lbbutton:hover { + opacity:1; +} + +.lbbuttonsel { + opacity:0.9; +} + +.lbbuttonsel2 { + width:82px; + border-radius:5px 0px 0px 5px; + opacity:1; +} + +.lb1 { + background: url(../images/leftbar-62.jpg) -0px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.lb2 { + background: url(../images/leftbar-62.jpg) -75px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.lb3 { + background: url(../images/leftbar-62.jpg) -150px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.lb4 { + background: url(../images/leftbar-62.jpg) -225px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.lb5 { + background: url(../images/leftbar-62.jpg) -294px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.lb6 { + background: url(../images/leftbar-62.jpg) -360px 0px; + height: 62px; + width: 62px; + cursor: pointer; + border: none; + position:absolute; + top: 6px; + left: 6px +} + +.m0 { background : url(../images/images16.png) -32px 0px; height : 16px; width : 16px; border:none; float:left } +.m1 { background : url(../images/images16.png) -16px 0px; height : 16px; width : 16px; border:none; float:left } +.m2 { background : url(../images/images16.png) -96px 0px; height : 16px; width : 16px; border:none; float:left } +.m3 { background : url(../images/images16.png) -112px 0px; height : 16px; width : 16px; border:none; float:left } +.si0 { background : url(../images/icons16.png) 0px 0px; height : 16px; width : 16px; border:none; float:left } +.si1 { background : url(../images/icons16.png) -16px 0px; height : 16px; width : 16px; border:none; float:left } +.si2 { background : url(../images/icons16.png) -32px 0px; height : 16px; width : 16px; border:none; float:left } +.si3 { background : url(../images/icons16.png) -48px 0px; height : 16px; width : 16px; border:none; float:left } +.si4 { background : url(../images/icons16.png) -64px 0px; height : 16px; width : 16px; border:none; float:left } + +.mi { background : url(../images/meshicon50.png) 0px 0px; height: 50px; width: 50px; cursor:pointer; border:none } + +#floatframe { + position: fixed; + top: 200px; + height: 300px; + z-index: 200; + display: none; +} + +.style1 { + text-align: center; +} + +.style2 { + text-align: center; + background-color: #808080; + font-weight: bold; +} + +.style3 { + text-align: center; + color: white; + background-color: #808080; + font-weight: bold; +} + +.style3x { + text-align: center; + color: white; + background-color: #808080; + font-weight: bold; +} + + .style3x:hover { + background-color: #606060; + } + + .style3x.fullselect { + background-color: #003366; + } + + .style3x.semiselect { + background-color: #606060; + } + +.style3sel { + text-align: center; + color: white; + background-color: #003366; + font-weight: bold; +} + + +.style4 { + color: white; + text-decoration: none; +} + +.style5 { + text-align: center; + background-color: #808080; + font-weight: normal; +} + +.style6 { + text-align: left; + background-color: #D3D9D6; + padding:3px; +} + +.style7 { + font-size: large; + background-color: #FFFFFF; + width: 180px; +} + +.style9 { + max-width: 400px; + overflow: hidden; +} + +.style10 { + background-color: #C9C9C9; +} + +.style11 { + font-size: large; + background-color: #C9C9C9; +} + +.style14 { + height: 100%; + text-align: left; + background-color: #D3D9D6; +} + +.auto-style1 { + text-align: right; + background-color: #D3D9D6; +} + +.icon2 { + float: left; + margin: 7px; +} + +.warningbox { + width: auto; + border-radius: 8px; + padding: 8px; + background-color: lightsalmon; +} + +.fileIcon1 { + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb49Y2Sj9LT2f///yH5BAEAAAMALAAAAAAQABAAAAImnI+py+1vhJwyUYAzHTL4D3qdlJWaIFJqmKod607sDKIiDUP63hQAOw==); + height: 16px; + width: 16px; + cursor: pointer; + border: none; + float: left; + margin-top: 1px; +} + +.fileIcon2 { + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7); + height: 16px; + width: 16px; + cursor: pointer; + border: none; + float: left; + margin-top: 1px; +} + +.fileIcon3 { + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==); + height: 16px; + width: 16px; + cursor: pointer; + border: none; + float: left; + margin-top: 1px; +} + +.fileIcon4 { + background: url(../images/meshicon16.png); + height: 16px; + width: 16px; + cursor: pointer; + border: none; + float: left; + margin-top: 1px; +} + +.filelist { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -o-user-select: none; + cursor: default; + -khtml-user-drag: element; + background-color: white; + clear: both; +} + +.noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.fsize { + float: right; + text-align: right; + width: 180px; +} + +.g1 { + background-position: 0% 0%; + width: 14px; + height: 100%; + float: left; + /* fallback (Opera) */ + /* Mozilla: */ + /* Chrome, Safari:*/ + background-image: linear-gradient(to right, #ffffff 0%, #c9c9c9 100%); + background-color: #c9c9c9; + background-repeat: repeat; + background-attachment: scroll; +} + #p3events .g1 { + float: none; + } + #p3users .g1 { + height:24px; + float: left; + } + +.g1s { + background-image: linear-gradient(to right, #ffffff 0%, #b9b9b9 100%); +} + +.g2 { + background-position: 0% 0%; + width: 14px; + height: 100%; + float: right; + /* fallback (Opera) */ + /* Mozilla: */ + /* Chrome, Safari:*/ + background-image: linear-gradient(to right, #c9c9c9 0%, #ffffff 100%); + background-color: #c9c9c9; + background-repeat: repeat; + background-attachment: scroll; +} + #p3events .g2 { + float: none; + } + #p3users .g2 { + height:24px; + float: right; + } + +.g2s { + background-image: linear-gradient(to right, #b9b9b9 0%, #ffffff 100%); +} + +.h1pre { + width: 16px; + height: 100%; + float: left; + font-size: large; + background-color: #FFFFFF; +} + +.h1 { + background-position: 0% 0%; + width: 14px; + height: 100%; + /* fallback (Opera) */ + /* Mozilla: */ + /* Chrome, Safari:*/ + background-image: linear-gradient(to right, #ffffff 0%, #d3d9d6 100%); + background-color: #d3d9d6; + background-repeat: repeat; + background-attachment: scroll; +} + +.h2end { + height: 100%; + width: 20px; + float: right; + background-color: #ffffff +} + +.h2 { + background-position: 0% 0%; + width: 14px; + height: 100%; + /* fallback (Opera) */ + /* Mozilla: */ + /* Chrome, Safari:*/ + background-image: linear-gradient(to right, #d3d9d6 0%, #ffffff 100%); + background-color: #d3d9d6; + background-repeat: repeat; + background-attachment: scroll; +} + +.e1 { + font-size: large; + margin-top: 4px; + margin-bottom: 3px; + overflow: hidden; + word-wrap: hyphenate; + white-space: nowrap; + text-overflow: ellipsis; +} + +.e2 { + float: left; + height: 100%; + background-color: #c9c9c9; +} + +.e2s { + background-color: #b9b9b9; +} + +.bar { + font-size: large; + background-color: #C9C9C9; + height: 24px; + float: left; + margin-bottom: 2px; +} + #p3users .bar { + width: 100%; + font-size: medium; + } + +.baricon { + float: left; + height: 24px; + width: 24px; + background-color: white; +} + .baricon div { + width: 16px; + margin-top: 4px; + margin-left: 2px; + height: 16px + } + +.bar2 { + font-size: large; + height: 24px; + float: left; + margin-bottom: 2px; +} + +.bar18 { + font-size: large; + background-color: #C9C9C9; + height: 18px; + float: left; + margin-bottom: 2px; +} + +.bar182 { + font-size: large; + height: 18px; + float: left; + margin-bottom: 2px; +} + +.devHeaderx { + color: lightgray; +} + +.DevSt { + border-bottom-style: solid; + border-bottom-width: 1px; + border-bottom-color: #DDDDDD; +} + +.contextMenu { + background: #F9F9F9; + box-shadow: 0 0 12px rgba( 0, 0, 0, .3 ); + border: 1px solid #ccc; + /*border-radius: 4px;*/ + display: none; + position: absolute; + top: 0; + left: 0; + list-style: none; + margin: 0; + padding: 5px; + min-width: 100px; + max-width: 150px; + z-index: 500; +} + +.cmtext { + color: #444; + display: inline-block; + padding-left: 8px; + padding-right: 8px; + padding-top: 5px; + padding-bottom: 5px; + text-decoration: none; + width: 85%; + cursor: default; + overflow: hidden; + position: relative; +} + + .cmtext:hover { + color: #f9f9f9; + background: #444; + } + +.gray { + /*filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");*/ /* Firefox 10+, Firefox on Android */ + filter: gray; /* IE6-9 */ + -webkit-filter: grayscale(100%) opacity(60%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */ +} + +.unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.notifiyBox { + position: absolute; + z-index:1000; + top: 50px; + right: 26px; + width: 300px; + text-align: left; + background-color: #F0ECCD; + border: 4px solid #666; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + -webkit-box-shadow: 2px 2px 4px #888; + -moz-box-shadow: 2px 2px 4px #888; + box-shadow: 2px 2px 4px #888; + max-height:200px; +} + +.notifiyBox:before { + content: ' '; + position: absolute; + width: 0; + height: 0; + right: 5px; + top: -30px; + border: 15px solid; + border-color: transparent #666 #666 transparent; +} + +.notifiyBox:after { + content: ' '; + position: absolute; + width: 0; + height: 0; + right: 7px; + top: -24px; + border: 12px solid; + border-color: transparent #F0ECCD #F0ECCD transparent; +} + +.notification { + width:100%; + min-height:30px; +} + +.notification:hover { + background-color: #EFE8B6; +} + +#notificationCount { + min-width: 28px; + font-size: 20px; + border-radius: 5px; + background-color: lightblue; + text-align: center; + margin: 8px; + cursor: pointer; + padding: 4px +} + +#deskarea3x { + background: black; + text-align: center; + position: relative; + overflow: hidden; +} + +#DeskFocus { + overflow: hidden; + color: transparent; + border:3px dotted rgba(255,0,0,.2); + position: absolute; + border-radius: 5px; +} + +#DeskParent { + overflow:hidden +} + +#Desk { + overflow: hidden; + width: 100%; + -ms-touch-action: none; + margin-left: 0px; +} + + +#deskToolsBar { + position: absolute; + padding: 3px; + border-radius: 3px 3px 0px 0px; + top: 5px; + left: 4px; + bottom: 26px; + background-color:lightgray; + cursor: pointer; +} + +#DeskToolsProcesses { + overflow-y: scroll; + position: absolute; + top: 24px; + bottom: 0px; + width: 100% +} + +.deskToolsBar { + padding: 3px; +} +.deskToolsBar:hover { + background-color: #EFE8B6; +} + + +.userTableHeader { + border-bottom: 1pt solid lightgray; + padding-top: 4px; + padding-bottom: 4px; +} + +.viewSelector { + width:32px; + height:32px; + background-color:#DDD; + border-radius:3px; + float:left; + margin-left:5px; + cursor: pointer; + opacity: 0.3; +} + +.viewSelectorSel { + background-color:#BBB; + opacity: 0.8; +} + + .viewSelector:hover { + opacity: 0.5; + background-color:#AAA; + } + + +.viewSelector1 { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -0px 0px; + height: 28px; + width: 28px; +} + +.viewSelector2 { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -28px 0px; + height: 28px; + width: 28px; +} + +.viewSelector3 { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -56px 0px; + height: 28px; + width: 28px; +} + +.viewSelector4 { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -84px 0px; + height: 28px; + width: 28px; +} + +.viewSelector5 { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -112px 0px; + height: 28px; + width: 28px; +} + +.backButtonEx { + margin-left:2px; + margin-top:2px; + background: url(../images/views.png) -140px 0px; + height: 28px; + width: 28px; +} + +.backButton { + width:32px; + height:32px; + background-color:#DDD; + border-radius:3px; + float:left; + margin-right:5px; + cursor: pointer; + opacity: 0.3; +} + .backButton:hover { + opacity: 0.5; + background-color:#AAA; + } + +.hoverButton { + opacity: 0.5; + width: 10px; + height: 10px; +} + + .hoverButton:hover { + opacity: 1; + } + +.tagSpan { + background-color: lightgray; + padding: 3px; + margin-right: 4px; + border-radius: 5px; +} \ No newline at end of file diff --git a/public/styles/style.css b/public/styles/style.css index 7916784c..2d732d13 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -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; diff --git a/sample-config.json b/sample-config.json index 2affe5a5..229724f5 100644 --- a/sample-config.json +++ b/sample-config.json @@ -49,13 +49,15 @@ "_NewAccountEmailDomains": [ "sample.com" ], "Footer": "Twitter", "_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, diff --git a/views/default-min.handlebars b/views/default-min.handlebars index 9634a0ff..5954aa17 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - MeshCentral

{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index e1b96347..a43663ff 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral
{{{title}}}
{{{title2}}}
\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index b12064f7..2c5a6563 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -18,7 +18,7 @@ - MeshCentral + {{{title}}} {{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file + {{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file diff --git a/views/login.handlebars b/views/login.handlebars index 7103df18..327fad3e 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -22,7 +22,7 @@
-
+

Welcome

diff --git a/views/messenger-min.handlebars b/views/messenger-min.handlebars index c477cfab..867b086c 100644 --- a/views/messenger-min.handlebars +++ b/views/messenger-min.handlebars @@ -1 +1 @@ -MeshMessenger
MeshMessenger
\ No newline at end of file +MeshMessenger
MeshMessenger
\ No newline at end of file diff --git a/webserver.js b/webserver.js index c1a5efe7..480c66dc 100644 --- a/webserver.js +++ b/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; }