mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Added RDP ClickOnce support.
This commit is contained in:
parent
5108b344be
commit
3801159200
@ -33,9 +33,11 @@
|
|||||||
<Compile Include="meshcentral.js" />
|
<Compile Include="meshcentral.js" />
|
||||||
<Compile Include="meshagent.js" />
|
<Compile Include="meshagent.js" />
|
||||||
<Compile Include="meshrelay.js" />
|
<Compile Include="meshrelay.js" />
|
||||||
|
<Compile Include="meshuser.js" />
|
||||||
<Compile Include="mpsserver.js" />
|
<Compile Include="mpsserver.js" />
|
||||||
<Compile Include="multiserver.js" />
|
<Compile Include="multiserver.js" />
|
||||||
<Compile Include="pass.js" />
|
<Compile Include="pass.js" />
|
||||||
|
<Compile Include="public\relay.js" />
|
||||||
<Compile Include="public\scripts\amt-0.2.0.js" />
|
<Compile Include="public\scripts\amt-0.2.0.js" />
|
||||||
<Compile Include="public\scripts\agent-desktop-0.0.2.js" />
|
<Compile Include="public\scripts\agent-desktop-0.0.2.js" />
|
||||||
<Compile Include="public\scripts\amt-desktop-0.0.2.js" />
|
<Compile Include="public\scripts\amt-desktop-0.0.2.js" />
|
||||||
@ -54,6 +56,15 @@
|
|||||||
<Compile Include="redirserver.js" />
|
<Compile Include="redirserver.js" />
|
||||||
<Compile Include="webserver.js" />
|
<Compile Include="webserver.js" />
|
||||||
<Content Include="package.json" />
|
<Content Include="package.json" />
|
||||||
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" />
|
||||||
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" />
|
||||||
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" />
|
||||||
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.manifest" />
|
||||||
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.ico.deploy" />
|
||||||
|
<Content Include="public\clickonce\minirouter\MeshMiniRouter.application" />
|
||||||
|
<Content Include="public\clickonce\minirouter\publish.htm" />
|
||||||
|
<Content Include="public\commander.htm" />
|
||||||
|
<Content Include="public\favicon.ico" />
|
||||||
<Content Include="public\images-isdu\ComputerIcon.png" />
|
<Content Include="public\images-isdu\ComputerIcon.png" />
|
||||||
<Content Include="public\images-isdu\ComputerIcon2.png" />
|
<Content Include="public\images-isdu\ComputerIcon2.png" />
|
||||||
<Content Include="public\images-isdu\IntelLogo.png" />
|
<Content Include="public\images-isdu\IntelLogo.png" />
|
||||||
@ -71,6 +82,40 @@
|
|||||||
<Content Include="public\images-isdu\info.gif" />
|
<Content Include="public\images-isdu\info.gif" />
|
||||||
<Content Include="public\images-isdu\warning.gif" />
|
<Content Include="public\images-isdu\warning.gif" />
|
||||||
<Content Include="public\images-isdu\isdu.ico" />
|
<Content Include="public\images-isdu\isdu.ico" />
|
||||||
|
<Content Include="public\images\dot.png" />
|
||||||
|
<Content Include="public\images\icon-addnew.png" />
|
||||||
|
<Content Include="public\images\icon-graph.png" />
|
||||||
|
<Content Include="public\images\icon-installmesh.png" />
|
||||||
|
<Content Include="public\images\icon-manage.png" />
|
||||||
|
<Content Include="public\images\icon-remove.png" />
|
||||||
|
<Content Include="public\images\icons16.png" />
|
||||||
|
<Content Include="public\images\icons200-1-1.png" />
|
||||||
|
<Content Include="public\images\icons200-2-1.png" />
|
||||||
|
<Content Include="public\images\icons200-3-1.png" />
|
||||||
|
<Content Include="public\images\icons200-4-1.png" />
|
||||||
|
<Content Include="public\images\icons200-5-1.png" />
|
||||||
|
<Content Include="public\images\icons200-6-1.png" />
|
||||||
|
<Content Include="public\images\icons50.png" />
|
||||||
|
<Content Include="public\images\images16.png" />
|
||||||
|
<Content Include="public\images\info.png" />
|
||||||
|
<Content Include="public\images\link1.png" />
|
||||||
|
<Content Include="public\images\link2.png" />
|
||||||
|
<Content Include="public\images\link3.png" />
|
||||||
|
<Content Include="public\images\link4.png" />
|
||||||
|
<Content Include="public\images\logoback.png" />
|
||||||
|
<Content Include="public\images\mainaccount.png" />
|
||||||
|
<Content Include="public\images\mainwelcome.png" />
|
||||||
|
<Content Include="public\images\mapmarker-gps.png" />
|
||||||
|
<Content Include="public\images\mapmarker-ip.png" />
|
||||||
|
<Content Include="public\images\mapmarker-user.png" />
|
||||||
|
<Content Include="public\images\mapmarker-wifi.png" />
|
||||||
|
<Content Include="public\images\mapmarker.png" />
|
||||||
|
<Content Include="public\images\meshicon50.png" />
|
||||||
|
<Content Include="public\images\trash.png" />
|
||||||
|
<Content Include="public\index.html" />
|
||||||
|
<Content Include="public\relay.htm" />
|
||||||
|
<Content Include="public\scriptblocks.txt" />
|
||||||
|
<Content Include="public\sounds\chimes.mp3" />
|
||||||
<Content Include="public\styles\font-awesome\css\font-awesome.min.css" />
|
<Content Include="public\styles\font-awesome\css\font-awesome.min.css" />
|
||||||
<Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.eot" />
|
<Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.eot" />
|
||||||
<Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.svg" />
|
<Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.svg" />
|
||||||
@ -108,6 +153,7 @@
|
|||||||
<Content Include="public\styles\font-awesome\scss\_variables.scss" />
|
<Content Include="public\styles\font-awesome\scss\_variables.scss" />
|
||||||
<Content Include="public\styles\style.css" />
|
<Content Include="public\styles\style.css" />
|
||||||
<Content Include="readme.txt" />
|
<Content Include="readme.txt" />
|
||||||
|
<Content Include="SourceFileList.txt" />
|
||||||
<Content Include="views\default.handlebars" />
|
<Content Include="views\default.handlebars" />
|
||||||
<Content Include="views\download.handlebars" />
|
<Content Include="views\download.handlebars" />
|
||||||
<Content Include="views\login.handlebars" />
|
<Content Include="views\login.handlebars" />
|
||||||
@ -116,8 +162,14 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="agents\" />
|
<Folder Include="agents\" />
|
||||||
<Folder Include="public" />
|
<Folder Include="public" />
|
||||||
|
<Folder Include="public\clickonce\" />
|
||||||
|
<Folder Include="public\clickonce\minirouter\" />
|
||||||
|
<Folder Include="public\clickonce\minirouter\Application Files\" />
|
||||||
|
<Folder Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\" />
|
||||||
<Folder Include="public\images-isdu" />
|
<Folder Include="public\images-isdu" />
|
||||||
|
<Folder Include="public\images\" />
|
||||||
<Folder Include="public\scripts\" />
|
<Folder Include="public\scripts\" />
|
||||||
|
<Folder Include="public\sounds\" />
|
||||||
<Folder Include="public\styles\" />
|
<Folder Include="public\styles\" />
|
||||||
<Folder Include="public\styles\font-awesome\" />
|
<Folder Include="public\styles\font-awesome\" />
|
||||||
<Folder Include="public\styles\font-awesome\css\" />
|
<Folder Include="public\styles\font-awesome\css\" />
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -18,7 +18,7 @@ function createMeshCore(agent) {
|
|||||||
var obj = {};
|
var obj = {};
|
||||||
|
|
||||||
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
||||||
obj.meshCoreInfo = "MeshCore v3k";
|
obj.meshCoreInfo = "MeshCore v4";
|
||||||
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
|
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
|
||||||
obj.useNativePipes = true; //(process.platform == 'win32');
|
obj.useNativePipes = true; //(process.platform == 'win32');
|
||||||
var meshServerConnectionState = 0;
|
var meshServerConnectionState = 0;
|
||||||
@ -28,6 +28,7 @@ function createMeshCore(agent) {
|
|||||||
var lastPublicLocationInfo = null;
|
var lastPublicLocationInfo = null;
|
||||||
var selfInfoUpdateTimer = null;
|
var selfInfoUpdateTimer = null;
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
var net = require('net');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var rtc = require('ILibWebRTC');
|
var rtc = require('ILibWebRTC');
|
||||||
var wifiScannerLib = null;
|
var wifiScannerLib = null;
|
||||||
@ -57,7 +58,7 @@ function createMeshCore(agent) {
|
|||||||
|
|
||||||
// Get our location (lat/long) using our public IP address
|
// Get our location (lat/long) using our public IP address
|
||||||
var getIpLocationDataExInProgress = false;
|
var getIpLocationDataExInProgress = false;
|
||||||
var getIpLocationDataExCounts = [ 0, 0 ];
|
var getIpLocationDataExCounts = [0, 0];
|
||||||
function getIpLocationDataEx(func) {
|
function getIpLocationDataEx(func) {
|
||||||
if (getIpLocationDataExInProgress == true) { return false; }
|
if (getIpLocationDataExInProgress == true) { return false; }
|
||||||
try {
|
try {
|
||||||
@ -157,7 +158,9 @@ function createMeshCore(agent) {
|
|||||||
var w = arguments[i];
|
var w = arguments[i];
|
||||||
if (w != null) {
|
if (w != null) {
|
||||||
while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
|
while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
|
||||||
while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
|
if (i != 0) {
|
||||||
|
while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
|
||||||
|
}
|
||||||
x.push(w);
|
x.push(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,29 +286,27 @@ function createMeshCore(agent) {
|
|||||||
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
|
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (data.type == 'tunnel') { // Process a new tunnel connection request
|
else if ((data.type == 'tunnel') && (data.value != null)) { // Process a new tunnel connection request
|
||||||
if (data.value && data.sessionid) {
|
// Create a new tunnel object
|
||||||
// Create a new tunnel object
|
var xurl = getServerTargetUrlEx(data.value);
|
||||||
sendConsoleText(data.value);
|
if (xurl != null) {
|
||||||
var xurl = getServerTargetUrlEx(data.value);
|
var tunnel = http.request(http.parseUri(xurl));
|
||||||
sendConsoleText(xurl);
|
tunnel.upgrade = onTunnelUpgrade;
|
||||||
if (xurl != null) {
|
tunnel.sessionid = data.sessionid;
|
||||||
var tunnel = http.request(http.parseUri(xurl));
|
tunnel.rights = data.rights;
|
||||||
tunnel.upgrade = onTunnelUpgrade;
|
tunnel.state = 0;
|
||||||
tunnel.sessionid = data.sessionid;
|
tunnel.url = xurl;
|
||||||
tunnel.rights = data.rights;
|
tunnel.protocol = 0;
|
||||||
tunnel.state = 0;
|
tunnel.tcpaddr = data.tcpaddr;
|
||||||
tunnel.url = xurl;
|
tunnel.tcpport = data.tcpport;
|
||||||
tunnel.protocol = 0;
|
|
||||||
|
|
||||||
// Put the tunnel in the tunnels list
|
// Put the tunnel in the tunnels list
|
||||||
var index = 1;
|
var index = 1;
|
||||||
while (tunnels[index]) { index++; }
|
while (tunnels[index]) { index++; }
|
||||||
tunnel.index = index;
|
tunnel.index = index;
|
||||||
tunnels[index] = tunnel;
|
tunnels[index] = tunnel;
|
||||||
|
|
||||||
sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
|
sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -339,7 +340,7 @@ function createMeshCore(agent) {
|
|||||||
|
|
||||||
// Called when a file changed in the file system
|
// Called when a file changed in the file system
|
||||||
function onFileWatcher(a, b) {
|
function onFileWatcher(a, b) {
|
||||||
//console.log('onFileWatcher', a, b, this.path);
|
console.log('onFileWatcher', a, b, this.path);
|
||||||
var response = getDirectoryInfo(this.path);
|
var response = getDirectoryInfo(this.path);
|
||||||
if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
|
if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
|
||||||
}
|
}
|
||||||
@ -364,6 +365,7 @@ function createMeshCore(agent) {
|
|||||||
if (reqpath == '') { reqpath = '/'; }
|
if (reqpath == '') { reqpath = '/'; }
|
||||||
var xpath = obj.path.join(reqpath, '*');
|
var xpath = obj.path.join(reqpath, '*');
|
||||||
var results = null;
|
var results = null;
|
||||||
|
|
||||||
try { results = fs.readdirSync(xpath); } catch (e) { }
|
try { results = fs.readdirSync(xpath); } catch (e) { }
|
||||||
if (results != null) {
|
if (results != null) {
|
||||||
for (var i = 0; i < results.length; ++i) {
|
for (var i = 0; i < results.length; ++i) {
|
||||||
@ -385,7 +387,38 @@ function createMeshCore(agent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tunnel callback operations
|
// Tunnel callback operations
|
||||||
function onTunnelUpgrade(response, s, head) { sendConsoleText('onTunnelUpgrade'); this.s = s; s.httprequest = this; s.end = onTunnelClosed; s.data = onTunnelData; }
|
function onTunnelUpgrade(response, s, head) {
|
||||||
|
this.s = s;
|
||||||
|
s.httprequest = this;
|
||||||
|
s.end = onTunnelClosed;
|
||||||
|
|
||||||
|
if (this.tcpport != null) {
|
||||||
|
// This is a TCP relay connection, pause now and try to connect to the target.
|
||||||
|
s.pause();
|
||||||
|
s.data = onTcpRelayServerTunnelData;
|
||||||
|
var connectionOptions = { port: parseInt(this.tcpport) };
|
||||||
|
if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
|
||||||
|
s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
|
||||||
|
s.tcprelay.peerindex = this.index;
|
||||||
|
} else {
|
||||||
|
// This is a normal connect for KVM/Terminal/Files
|
||||||
|
s.data = onTunnelData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the TCP relay target is connected
|
||||||
|
function onTcpRelayTargetTunnelConnect() {
|
||||||
|
var peerTunnel = tunnels[this.peerindex];
|
||||||
|
this.pipe(peerTunnel.s); // Pipe Target --> Server
|
||||||
|
peerTunnel.s.first = true;
|
||||||
|
peerTunnel.s.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
|
||||||
|
function onTcpRelayServerTunnelData(data) {
|
||||||
|
if (this.first == true) { this.first = false; this.pipe(this.tcprelay); } // Pipe Server --> Target
|
||||||
|
}
|
||||||
|
|
||||||
function onTunnelClosed() {
|
function onTunnelClosed() {
|
||||||
sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
||||||
if (this.httprequest.protocol == 1) { this.httprequest.process.end(); delete this.httprequest.process; }
|
if (this.httprequest.protocol == 1) { this.httprequest.process.end(); delete this.httprequest.process; }
|
||||||
@ -395,7 +428,7 @@ function createMeshCore(agent) {
|
|||||||
if (this.httprequest.watcher != undefined) {
|
if (this.httprequest.watcher != undefined) {
|
||||||
//console.log('Closing watcher: ' + this.httprequest.watcher.path);
|
//console.log('Closing watcher: ' + this.httprequest.watcher.path);
|
||||||
//this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
|
//this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
|
||||||
delete this.httprequest.watcher;
|
delete this.httprequest.watcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a upload or download active on this connection, close the file
|
// If there is a upload or download active on this connection, close the file
|
||||||
@ -404,6 +437,7 @@ function createMeshCore(agent) {
|
|||||||
}
|
}
|
||||||
function onTunnelSendOk() { sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid); }
|
function onTunnelSendOk() { sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid); }
|
||||||
function onTunnelData(data) {
|
function onTunnelData(data) {
|
||||||
|
console.log("OnTunnelData");
|
||||||
// If this is upload data, save it to file
|
// If this is upload data, save it to file
|
||||||
if (this.httprequest.uploadFile) {
|
if (this.httprequest.uploadFile) {
|
||||||
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(JSON.stringify({ action: 'uploaderror' })); return; } // Write to the file, if there is a problem, error out.
|
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(JSON.stringify({ action: 'uploaderror' })); return; } // Write to the file, if there is a problem, error out.
|
||||||
@ -521,8 +555,7 @@ function createMeshCore(agent) {
|
|||||||
try { cmd = JSON.parse(data); } catch (e) { };
|
try { cmd = JSON.parse(data); } catch (e) { };
|
||||||
if ((cmd == null) || (cmd.action == undefined)) { return; }
|
if ((cmd == null) || (cmd.action == undefined)) { return; }
|
||||||
if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
|
if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
|
||||||
sendConsoleText(JSON.stringify(cmd));
|
console.log(objToString(cmd, 0, '.'));
|
||||||
//console.log(objToString(cmd, 0, '.'));
|
|
||||||
switch (cmd.action) {
|
switch (cmd.action) {
|
||||||
case 'ls': {
|
case 'ls': {
|
||||||
// Close the watcher if required
|
// Close the watcher if required
|
||||||
@ -534,9 +567,7 @@ function createMeshCore(agent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the folder content to the browser
|
// Send the folder content to the browser
|
||||||
sendConsoleText(JSON.stringify(cmd.path));
|
|
||||||
var response = getDirectoryInfo(cmd.path);
|
var response = getDirectoryInfo(cmd.path);
|
||||||
sendConsoleText(JSON.stringify(response));
|
|
||||||
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
|
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
|
||||||
this.write(JSON.stringify(response));
|
this.write(JSON.stringify(response));
|
||||||
|
|
||||||
@ -605,11 +636,11 @@ function createMeshCore(agent) {
|
|||||||
//sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
|
//sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Console state
|
// Console state
|
||||||
var consoleWebSockets = {};
|
var consoleWebSockets = {};
|
||||||
var consoleHttpRequest = null;
|
var consoleHttpRequest = null;
|
||||||
|
|
||||||
// Console HTTP response
|
// Console HTTP response
|
||||||
function consoleHttpResponse(response) {
|
function consoleHttpResponse(response) {
|
||||||
response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
|
response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
|
||||||
@ -807,7 +838,7 @@ function createMeshCore(agent) {
|
|||||||
response += (results[i] + "\r\n");
|
response += (results[i] + "\r\n");
|
||||||
} else {
|
} else {
|
||||||
response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
|
response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1001,7 +1032,7 @@ function createMeshCore(agent) {
|
|||||||
function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
|
function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
|
||||||
function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
|
function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
|
||||||
function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
|
function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
|
||||||
|
|
||||||
function onWebSocketUpgrade(response, s, head) {
|
function onWebSocketUpgrade(response, s, head) {
|
||||||
sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
|
sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
|
||||||
this.s = s;
|
this.s = s;
|
||||||
|
@ -362,6 +362,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
// Route a message.
|
// Route a message.
|
||||||
// If this command has a sessionid, that is the target.
|
// If this command has a sessionid, that is the target.
|
||||||
if (command.sessionid != null) {
|
if (command.sessionid != null) {
|
||||||
|
if (typeof command.sessionid != 'string') break;
|
||||||
var splitsessionid = command.sessionid.split('/');
|
var splitsessionid = command.sessionid.split('/');
|
||||||
// Check that we are in the same domain and the user has rights over this node.
|
// Check that we are in the same domain and the user has rights over this node.
|
||||||
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
|
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
|
||||||
@ -384,6 +385,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (command.userid != null) { // If this command has a userid, that is the target.
|
} else if (command.userid != null) { // If this command has a userid, that is the target.
|
||||||
|
if (typeof command.userid != 'string') break;
|
||||||
var splituserid = command.userid.split('/');
|
var splituserid = command.userid.split('/');
|
||||||
// Check that we are in the same domain and the user has rights over this node.
|
// Check that we are in the same domain and the user has rights over this node.
|
||||||
if ((splituserid[0] == 'user') && (splituserid[1] == domain.id)) {
|
if ((splituserid[0] == 'user') && (splituserid[1] == domain.id)) {
|
||||||
|
65
meshrelay.js
65
meshrelay.js
@ -10,21 +10,78 @@ module.exports.CreateMeshRelay = function (parent, ws, req) {
|
|||||||
obj.req = req;
|
obj.req = req;
|
||||||
obj.peer = null;
|
obj.peer = null;
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.id = req.query['id'];
|
obj.id = req.query.id;
|
||||||
obj.remoteaddr = obj.ws._socket.remoteAddress;
|
obj.remoteaddr = obj.ws._socket.remoteAddress;
|
||||||
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
|
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
|
||||||
|
|
||||||
if (obj.id == undefined) { obj.ws.close(); obj.id = null; return null; } // Attempt to connect without id, drop this.
|
// Disconnect this agent
|
||||||
ws._socket.setKeepAlive(true, 0); // Set TCP keep alive
|
obj.close = function (arg) {
|
||||||
|
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Relay: Soft disconnect (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
|
||||||
|
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Relay: Hard disconnect (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.sendAgentMessage = function (command, userid, domainid) {
|
||||||
|
if (command.nodeid == null) return false;
|
||||||
|
var user = obj.parent.users[userid];
|
||||||
|
if (user == null) return false;
|
||||||
|
var splitnodeid = command.nodeid.split('/');
|
||||||
|
// Check that we are in the same domain and the user has rights over this node.
|
||||||
|
if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domainid)) {
|
||||||
|
// Get the user object
|
||||||
|
// See if the node is connected
|
||||||
|
var agent = obj.parent.wsagents[command.nodeid];
|
||||||
|
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 & 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
|
||||||
|
delete command.nodeid; // Remove the nodeid since it's implyed.
|
||||||
|
agent.send(JSON.stringify(command));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check if a peer server is connected to this agent
|
||||||
|
var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
|
||||||
|
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 & 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
|
||||||
|
obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.query.auth == null) {
|
if (req.query.auth == null) {
|
||||||
// Use ExpressJS session, check if this session is a logged in user, at least one of the two connections will need to be authenticated.
|
// Use ExpressJS session, check if this session is a logged in user, at least one of the two connections will need to be authenticated.
|
||||||
try { if ((req.session) && (req.session.userid) || (req.session.domainid == getDomain(req).id)) { obj.authenticated = true; } } catch (e) { }
|
try { if ((req.session) && (req.session.userid) || (req.session.domainid == getDomain(req).id)) { obj.authenticated = true; } } catch (e) { }
|
||||||
} else {
|
} else {
|
||||||
// Get the session from the cookie
|
// Get the session from the cookie
|
||||||
if ((obj.parent.parent.multiServer != null) && (obj.parent.parent.multiServer.decodeCookie(req.query.auth) != null)) { obj.authenticated = true; }
|
var cookie = obj.parent.parent.webserver.decodeCookie(req.query.auth);
|
||||||
|
if (cookie != null) {
|
||||||
|
obj.authenticated = true;
|
||||||
|
if (cookie.tcpport != null) {
|
||||||
|
// This cookie has agent routing instructions, process this here.
|
||||||
|
if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
|
||||||
|
// Send connection request to agent
|
||||||
|
var command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr };
|
||||||
|
if (obj.sendAgentMessage(command, cookie.userid, cookie.domainid) == false) { obj.id = null; obj.parent.parent.debug(1, 'Relay: Unable to contact this agent (' + obj.remoteaddr + ')'); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj.id = null;
|
||||||
|
obj.parent.parent.debug(1, 'Relay: invalid cookie (' + obj.remoteaddr + ')');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.id == null) { try { obj.close(); } catch (e) { } return null; } // Attempt to connect without id, drop this.
|
||||||
|
ws._socket.setKeepAlive(true, 0); // Set TCP keep alive
|
||||||
|
|
||||||
// Validate that the id is valid, we only need to do this on non-authenticated sessions.
|
// Validate that the id is valid, we only need to do this on non-authenticated sessions.
|
||||||
// TODO: Figure out when this needs to be done.
|
// TODO: Figure out when this needs to be done.
|
||||||
/*
|
/*
|
||||||
|
@ -23,19 +23,17 @@ module.exports.CreateMeshScanner = function (parent) {
|
|||||||
// Get a list of IPv4 and IPv6 interface addresses
|
// Get a list of IPv4 and IPv6 interface addresses
|
||||||
function getInterfaceList() {
|
function getInterfaceList() {
|
||||||
var ipv4 = ['*'], ipv6 = ['*']; // Bind to IN_ADDR_ANY always
|
var ipv4 = ['*'], ipv6 = ['*']; // Bind to IN_ADDR_ANY always
|
||||||
//if (parent.platform == 'win32') { // On Windows, also bind to each interface seperatly (TODO: REMOVE THIS AND TEST ON LINUX!!!!!!!!!!!!!!!!!!)
|
var interfaces = require('os').networkInterfaces();
|
||||||
var interfaces = require('os').networkInterfaces();
|
for (var i in interfaces) {
|
||||||
for (var i in interfaces) {
|
var interface = interfaces[i];
|
||||||
var interface = interfaces[i];
|
for (var j in interface) {
|
||||||
for (var j in interface) {
|
var interface2 = interface[j];
|
||||||
var interface2 = interface[j];
|
if ((interface2.mac != '00:00:00:00:00:00') && (interface2.internal == false)) {
|
||||||
if ((interface2.mac != '00:00:00:00:00:00') && (interface2.internal == false)) {
|
if (interface2.family == 'IPv4') { ipv4.push(interface2.address); }
|
||||||
if (interface2.family == 'IPv4') { ipv4.push(interface2.address); }
|
if (interface2.family == 'IPv6') { ipv6.push(interface2.address + '%' + i); }
|
||||||
if (interface2.family == 'IPv6') { ipv6.push(interface2.address + '%' + i); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
}
|
||||||
return { ipv4: ipv4, ipv6: ipv6 };
|
return { ipv4: ipv4, ipv6: ipv6 };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ module.exports.CreateMeshScanner = function (parent) {
|
|||||||
server4.xxtype = 4;
|
server4.xxtype = 4;
|
||||||
server4.xxlocal = localAddress;
|
server4.xxlocal = localAddress;
|
||||||
server4.on('error', function (err) { if (this.xxlocal == '*') { console.log("ERROR: Server port 16989 not available, check if server is running twice."); } this.close(); delete obj.servers6[this.xxlocal]; });
|
server4.on('error', function (err) { if (this.xxlocal == '*') { console.log("ERROR: Server port 16989 not available, check if server is running twice."); } this.close(); delete obj.servers6[this.xxlocal]; });
|
||||||
var bindOptions = { port: 16989, exclusive: false };
|
var bindOptions = { port: 16989, exclusive: true };
|
||||||
if (server4.xxlocal != '*') { bindOptions.address = server4.xxlocal; }
|
if (server4.xxlocal != '*') { bindOptions.address = server4.xxlocal; }
|
||||||
server4.bind(bindOptions, function () {
|
server4.bind(bindOptions, function () {
|
||||||
try {
|
try {
|
||||||
@ -68,7 +66,7 @@ module.exports.CreateMeshScanner = function (parent) {
|
|||||||
this.on('message', function (msg, info) { onUdpPacket(msg, info, this); });
|
this.on('message', function (msg, info) { onUdpPacket(msg, info, this); });
|
||||||
obj.performScan(this);
|
obj.performScan(this);
|
||||||
obj.performScan(this);
|
obj.performScan(this);
|
||||||
} catch (e) { }
|
} catch (e) { console.log(e); }
|
||||||
});
|
});
|
||||||
obj.servers4[localAddress] = server4;
|
obj.servers4[localAddress] = server4;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -84,28 +82,32 @@ module.exports.CreateMeshScanner = function (parent) {
|
|||||||
obj.servers6[localAddress].xxclear = false;
|
obj.servers6[localAddress].xxclear = false;
|
||||||
} else {
|
} else {
|
||||||
// Create a new IPv6 server
|
// Create a new IPv6 server
|
||||||
var server6 = obj.dgram.createSocket({ type: 'udp6', reuseAddr: true });
|
try {
|
||||||
server6.xxclear = false;
|
var server6 = obj.dgram.createSocket({ type: 'udp6', reuseAddr: true });
|
||||||
server6.xxtype = 6;
|
server6.xxclear = false;
|
||||||
server6.xxlocal = localAddress;
|
server6.xxtype = 6;
|
||||||
server6.on('error', function (err) { this.close(); delete obj.servers6[this.xxlocal]; });
|
server6.xxlocal = localAddress;
|
||||||
var bindOptions = { port: 16989, exclusive: false };
|
server6.on('error', function (err) { this.close(); delete obj.servers6[this.xxlocal]; });
|
||||||
if (server6.xxlocal != '*') { bindOptions.address = server6.xxlocal; }
|
var bindOptions = { port: 16989, exclusive: true };
|
||||||
server6.bind(bindOptions, function () {
|
if (server6.xxlocal != '*') { bindOptions.address = server6.xxlocal; }
|
||||||
try {
|
server6.bind(bindOptions, function () {
|
||||||
this.setBroadcast(true);
|
try {
|
||||||
this.setMulticastTTL(128);
|
this.setBroadcast(true);
|
||||||
this.addMembership(membershipIPv6);
|
this.setMulticastTTL(128);
|
||||||
this.on('error', function (error) { console.log('Error: ' + error); });
|
this.addMembership(membershipIPv6);
|
||||||
this.on('message', function (msg, info) { onUdpPacket(msg, info, this); });
|
this.on('error', function (error) { console.log('Error: ' + error); });
|
||||||
obj.performScan(this);
|
this.on('message', function (msg, info) { onUdpPacket(msg, info, this); });
|
||||||
obj.performScan(this);
|
obj.performScan(this);
|
||||||
} catch (e) { }
|
obj.performScan(this);
|
||||||
});
|
} catch (e) { console.log(e); }
|
||||||
obj.servers6[localAddress] = server6;
|
});
|
||||||
|
obj.servers6[localAddress] = server6;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; }; }
|
for (var i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; }; }
|
||||||
for (var i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; }; }
|
for (var i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; }; }
|
||||||
}
|
}
|
||||||
|
931
meshuser.js
Normal file
931
meshuser.js
Normal file
@ -0,0 +1,931 @@
|
|||||||
|
/**
|
||||||
|
* @description Meshcentral MeshAgent
|
||||||
|
* @author Ylian Saint-Hilaire & Bryan Roe
|
||||||
|
* @version v0.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Construct a MeshAgent object, called upon connection
|
||||||
|
module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||||
|
var obj = {};
|
||||||
|
obj.db = db;
|
||||||
|
obj.ws = ws;
|
||||||
|
obj.fs = parent.fs;
|
||||||
|
obj.args = args;
|
||||||
|
obj.parent = parent;
|
||||||
|
obj.domain = domain;
|
||||||
|
obj.common = parent.common;
|
||||||
|
|
||||||
|
// Send a message to the user
|
||||||
|
//obj.send = function (data) { try { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } } catch (e) { } }
|
||||||
|
|
||||||
|
// Disconnect this user
|
||||||
|
obj.close = function (arg) {
|
||||||
|
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Soft disconnect'); } catch (e) { console.log(e); } } // Soft close, close the websocket
|
||||||
|
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Hard disconnect'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if the user is logged in
|
||||||
|
if ((!req.session) || (!req.session.userid) || (req.session.domainid != domain.id)) { try { obj.ws.close(); } catch (e) { } return; }
|
||||||
|
req.session.ws = obj.ws; // Associate this websocket session with the web session
|
||||||
|
req.session.ws.userid = req.session.userid;
|
||||||
|
req.session.ws.domainid = domain.id;
|
||||||
|
var user = obj.parent.users[req.session.userid];
|
||||||
|
if (user == null) { try { obj.ws.close(); } catch (e) { } return; }
|
||||||
|
|
||||||
|
// Add this web socket session to session list
|
||||||
|
obj.ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2);
|
||||||
|
obj.parent.wssessions2[ws.sessionId] = obj.ws;
|
||||||
|
if (!obj.parent.wssessions[user._id]) { obj.parent.wssessions[user._id] = [ws]; } else { obj.parent.wssessions[user._id].push(obj.ws); }
|
||||||
|
if (obj.parent.parent.multiServer == null) {
|
||||||
|
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[user._id].length, nolog: 1, domain: obj.domain.id })
|
||||||
|
} else {
|
||||||
|
obj.parent.recountSessions(obj.ws.sessionId); // Recount sessions
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have peer servers, inform them of the new session
|
||||||
|
if (obj.parent.parent.multiServer != null) { obj.parent.parent.multiServer.DispatchMessage({ action: 'sessionStart', sessionid: obj.ws.sessionId }); }
|
||||||
|
|
||||||
|
// Handle events
|
||||||
|
obj.ws.HandleEvent = function (source, event) {
|
||||||
|
if (!event.domain || event.domain == obj.domain.id) {
|
||||||
|
try {
|
||||||
|
if (event == 'close') { obj.req.session.destroy(); obj.ws.close(); }
|
||||||
|
else if (event == 'resubscribe') { user.subscriptions = obj.parent.subscribe(user._id, ws); }
|
||||||
|
else if (event == 'updatefiles') { updateUserFiles(user, ws, domain); }
|
||||||
|
else { ws.send(JSON.stringify({ action: 'event', event: event })); }
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user.subscriptions = obj.parent.subscribe(user._id, ws); // Subscribe to events
|
||||||
|
obj.ws._socket.setKeepAlive(true, 0); // Set TCP keep alive
|
||||||
|
|
||||||
|
// When data is received from the web socket
|
||||||
|
ws.on('message', function (msg) {
|
||||||
|
var user = obj.parent.users[req.session.userid];
|
||||||
|
var command = JSON.parse(msg.toString('utf8'))
|
||||||
|
switch (command.action) {
|
||||||
|
case 'meshes':
|
||||||
|
{
|
||||||
|
// Request a list of all meshes this user as rights to
|
||||||
|
var docs = [];
|
||||||
|
for (var i in user.links) { if (obj.parent.meshes[i]) { docs.push(obj.parent.meshes[i]); } }
|
||||||
|
ws.send(JSON.stringify({ action: 'meshes', meshes: docs }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'nodes':
|
||||||
|
{
|
||||||
|
// Request a list of all meshes this user as rights to
|
||||||
|
var links = [];
|
||||||
|
for (var i in user.links) { links.push(i); }
|
||||||
|
|
||||||
|
// Request a list of all nodes
|
||||||
|
obj.db.GetAllTypeNoTypeFieldMeshFiltered(links, domain.id, 'node', function (err, docs) {
|
||||||
|
var r = {};
|
||||||
|
for (var i in docs) {
|
||||||
|
// Add the connection state
|
||||||
|
var state = obj.parent.parent.GetConnectivityState(docs[i]._id);
|
||||||
|
if (state) {
|
||||||
|
docs[i].conn = state.connectivity;
|
||||||
|
docs[i].pwr = state.powerState;
|
||||||
|
if ((state.connectivity & 1) != 0) { var agent = obj.parent.wsagents[docs[i]._id]; if (agent != null) { docs[i].agct = agent.connectTime; } }
|
||||||
|
if ((state.connectivity & 2) != 0) { var cira = obj.parent.parent.mpsserver.ciraConnections[docs[i]._id]; if (cira != null) { docs[i].cict = cira.tag.connectTime; } }
|
||||||
|
}
|
||||||
|
// Compress the meshid's
|
||||||
|
var meshid = docs[i].meshid;
|
||||||
|
if (!r[meshid]) { r[meshid] = []; }
|
||||||
|
delete docs[i].meshid;
|
||||||
|
r[meshid].push(docs[i]);
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify({ action: 'nodes', nodes: r }));
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'powertimeline':
|
||||||
|
{
|
||||||
|
// Query the database for the power timeline for a given node
|
||||||
|
// The result is a compacted array: [ startPowerState, startTimeUTC, powerState ] + many[ deltaTime, powerState ]
|
||||||
|
obj.db.getPowerTimeline(command.nodeid, function (err, docs) {
|
||||||
|
if (err == null && docs.length > 0) {
|
||||||
|
var timeline = [], time = null, previousPower;
|
||||||
|
for (var i in docs) {
|
||||||
|
var doc = docs[i];
|
||||||
|
if (time == null) {
|
||||||
|
// First element
|
||||||
|
time = doc.time;
|
||||||
|
if (doc.oldPower) { timeline.push(doc.oldPower); } else { timeline.push(0); }
|
||||||
|
timeline.push(time);
|
||||||
|
timeline.push(doc.power);
|
||||||
|
previousPower = doc.power;
|
||||||
|
} else {
|
||||||
|
// Delta element
|
||||||
|
if ((previousPower != doc.power) && ((doc.time - time) > 60000)) { // To boost speed, any blocks less than a minute get approximated.
|
||||||
|
// Create a new timeline
|
||||||
|
timeline.push(doc.time - time);
|
||||||
|
timeline.push(doc.power);
|
||||||
|
time = doc.time;
|
||||||
|
previousPower = doc.power;
|
||||||
|
} else {
|
||||||
|
// Extend the previous timeline
|
||||||
|
if ((timeline.length >= 6) && (timeline[timeline.length - 3] == doc.power)) { // We can merge the block with the previous block
|
||||||
|
timeline[timeline.length - 4] += (timeline[timeline.length - 2] + (doc.time - time));
|
||||||
|
timeline.pop();
|
||||||
|
timeline.pop();
|
||||||
|
} else { // Extend the last block in the timeline
|
||||||
|
timeline[timeline.length - 2] += (doc.time - time);
|
||||||
|
timeline[timeline.length - 1] = doc.power;
|
||||||
|
}
|
||||||
|
time = doc.time;
|
||||||
|
previousPower = doc.power;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: timeline }));
|
||||||
|
} else {
|
||||||
|
// No records found, send current state if we have it
|
||||||
|
var state = obj.parent.parent.GetConnectivityState(command.nodeid);
|
||||||
|
if (state != null) { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: [state.powerState, Date.now(), state.powerState] })); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'files':
|
||||||
|
{
|
||||||
|
// Send the full list of server files to the browser app
|
||||||
|
if ((user.siteadmin & 8) != 0) { updateUserFiles(user, ws, domain); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'fileoperation':
|
||||||
|
{
|
||||||
|
// Check permissions
|
||||||
|
if ((user.siteadmin & 8) != 0) {
|
||||||
|
// Perform a file operation (Create Folder, Delete Folder, Delete File...)
|
||||||
|
if ((command.path != null) && (typeof command.path == 'object') && command.path.length > 0) {
|
||||||
|
var rootfolder = command.path[0];
|
||||||
|
var rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
|
||||||
|
if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
|
||||||
|
var path = obj.path.join(obj.filespath, domainx + "/" + rootfoldersplit[0] + "-" + rootfoldersplit[2]);
|
||||||
|
for (var i = 1; i < command.path.length; i++) { if (obj.common.IsFilenameValid(command.path[i]) == false) { path = null; break; } path += ("/" + command.path[i]); }
|
||||||
|
if (path == null) break;
|
||||||
|
|
||||||
|
if ((command.fileop == 'createfolder') && (obj.common.IsFilenameValid(command.newfolder) == true)) { try { obj.fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { } } // Create a new folder
|
||||||
|
else if (command.fileop == 'delete') { for (var i in command.delfiles) { if (obj.common.IsFilenameValid(command.delfiles[i]) == true) { var fullpath = path + "/" + command.delfiles[i]; try { obj.fs.rmdirSync(fullpath); } catch (e) { try { obj.fs.unlinkSync(fullpath); } catch (e) { } } } } } // Delete
|
||||||
|
else if ((command.fileop == 'rename') && (obj.common.IsFilenameValid(command.oldname) == true) && (obj.common.IsFilenameValid(command.newname) == true)) { try { obj.fs.renameSync(path + "/" + command.oldname, path + "/" + command.newname); } catch (e) { } } // Rename
|
||||||
|
|
||||||
|
obj.parent.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'msg':
|
||||||
|
{
|
||||||
|
// Route a message.
|
||||||
|
// This this command has a nodeid, that is the target.
|
||||||
|
if (command.nodeid != null) {
|
||||||
|
var splitnodeid = command.nodeid.split('/');
|
||||||
|
// Check that we are in the same domain and the user has rights over this node.
|
||||||
|
if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domain.id)) {
|
||||||
|
// See if the node is connected
|
||||||
|
var agent = obj.parent.wsagents[command.nodeid];
|
||||||
|
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 & 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
|
||||||
|
delete command.nodeid; // Remove the nodeid since it's implyed.
|
||||||
|
agent.send(JSON.stringify(command));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check if a peer server is connected to this agent
|
||||||
|
var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
|
||||||
|
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 & 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
|
||||||
|
obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'events':
|
||||||
|
{
|
||||||
|
// Send the list of events for this session
|
||||||
|
obj.db.GetEvents(user.subscriptions, domain.id, function (err, docs) { if (err != null) return; ws.send(JSON.stringify({ action: 'events', events: docs })); });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'clearevents':
|
||||||
|
{
|
||||||
|
// Delete all events
|
||||||
|
if (user.siteadmin != 0xFFFFFFFF) break;
|
||||||
|
obj.db.RemoveAllEvents(domain.id);
|
||||||
|
obj.parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id })
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'users':
|
||||||
|
{
|
||||||
|
// Request a list of all users
|
||||||
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
|
var docs = [];
|
||||||
|
for (var i in obj.parent.users) { if ((obj.parent.users[i].domain == domain.id) && (obj.parent.users[i].name != '~')) { docs.push(obj.parent.users[i]); } }
|
||||||
|
ws.send(JSON.stringify({ action: 'users', users: docs }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'wssessioncount':
|
||||||
|
{
|
||||||
|
// Request a list of all web socket user session count
|
||||||
|
var wssessions = {};
|
||||||
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
|
if (obj.parent.parent.multiServer == null) {
|
||||||
|
// No peering, use simple session counting
|
||||||
|
for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
|
||||||
|
} else {
|
||||||
|
// We have peer servers, use more complex session counting
|
||||||
|
for (var userid in obj.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.sessionsCount[userid]; } }
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions })); // wssessions is: userid --> count
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'deleteuser':
|
||||||
|
{
|
||||||
|
// Delete a user account
|
||||||
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
|
var delusername = command.username, deluserid = command.userid, deluser = obj.parent.users[deluserid];
|
||||||
|
if ((deluser.siteadmin != null) && (deluser.siteadmin > 0) && (user.siteadmin != 0xFFFFFFFF)) break; // Need full admin to remote another administrator
|
||||||
|
if ((deluserid.split('/').length != 3) || (deluserid.split('/')[1] != domain.id)) break; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Delete all files on the server for this account
|
||||||
|
try {
|
||||||
|
var deluserpath = obj.parent.getServerRootFilePath(deluser);
|
||||||
|
if (deluserpath != null) { obj.parent.deleteFolderRec(deluserpath); }
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
obj.db.Remove(deluserid);
|
||||||
|
delete obj.parent.users[deluserid];
|
||||||
|
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: delusername, action: 'accountremove', msg: 'Account removed', domain: domain.id })
|
||||||
|
obj.parent.parent.DispatchEvent([deluserid], obj, 'close');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'adduser':
|
||||||
|
{
|
||||||
|
// Add a new user account
|
||||||
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
|
var newusername = command.username, newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase();
|
||||||
|
if (newusername == '~') break; // This is a reserved user name
|
||||||
|
if (!obj.parent.users[newuserid]) {
|
||||||
|
var newuser = { type: 'user', _id: newuserid, name: newusername, email: command.email, creation: Date.now(), domain: domain.id };
|
||||||
|
obj.parent.users[newuserid] = newuser;
|
||||||
|
// Create a user, generate a salt and hash the password
|
||||||
|
obj.parent.hash(command.pass, function (err, salt, hash) {
|
||||||
|
if (err) throw err;
|
||||||
|
newuser.salt = salt;
|
||||||
|
newuser.hash = hash;
|
||||||
|
obj.db.SetUser(newuser);
|
||||||
|
var newuser2 = obj.common.Clone(newuser);
|
||||||
|
if (newuser2.subscriptions) { delete newuser2.subscriptions; }
|
||||||
|
if (newuser2.salt) { delete newuser2.salt; }
|
||||||
|
if (newuser2.hash) { delete newuser2.hash; }
|
||||||
|
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: newusername, account: newuser2, action: 'accountcreate', msg: 'Account created, email is ' + command.email, domain: domain.id })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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 = obj.parent.users[chguserid], change = 0;
|
||||||
|
if (chguser) {
|
||||||
|
if (command.email && chguser.email != command.email) { chguser.email = command.email; change = 1; }
|
||||||
|
if (command.quota != chguser.quota) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
|
||||||
|
if ((user.siteadmin == 0xFFFFFFFF) && (command.siteadmin != null) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
|
||||||
|
if (change == 1) {
|
||||||
|
obj.db.Set(chguser);
|
||||||
|
obj.parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
|
||||||
|
var chguser2 = obj.common.Clone(chguser);
|
||||||
|
delete chguser2.salt;
|
||||||
|
delete chguser2.hash;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: chguser2, action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'serverversion':
|
||||||
|
{
|
||||||
|
// Check the server version
|
||||||
|
if ((user.siteadmin & 16) == 0) break;
|
||||||
|
obj.parent.parent.getLatestServerVersion(function (currentVersion, latestVersion) { ws.send(JSON.stringify({ action: 'serverversion', current: currentVersion, latest: latestVersion })); });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'serverupdate':
|
||||||
|
{
|
||||||
|
// Perform server update
|
||||||
|
if ((user.siteadmin & 16) == 0) break;
|
||||||
|
obj.parent.parent.performServerUpdate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'createmesh':
|
||||||
|
{
|
||||||
|
// Create mesh
|
||||||
|
// TODO: Right now, we only create type 1 Agent-less Intel AMT mesh, or type 2 Agent mesh
|
||||||
|
if ((command.meshtype == 1) || (command.meshtype == 2)) {
|
||||||
|
// Create a type 1 agent-less Intel AMT mesh.
|
||||||
|
obj.crypto.randomBytes(48, function (err, buf) {
|
||||||
|
var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
|
||||||
|
var links = {}
|
||||||
|
links[user._id] = { name: user.name, rights: 0xFFFFFFFF };
|
||||||
|
var mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
|
||||||
|
obj.db.Set(mesh);
|
||||||
|
obj.parent.meshes[meshid] = mesh;
|
||||||
|
obj.parent.parent.AddEventDispatch([meshid], ws);
|
||||||
|
if (user.links == null) user.links = {};
|
||||||
|
user.links[meshid] = { rights: 0xFFFFFFFF };
|
||||||
|
user.subscriptions = obj.parent.subscribe(user._id, ws);
|
||||||
|
obj.db.SetUser(user);
|
||||||
|
obj.parent.parent.DispatchEvent(['*', meshid, user._id], obj, { etype: 'mesh', username: user.name, meshid: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, action: 'createmesh', links: links, msg: 'Mesh created: ' + command.meshname, domain: domain.id })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'deletemesh':
|
||||||
|
{
|
||||||
|
// Delete a mesh and all computers within it
|
||||||
|
obj.db.Get(command.meshid, function (err, meshes) {
|
||||||
|
if (meshes.length != 1) return;
|
||||||
|
var mesh = meshes[0];
|
||||||
|
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) return;
|
||||||
|
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Fire the removal event first, because after this, the event will not route
|
||||||
|
obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'mesh', username: user.name, meshid: command.meshid, name: command.meshname, action: 'deletemesh', msg: 'Mesh deleted: ' + command.meshname, domain: domain.id })
|
||||||
|
|
||||||
|
// Remove all user links to this mesh
|
||||||
|
for (var i in meshes) {
|
||||||
|
var links = meshes[i].links;
|
||||||
|
for (var j in links) {
|
||||||
|
var xuser = obj.parent.users[j];
|
||||||
|
delete xuser.links[meshes[i]._id];
|
||||||
|
obj.db.Set(xuser);
|
||||||
|
obj.parent.parent.DispatchEvent([xuser._id], obj, 'resubscribe');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all files on the server for this mesh
|
||||||
|
try {
|
||||||
|
var meshpath = getServerRootFilePath(mesh);
|
||||||
|
if (meshpath != null) { deleteFolderRec(meshpath); }
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
obj.parent.parent.RemoveEventDispatchId(command.meshid); // Remove all subscriptions to this mesh
|
||||||
|
obj.db.RemoveMesh(command.meshid); // Remove mesh from database
|
||||||
|
delete obj.parent.meshes[command.meshid]; // Remove mesh from memory
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'editmesh':
|
||||||
|
{
|
||||||
|
// Change the name or description of a mesh
|
||||||
|
var mesh = obj.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;
|
||||||
|
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
if (command.meshname && command.meshname != '' && command.meshname != mesh.name) { change = 'Mesh name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
|
||||||
|
if (command.desc != null && command.desc != mesh.desc) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
|
||||||
|
if (change != '') { obj.db.Set(mesh); obj.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, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }) }
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'addmeshuser':
|
||||||
|
{
|
||||||
|
// Check if the user exists
|
||||||
|
var newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase(), newuser = obj.parent.users[newuserid];
|
||||||
|
if (newuser == null) {
|
||||||
|
// TODO: Send error back, user not found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the mesh
|
||||||
|
var mesh = obj.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 & 2) == 0)) return;
|
||||||
|
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Add mesh to user
|
||||||
|
if (newuser.links == null) newuser.links = {};
|
||||||
|
newuser.links[command.meshid] = { rights: command.meshadmin };
|
||||||
|
obj.db.Set(newuser);
|
||||||
|
obj.parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
|
||||||
|
|
||||||
|
// Add a user to the mesh
|
||||||
|
mesh.links[newuserid] = { name: command.username, rights: command.meshadmin };
|
||||||
|
obj.db.Set(mesh);
|
||||||
|
|
||||||
|
// Notify mesh change
|
||||||
|
var change = 'Added user ' + command.username + ' to mesh ' + mesh.name;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, { etype: 'mesh', username: user.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'removemeshuser':
|
||||||
|
{
|
||||||
|
if ((command.userid.split('/').length != 3) || (command.userid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Check if the user exists
|
||||||
|
var deluserid = command.userid, deluser = obj.parent.users[deluserid];
|
||||||
|
if (deluser == null) {
|
||||||
|
// TODO: Send error back, user not found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the mesh
|
||||||
|
var mesh = obj.parent.meshes[command.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
|
||||||
|
|
||||||
|
// Remove mesh from user
|
||||||
|
if (deluser.links != null && deluser.links[command.meshid] != null) {
|
||||||
|
var delmeshrights = deluser.links[command.meshid].rights;
|
||||||
|
if ((delmeshrights == 0xFFFFFFFF) && (mesh.links[user._id].rights != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin
|
||||||
|
delete deluser.links[command.meshid];
|
||||||
|
obj.db.Set(deluser);
|
||||||
|
obj.parent.parent.DispatchEvent([deluser._id], obj, 'resubscribe');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove user from the mesh
|
||||||
|
if (mesh.links[command.userid] != null) {
|
||||||
|
delete mesh.links[command.userid];
|
||||||
|
obj.db.Set(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify mesh change
|
||||||
|
var change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'addamtdevice':
|
||||||
|
{
|
||||||
|
if (obj.args.wanonly == true) return; // This is a WAN-only server, local Intel AMT computers can't be added
|
||||||
|
|
||||||
|
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Get the mesh
|
||||||
|
var mesh = obj.parent.meshes[command.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
|
||||||
|
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
|
||||||
|
|
||||||
|
// Create a new nodeid
|
||||||
|
obj.crypto.randomBytes(48, function (err, buf) {
|
||||||
|
// create the new node
|
||||||
|
var nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
|
||||||
|
var device = { type: 'node', mtype: 1, _id: nodeid, meshid: command.meshid, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: parseInt(command.amttls) } };
|
||||||
|
obj.db.Set(device);
|
||||||
|
|
||||||
|
// Event the new node
|
||||||
|
var device2 = obj.common.Clone(device);
|
||||||
|
delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
|
var change = 'Added device ' + command.devicename + ' to mesh ' + mesh.name;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', username: user.name, action: 'addnode', node: device2, msg: change, domain: domain.id })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'scanamtdevice':
|
||||||
|
{
|
||||||
|
if (obj.args.wanonly == true) return; // This is a WAN-only server, this type of scanning is not allowed.
|
||||||
|
|
||||||
|
// Ask the RMCP scanning to scan a range of IP addresses
|
||||||
|
if (obj.parent.parent.amtScanner) {
|
||||||
|
if (obj.parent.parent.amtScanner.performRangeScan(ws.userid, command.range) == false) {
|
||||||
|
obj.parent.parent.DispatchEvent(['*', ws.userid], obj, { action: 'scanamtdevice', range: command.range, results: null, nolog: 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'removedevices':
|
||||||
|
{
|
||||||
|
for (var i in command.nodeids) {
|
||||||
|
var nodeid = command.nodeids[i];
|
||||||
|
if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Get the device
|
||||||
|
obj.db.Get(nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) return;
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.parent.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
|
||||||
|
|
||||||
|
// Delete this node including network interface information and events
|
||||||
|
obj.db.Remove(node._id);
|
||||||
|
obj.db.Remove('if' + node._id);
|
||||||
|
|
||||||
|
// Event node deletion
|
||||||
|
var change = 'Removed device ' + node.name + ' from mesh ' + mesh.name;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: change, domain: domain.id })
|
||||||
|
|
||||||
|
// Disconnect all connections if needed
|
||||||
|
var state = obj.parent.parent.GetConnectivityState(command.nodeid);
|
||||||
|
if ((state != null) && (state.connectivity != null)) {
|
||||||
|
if ((state.connectivity & 1) != 0) { obj.parent.wsagents[command.nodeid].close(); } // Disconnect mesh agent
|
||||||
|
if ((state.connectivity & 2) != 0) { obj.parent.parent.mpsserver.close(obj.parent.parent.mpsserver.ciraConnections[command.nodeid]); } // Disconnect CIRA connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'wakedevices':
|
||||||
|
{
|
||||||
|
// TODO: INPUT VALIDATION!!!
|
||||||
|
// TODO: We can optimize this a lot.
|
||||||
|
// - We should get a full list of all MAC's to wake first.
|
||||||
|
// - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
|
||||||
|
for (var i in command.nodeids) {
|
||||||
|
var nodeid = command.nodeids[i], wakeActions = 0;
|
||||||
|
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||||
|
// Get the device
|
||||||
|
obj.db.Get(nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) return;
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.parent.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 64) != 0)) {
|
||||||
|
|
||||||
|
// Get the device interface information
|
||||||
|
obj.db.Get('if' + node._id, function (err, nodeifs) {
|
||||||
|
if (nodeifs.length == 1) {
|
||||||
|
var nodeif = nodeifs[0];
|
||||||
|
var macs = [];
|
||||||
|
for (var i in nodeif.netif) { if (nodeif.netif[i].mac) { macs.push(nodeif.netif[i].mac); } }
|
||||||
|
|
||||||
|
// Have the server send a wake-on-lan packet (Will not work in WAN-only)
|
||||||
|
if (obj.parent.parent.meshScanner != null) { obj.parent.parent.meshScanner.wakeOnLan(macs); wakeActions++; }
|
||||||
|
|
||||||
|
// Get the list of mesh this user as access to
|
||||||
|
var targetMeshes = [];
|
||||||
|
for (var i in user.links) { targetMeshes.push(i); }
|
||||||
|
|
||||||
|
// Go thru all the connected agents and send wake-on-lan on all the ones in the target mesh list
|
||||||
|
for (var i in obj.parent.wsagents) {
|
||||||
|
var agent = obj.parent.wsagents[i];
|
||||||
|
if ((targetMeshes.indexOf(agent.dbMeshKey) >= 0) && (agent.authenticated == 2)) {
|
||||||
|
//console.log('Asking agent ' + agent.dbNodeKey + ' to wake ' + macs.join(','));
|
||||||
|
agent.send(JSON.stringify({ action: 'wakeonlan', macs: macs }));
|
||||||
|
wakeActions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Confirm we may be doing something (TODO)
|
||||||
|
ws.send(JSON.stringify({ action: 'wakedevices' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'poweraction':
|
||||||
|
{
|
||||||
|
// TODO: INPUT VALIDATION!!!
|
||||||
|
for (var i in command.nodeids) {
|
||||||
|
var nodeid = command.nodeids[i], powerActions = 0;
|
||||||
|
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||||
|
// Get the device
|
||||||
|
obj.db.Get(nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) return;
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.parent.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
|
||||||
|
|
||||||
|
// Get this device
|
||||||
|
var agent = obj.parent.wsagents[node._id];
|
||||||
|
if (agent != null) {
|
||||||
|
// Send the power command
|
||||||
|
agent.send(JSON.stringify({ action: 'poweraction', actiontype: command.actiontype }));
|
||||||
|
powerActions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Confirm we may be doing something (TODO)
|
||||||
|
ws.send(JSON.stringify({ action: 'poweraction' }));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'getnetworkinfo':
|
||||||
|
{
|
||||||
|
// Argument validation
|
||||||
|
if ((command.nodeid == null) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
|
||||||
|
// Get the device
|
||||||
|
obj.db.Get(command.nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.parent.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
|
||||||
|
|
||||||
|
// Get network information about this node
|
||||||
|
obj.db.Get('if' + command.nodeid, function (err, netinfos) {
|
||||||
|
if (netinfos.length != 1) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
|
||||||
|
var netinfo = netinfos[0];
|
||||||
|
ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, updateTime: netinfo.updateTime, netif: netinfo.netif }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'changedevice':
|
||||||
|
{
|
||||||
|
// Argument validation
|
||||||
|
if ((command.nodeid == null) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||||
|
if ((command.userloc) && (command.userloc.length != 2) && (command.userloc.length != 0)) return;
|
||||||
|
|
||||||
|
// Change the device
|
||||||
|
obj.db.Get(command.nodeid, function (err, nodes) {
|
||||||
|
if (nodes.length != 1) return;
|
||||||
|
var node = nodes[0];
|
||||||
|
|
||||||
|
// Get the mesh for this device
|
||||||
|
var mesh = obj.parent.meshes[node.meshid];
|
||||||
|
if (mesh) {
|
||||||
|
// Check if this user has rights to do this
|
||||||
|
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
|
||||||
|
|
||||||
|
// Ready the node change event
|
||||||
|
var changes = [], change = 0, event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
|
||||||
|
event.msg = ": ";
|
||||||
|
|
||||||
|
// Look for a change
|
||||||
|
if (command.icon && (command.icon != node.icon)) { change = 1; node.icon = command.icon; changes.push('icon'); }
|
||||||
|
if (command.name && (command.name != node.name)) { change = 1; node.name = command.name; changes.push('name'); }
|
||||||
|
if (command.host && (command.host != node.host)) { change = 1; node.host = command.host; changes.push('host'); }
|
||||||
|
if (command.userloc && ((node.userloc == null) || (command.userloc[0] != node.userloc[0]) || (command.userloc[1] != node.userloc[1]))) {
|
||||||
|
change = 1;
|
||||||
|
if ((command.userloc.length == 0) && (node.userloc)) {
|
||||||
|
delete node.userloc;
|
||||||
|
changes.push('location removed');
|
||||||
|
} else {
|
||||||
|
command.userloc.push((Math.floor((new Date()) / 1000)));
|
||||||
|
node.userloc = command.userloc.join(',');
|
||||||
|
changes.push('location');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (command.desc != null && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); }
|
||||||
|
if (command.intelamt != null) {
|
||||||
|
if ((command.intelamt.user != null) && (command.intelamt.pass != undefined) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; changes.push('Intel AMT credentials'); }
|
||||||
|
if (command.intelamt.tls && (command.intelamt.tls != node.intelamt.tls)) { change = 1; node.intelamt.tls = command.intelamt.tls; changes.push('Intel AMT TLS'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change == 1) {
|
||||||
|
// Save the node
|
||||||
|
obj.db.Set(node);
|
||||||
|
|
||||||
|
// Event the node change
|
||||||
|
event.msg = 'Changed device ' + node.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ');
|
||||||
|
var node2 = obj.common.Clone(node);
|
||||||
|
if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
|
event.node = node2;
|
||||||
|
obj.parent.parent.DispatchEvent(['*', node.meshid], obj, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'uploadagentcore':
|
||||||
|
{
|
||||||
|
if (user.siteadmin != 0xFFFFFFFF) break;
|
||||||
|
if (command.path) {
|
||||||
|
if (command.path == '*') {
|
||||||
|
// Update the server default core and send a core hash request
|
||||||
|
// Load default mesh agent core if present, then perform a core update
|
||||||
|
obj.parent.parent.updateMeshCore(function () { obj.parent.sendMeshAgentCore(user, domain, command.nodeid, '*'); });
|
||||||
|
} else {
|
||||||
|
// Send a mesh agent core to the mesh agent
|
||||||
|
var file = obj.parent.getServerFilePath(user, domain, command.path);
|
||||||
|
if (file != null) {
|
||||||
|
obj.parent.readEntireTextFile(file.fullpath, function (data) {
|
||||||
|
if (data != null) {
|
||||||
|
data = obj.common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
|
||||||
|
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Clear the mesh agent core on the mesh agent
|
||||||
|
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'agentdisconnect':
|
||||||
|
{
|
||||||
|
// Force mesh agent disconnection
|
||||||
|
forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'close':
|
||||||
|
{
|
||||||
|
// Close the web socket session
|
||||||
|
if (obj.req.session && obj.req.session.ws && obj.req.session.ws == ws) delete obj.req.session.ws;
|
||||||
|
try { ws.close(); } catch (e) { }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'getcookie':
|
||||||
|
{
|
||||||
|
// Check if this user has rights on this nodeid
|
||||||
|
obj.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) {
|
||||||
|
var meshlinks = user.links[nodes[0].meshid];
|
||||||
|
if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.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; }
|
||||||
|
if (command.tcpaddr) { cookieContent.tcpaddr = command.tcpaddr; } // Indicates the browser want to agent to TCP connect to a remote address
|
||||||
|
if (command.tcpport) { cookieContent.tcpport = command.tcpport; } // Indicates the browser want to agent to TCP connect to a remote port
|
||||||
|
command.cookie = obj.parent.encodeCookie(cookieContent);
|
||||||
|
ws.send(JSON.stringify(command));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If error, do nothing
|
||||||
|
ws.on('error', function (err) { console.log(err); });
|
||||||
|
|
||||||
|
// If the web socket is closed
|
||||||
|
ws.on('close', function (req) {
|
||||||
|
obj.parent.parent.RemoveAllEventDispatch(ws);
|
||||||
|
if (req.session && req.session.ws && req.session.ws == ws) { delete req.session.ws; }
|
||||||
|
if (obj.parent.wssessions2[ws.sessionId]) { delete obj.parent.wssessions2[ws.sessionId]; }
|
||||||
|
if (obj.parent.wssessions[ws.userid]) {
|
||||||
|
var i = obj.parent.wssessions[ws.userid].indexOf(ws);
|
||||||
|
if (i >= 0) {
|
||||||
|
obj.parent.wssessions[ws.userid].splice(i, 1);
|
||||||
|
var user = obj.parent.users[ws.userid];
|
||||||
|
if (user) {
|
||||||
|
if (obj.parent.parent.multiServer == null) {
|
||||||
|
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[ws.userid].length, nolog: 1, domain: obj.domain.id })
|
||||||
|
} else {
|
||||||
|
obj.parent.recountSessions(ws.sessionId); // Recount sessions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj.parent.wssessions[ws.userid].length == 0) { delete obj.parent.wssessions[ws.userid]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have peer servers, inform them of the disconnected session
|
||||||
|
if (obj.parent.parent.multiServer != null) { obj.parent.parent.multiServer.DispatchMessage({ action: 'sessionEnd', sessionid: ws.sessionId }); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send user information to web socket, this is the first thing we send
|
||||||
|
var userinfo = obj.common.Clone(obj.parent.users[req.session.userid]);
|
||||||
|
delete userinfo.salt;
|
||||||
|
delete userinfo.hash;
|
||||||
|
ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo }));
|
||||||
|
|
||||||
|
// Next, send server information
|
||||||
|
if (obj.args.notls == true) {
|
||||||
|
ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, port: obj.args.port, https: false } }));
|
||||||
|
} else {
|
||||||
|
ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, redirport: obj.args.redirport, port: obj.args.port, https: true } }));
|
||||||
|
}
|
||||||
|
} catch (e) { console.log(e); }
|
||||||
|
|
||||||
|
// Return the maximum number of bytes allowed in the user account "My Files".
|
||||||
|
function getQuota(objid, domain) {
|
||||||
|
if (objid == null) return 0;
|
||||||
|
if (objid.startsWith('user/')) {
|
||||||
|
var user = obj.parent.users[objid];
|
||||||
|
if (user == null) return 0;
|
||||||
|
if ((user.quota != null) && (typeof user.quota == 'number')) { return user.quota; }
|
||||||
|
if ((domain != null) && (domain.userQuota != null) && (typeof domain.userQuota == 'number')) { return domain.userQuota; }
|
||||||
|
return 1048576; // By default, the server will have a 1 meg limit on user accounts
|
||||||
|
} else if (objid.startsWith('mesh/')) {
|
||||||
|
var mesh = obj.parent.meshes[objid];
|
||||||
|
if (mesh == null) return 0;
|
||||||
|
if ((mesh.quota != null) && (typeof mesh.quota == 'number')) { return mesh.quota; }
|
||||||
|
if ((domain != null) && (domain.meshQuota != null) && (typeof domain.meshQuota == 'number')) { return domain.meshQuota; }
|
||||||
|
return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a "user/domain/userid/path/file" format and return the actual server disk file path if access is allowed
|
||||||
|
function getServerFilePath(user, domain, path) {
|
||||||
|
var splitpath = path.split('/'), serverpath = obj.path.join(obj.filespath, 'domain'), filename = '';
|
||||||
|
if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
|
||||||
|
var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
|
||||||
|
if (splitpath[0] == 'user' && (objid != user._id)) return null; // User validation, only self allowed
|
||||||
|
if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == null) || (link.rights == null) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
|
||||||
|
if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
|
||||||
|
serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
|
||||||
|
for (var i = 3; i < splitpath.length; i++) { if (obj.common.IsFilenameValid(splitpath[i]) == true) { serverpath += '/' + splitpath[i]; filename = splitpath[i]; } else { return null; } } // Check that each folder is correct
|
||||||
|
var fullpath = obj.path.resolve(obj.filespath, serverpath), quota = 0;
|
||||||
|
return { fullpath: fullpath, path: serverpath, name: filename, quota: getQuota(objid, domain) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the folder and all sub-folders and serialize that into json.
|
||||||
|
function readFilesRec(path) {
|
||||||
|
var r = {}, dir = obj.fs.readdirSync(path);
|
||||||
|
for (var i in dir) {
|
||||||
|
var f = { t: 3, d: 111 };
|
||||||
|
var stat = obj.fs.statSync(path + '/' + dir[i])
|
||||||
|
if ((stat.mode & 0x004000) == 0) { f.s = stat.size; f.d = stat.mtime.getTime(); } else { f.t = 2; f.f = readFilesRec(path + '/' + dir[i]); }
|
||||||
|
r[dir[i]] = f;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUserFiles(user, ws, domain) {
|
||||||
|
// Request the list of server files
|
||||||
|
var files = { action: 'files', filetree: { n: 'Root', f: {} } };
|
||||||
|
|
||||||
|
// Add user files
|
||||||
|
files.filetree.f[user._id] = { t: 1, n: 'My Files', f: {} };
|
||||||
|
files.filetree.f[user._id].maxbytes = getQuota(user._id, domain);
|
||||||
|
var usersplit = user._id.split('/'), domainx = 'domain';
|
||||||
|
if (usersplit[1].length > 0) domainx = 'domain-' + usersplit[1];
|
||||||
|
|
||||||
|
// Read all files recursively
|
||||||
|
try {
|
||||||
|
files.filetree.f[user._id].f = readFilesRec(obj.path.join(obj.parent.filespath, domainx + "/user-" + usersplit[2]));
|
||||||
|
} catch (e) {
|
||||||
|
// Got an error, try to create all the folders and try again...
|
||||||
|
try { obj.fs.mkdirSync(obj.parent.filespath); } catch (e) { }
|
||||||
|
try { obj.fs.mkdirSync(obj.path.join(obj.parent.filespath, domainx)); } catch (e) { }
|
||||||
|
try { obj.fs.mkdirSync(obj.path.join(obj.parent.filespath, domainx + "/user-" + usersplit[2])); } catch (e) { }
|
||||||
|
try { obj.fs.mkdirSync(obj.path.join(obj.parent.filespath, domainx + "/user-" + usersplit[2] + "/Public")); } catch (e) { }
|
||||||
|
try { files.filetree.f[user._id].f = readFilesRec(obj.parent.path.join(obj.parent.filespath, domainx + "/user-" + usersplit[2])); } catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add files for each mesh
|
||||||
|
for (var i in user.links) {
|
||||||
|
if ((user.links[i].rights & 32) != 0) { // Check that we have file permissions
|
||||||
|
var mesh = obj.parent.meshes[i];
|
||||||
|
if (mesh) {
|
||||||
|
var meshsplit = mesh._id.split('/');
|
||||||
|
files.filetree.f[mesh._id] = { t: 1, n: mesh.name, f: {} };
|
||||||
|
files.filetree.f[mesh._id].maxbytes = getQuota(mesh._id, domain);
|
||||||
|
|
||||||
|
// Read all files recursively
|
||||||
|
try {
|
||||||
|
files.filetree.f[mesh._id].f = readFilesRec(obj.parent.path.join(__dirname, "files/" + domainx + "/mesh-" + meshsplit[2]));
|
||||||
|
} catch (e) {
|
||||||
|
// Got an error, try to create all the folders and try again...
|
||||||
|
try { obj.fs.mkdirSync(obj.parent.filespath); } catch (e) { }
|
||||||
|
try { obj.fs.mkdirSync(obj.parent.path.join(obj.parent.filespath, domainx)); } catch (e) { }
|
||||||
|
try { obj.fs.mkdirSync(obj.parent.path.join(obj.parent.filespath, domainx + "/mesh-" + meshsplit[2])); } catch (e) { }
|
||||||
|
try { files.filetree.f[mesh._id].f = readFilesRec(obj.parent.path.join(obj.parent.filespath, domainx + "/mesh-" + meshsplit[2])); } catch (e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond
|
||||||
|
ws.send(JSON.stringify(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
@ -127,14 +127,14 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
|
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
|
||||||
|
|
||||||
// Send information about our server to the peer
|
// Send information about our server to the peer
|
||||||
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
||||||
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
// Server confirmed authentication, we are allowed to send commands to the server
|
// Server confirmed authentication, we are allowed to send commands to the server
|
||||||
obj.connectionState |= 8;
|
obj.connectionState |= 8;
|
||||||
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
||||||
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -313,7 +313,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
function completePeerServerConnection() {
|
function completePeerServerConnection() {
|
||||||
if (obj.authenticated != 1) return;
|
if (obj.authenticated != 1) return;
|
||||||
obj.send(obj.common.ShortToStr(4));
|
obj.send(obj.common.ShortToStr(4));
|
||||||
obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }));
|
obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }));
|
||||||
obj.authenticated = 2;
|
obj.authenticated = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,9 +371,6 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
if (obj.serverid == null) { obj.serverid = require("os").hostname(); }
|
if (obj.serverid == null) { obj.serverid = require("os").hostname(); }
|
||||||
if (obj.parent.config.peers.servers[obj.serverid] == null) { console.log("Error: Unable to peer with other servers, \"" + obj.serverid + "\" not present in peer servers list."); return null; }
|
if (obj.parent.config.peers.servers[obj.serverid] == null) { console.log("Error: Unable to peer with other servers, \"" + obj.serverid + "\" not present in peer servers list."); return null; }
|
||||||
|
|
||||||
// Generate a cryptographic key used to encode and decode cookies
|
|
||||||
obj.generateCookieKey = function () { return new Buffer(obj.crypto.randomBytes(32), 'binary'); }
|
|
||||||
|
|
||||||
// Return the private key of a peer server
|
// Return the private key of a peer server
|
||||||
obj.getServerCookieKey = function (serverid) {
|
obj.getServerCookieKey = function (serverid) {
|
||||||
var server = obj.peerServers[serverid];
|
var server = obj.peerServers[serverid];
|
||||||
@ -381,32 +378,6 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode an object as a cookie using a key. (key must be 32 bytes long)
|
|
||||||
obj.encodeCookie = function (o, key) {
|
|
||||||
try {
|
|
||||||
if (key == null) { key = obj.serverKey; }
|
|
||||||
o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time
|
|
||||||
var iv = new Buffer(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
||||||
var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
|
|
||||||
return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
|
||||||
} catch (e) { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode a cookie back into an object using a key. Return null if it's not a valid cookie. (key must be 32 bytes long)
|
|
||||||
obj.decodeCookie = function (cookie, key) {
|
|
||||||
try {
|
|
||||||
if (key == null) { key = obj.serverKey; }
|
|
||||||
cookie = new Buffer(cookie.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64');
|
|
||||||
var decipher = obj.crypto.createDecipheriv('aes-256-gcm', key, cookie.slice(0, 12));
|
|
||||||
decipher.setAuthTag(cookie.slice(12, 16));
|
|
||||||
var o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8'));
|
|
||||||
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; }
|
|
||||||
o.time = o.time * 1000; // Decode the cookie creation time
|
|
||||||
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created
|
|
||||||
return o;
|
|
||||||
} catch (e) { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch an event to all other MeshCentral2 peer servers
|
// Dispatch an event to all other MeshCentral2 peer servers
|
||||||
obj.DispatchEvent = function (ids, source, event) {
|
obj.DispatchEvent = function (ids, source, event) {
|
||||||
var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event });
|
var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event });
|
||||||
@ -658,7 +629,6 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
return peerTunnel;
|
return peerTunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.serverKey = obj.generateCookieKey();
|
|
||||||
setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
|
setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.7" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<description asmv2:publisher="Meshcentral.com" asmv2:product="Meshcentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<deployment install="false" mapFileExtensions="true" trustURLParameters="true" />
|
||||||
|
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
|
||||||
|
</compatibleFrameworks>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_7\MeshMiniRouter.exe.manifest" size="4711">
|
||||||
|
<assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.7" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>VsPkLYR71TSqI8oGBBeXzb5hGi4R2xtQaGQJ0zmsTic=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</asmv1:assembly>
|
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<section name="MeshMiniRouterTool.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||||
|
<section name="MeshMiniRouterTool.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||||
|
<section name="MeshNetworkRouterTool.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
<userSettings>
|
||||||
|
<MeshMiniRouterTool.Properties.Settings>
|
||||||
|
<setting name="PuttyPath" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
<setting name="Upgraded" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="UltraVncPath" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
<setting name="HybridCloudManager" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
<setting name="TightVncPath" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
<setting name="WinSCPPath" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
</MeshMiniRouterTool.Properties.Settings>
|
||||||
|
<MeshMiniRouterTool.Settings1>
|
||||||
|
<setting name="puttypath" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
</MeshMiniRouterTool.Settings1>
|
||||||
|
<MeshNetworkRouterTool.Properties.Settings>
|
||||||
|
<setting name="Server" serializeAs="String">
|
||||||
|
<value/>
|
||||||
|
</setting>
|
||||||
|
</MeshNetworkRouterTool.Properties.Settings>
|
||||||
|
</userSettings>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
|
Binary file not shown.
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<asmv1:assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.7" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<description asmv2:iconFile="MeshMiniRouter.ico" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<application />
|
||||||
|
<entryPoint>
|
||||||
|
<assemblyIdentity name="MeshMiniRouter" version="1.0.6505.20092" language="neutral" processorArchitecture="msil" />
|
||||||
|
<commandLine file="MeshMiniRouter.exe" parameters="" />
|
||||||
|
</entryPoint>
|
||||||
|
<trustInfo>
|
||||||
|
<security>
|
||||||
|
<applicationRequestMinimum>
|
||||||
|
<PermissionSet version="1" class="System.Security.NamedPermissionSet" Name="Internet" Description="Default rights given to Internet applications" Unrestricted="true" ID="Custom" SameSite="site" />
|
||||||
|
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||||
|
</applicationRequestMinimum>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!-- UAC Manifest Options
|
||||||
|
If you want to change the Windows User Account Control level replace the
|
||||||
|
requestedExecutionLevel node with one of the following.
|
||||||
|
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
|
||||||
|
Specifying requestedExecutionLevel node will disable file and registry virtualization.
|
||||||
|
If you want to utilize File and Registry Virtualization for backward
|
||||||
|
compatibility then delete the requestedExecutionLevel node.
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentOS>
|
||||||
|
<osVersionInfo>
|
||||||
|
<os majorVersion="5" minorVersion="1" buildNumber="2600" servicePackMajor="0" />
|
||||||
|
</osVersionInfo>
|
||||||
|
</dependentOS>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
||||||
|
<assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="4.0.30319.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MeshMiniRouter.exe" size="193536">
|
||||||
|
<assemblyIdentity name="MeshMiniRouter" version="1.0.6505.20092" language="neutral" processorArchitecture="msil" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>G2b79xma2HCz/aTfnkt2L3I8c7mPbDDlU8IsdlFiDg8=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<file name="MeshMiniRouter.exe.config" size="2397">
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>UylUFD4/o0KBti+5/eodTDgq4BkUJD0J0aUXNd3yHbY=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</file>
|
||||||
|
<file name="MeshMiniRouter.ico" size="1078">
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>mkjbDQuo7YXa8wZxdKEu/ECXrORwwtpRgNj8NBKbzHo=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</file>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of all Windows versions that this application is designed to work with. Windows will automatically select the most compatible environment.-->
|
||||||
|
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
|
||||||
|
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</asmv1:assembly>
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
21
public/clickonce/minirouter/MeshMiniRouter.application
Normal file
21
public/clickonce/minirouter/MeshMiniRouter.application
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.7" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<description asmv2:publisher="Meshcentral.com" asmv2:product="Meshcentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
||||||
|
<deployment install="false" mapFileExtensions="true" trustURLParameters="true" />
|
||||||
|
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
||||||
|
<framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
|
||||||
|
</compatibleFrameworks>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_7\MeshMiniRouter.exe.manifest" size="4711">
|
||||||
|
<assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.7" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
|
||||||
|
<hash>
|
||||||
|
<dsig:Transforms>
|
||||||
|
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
||||||
|
</dsig:Transforms>
|
||||||
|
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
||||||
|
<dsig:DigestValue>VsPkLYR71TSqI8oGBBeXzb5hGi4R2xtQaGQJ0zmsTic=</dsig:DigestValue>
|
||||||
|
</hash>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</asmv1:assembly>
|
90
public/clickonce/minirouter/publish.htm
Normal file
90
public/clickonce/minirouter/publish.htm
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>Meshcentral Mini-Router</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />
|
||||||
|
<STYLE TYPE="text/css">
|
||||||
|
<!--
|
||||||
|
BODY{margin-top:20px; margin-left:20px; margin-right:20px; color:#000000; font-family:Tahoma; background-color:white}
|
||||||
|
A:link {font-weight:normal; color:#000066; text-decoration:none}
|
||||||
|
A:visited {font-weight:normal; color:#000066; text-decoration:none}
|
||||||
|
A:active {font-weight:normal; text-decoration:none}
|
||||||
|
A:hover {font-weight:normal; color:#FF6600; text-decoration:none}
|
||||||
|
P {margin-top:0px; margin-bottom:12px; color:#000000; font-family:Tahoma}
|
||||||
|
PRE {border-right:#f0f0e0 1px solid; padding-right:5px; border-top:#f0f0e0 1px solid; margin-top:-5px; padding-left:5px; font-size:x-small; padding-bottom:5px; border-left:#f0f0e0 1px solid; padding-top:5px; border-bottom:#f0f0e0 1px solid; font-family:Courier New; background-color:#e5e5cc}
|
||||||
|
TD {font-size:12px; color:#000000; font-family:Tahoma}
|
||||||
|
H2 {border-top: #003366 1px solid; margin-top:25px; font-weight:bold; font-size:1.5em; margin-bottom:10px; margin-left:-15px; color:#003366}
|
||||||
|
H3 {margin-top:10px; font-size: 1.1em; margin-bottom: 10px; margin-left: -15px; color: #000000}
|
||||||
|
UL {margin-top:10px; margin-left:20px}
|
||||||
|
OL {margin-top:10px; margin-left:20px}
|
||||||
|
LI {margin-top:10px; color: #000000}
|
||||||
|
FONT.value {font-weight:bold; color:darkblue}
|
||||||
|
FONT.key {font-weight: bold; color: darkgreen}
|
||||||
|
.divTag {border:1px; border-style:solid; background-color:#FFFFFF; text-decoration:none; height:auto; width:auto; background-color:#cecece}
|
||||||
|
.BannerColumn {background-color:#000000}
|
||||||
|
.Banner {border:0; padding:0; height:8px; margin-top:0px; color:#ffffff; filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#1c5280',EndColorStr='#FFFFFF');}
|
||||||
|
.BannerTextCompany {font:bold; font-size:18pt; color:#cecece; font-family:Tahoma; height:0px; margin-top:0; margin-left:8px; margin-bottom:0; padding:0px; white-space:nowrap; filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2,OffY=2,Color='black',Positive='true');}
|
||||||
|
.BannerTextApplication {font:bold; font-size:18pt; font-family:Tahoma; height:0px; margin-top:0; margin-left:8px; margin-bottom:0; padding:0px; white-space:nowrap; filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2,OffY=2,Color='black',Positive='true');}
|
||||||
|
.BannerText {font:bold; font-size:18pt; font-family:Tahoma; height:0px; margin-top:0; margin-left:8px; margin-bottom:0; padding:0px; filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2,OffY=2,Color='black',Positive='true');}
|
||||||
|
.BannerSubhead {border:0; padding:0; height:16px; margin-top:0px; margin-left:10px; color:#ffffff; filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#4B3E1A',EndColorStr='#FFFFFF');}
|
||||||
|
.BannerSubheadText {font:bold; height:11px; font-size:11px; font-family:Tahoma; margin-top:1; margin-left:10; filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2,OffY=2,Color='black',Positive='true');}
|
||||||
|
.FooterRule {border:0; padding:0; height:1px; margin:0px; color:#ffffff; filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#4B3E1A',EndColorStr='#FFFFFF');}
|
||||||
|
.FooterText {font-size:11px; font-weight:normal; text-decoration:none; font-family:Tahoma; margin-top:10; margin-left:0px; margin-bottom:2; padding:0px; color:#999999; white-space:nowrap}
|
||||||
|
.FooterText A:link {font-weight:normal; color:#999999; text-decoration:underline}
|
||||||
|
.FooterText A:visited {font-weight:normal; color:#999999; text-decoration:underline}
|
||||||
|
.FooterText A:active {font-weight:normal; color:#999999; text-decoration:underline}
|
||||||
|
.FooterText A:hover {font-weight:normal; color:#FF6600; text-decoration:underline}
|
||||||
|
.ClickOnceInfoText {font-size:11px; font-weight:normal; text-decoration:none; font-family:Tahoma; margin-top:0; margin-right:2px; margin-bottom:0; padding:0px; color:#000000}
|
||||||
|
.InstallTextStyle {font:bold; font-size:14pt; font-family:Tahoma; a:#FF0000; text-decoration:None}
|
||||||
|
.DetailsStyle {margin-left:30px}
|
||||||
|
.ItemStyle {margin-left:-15px; font-weight:bold}
|
||||||
|
.StartColorStr {background-color:#4B3E1A}
|
||||||
|
.JustThisApp A:link {font-weight:normal; color:#000066; text-decoration:underline}
|
||||||
|
.JustThisApp A:visited {font-weight:normal; color:#000066; text-decoration:underline}
|
||||||
|
.JustThisApp A:active {font-weight:normal; text-decoration:underline}
|
||||||
|
.JustThisApp A:hover {font-weight:normal; color:#FF6600; text-decoration:underline}
|
||||||
|
-->
|
||||||
|
|
||||||
|
</STYLE>
|
||||||
|
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="2" BORDER="0">
|
||||||
|
|
||||||
|
<!-- Begin Banner -->
|
||||||
|
<TR><TD><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" BGCOLOR="#cecece" WIDTH="100%"><TR><TD><TABLE BGCOLOR="#1c5280" WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR><TD CLASS="Banner" /></TR><TR><TD CLASS="Banner"><SPAN CLASS="BannerTextCompany">Meshcentral.com</SPAN></TD></TR><TR><TD CLASS="Banner"><SPAN CLASS="BannerTextApplication">Meshcentral Mini-Router</SPAN></TD></TR><TR><TD CLASS="Banner" ALIGN="RIGHT" /></TR></TABLE></TD></TR></TABLE></TD></TR>
|
||||||
|
<!-- End Banner -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Begin Dialog -->
|
||||||
|
<TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540"><TR><TD WIDTH="496">
|
||||||
|
|
||||||
|
<!-- Begin AppInfo -->
|
||||||
|
<TABLE><TR><TD COLSPAN="3"> </TD></TR><TR><TD><B>Name:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral Mini-Router</TD></TR><TR><TD COLSPAN="3"> </TD></TR><TR><TD><B>Version:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>2.0.0.7</TD></TR><TR><TD COLSPAN="3"> </TD></TR><TR><TD><B>Publisher:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral.com</TD></TR><tr><td colspan="3"> </td></tr></TABLE>
|
||||||
|
<!-- End AppInfo -->
|
||||||
|
|
||||||
|
|
||||||
|
</TD></TR></TABLE>
|
||||||
|
<!-- Begin Buttons -->
|
||||||
|
<TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540" STYLE="cursor:hand" ONCLICK="window.navigate(InstallButton.href)"><TR><TD ALIGN="LEFT"><TABLE CELLPADDING="1" BGCOLOR="#333333" CELLSPACING="0" BORDER="0"><TR><TD><TABLE CELLPADDING="1" BGCOLOR="#cecece" CELLSPACING="0" BORDER="0"><TR><TD><TABLE CELLPADDING="1" BGCOLOR="#efefef" CELLSPACING="0" BORDER="0"><TR><TD WIDTH="20"><SPACER TYPE="block" WIDTH="20" HEIGHT="1" /></TD><TD><A ID="InstallButton" HREF="MeshMiniRouter.application">Run</A></TD><TD width="20"><SPACER TYPE="block" WIDTH="20" HEIGHT="1" /></TD></TR></TABLE></TD></TR></TABLE></TD></TR></TABLE></TD><TD WIDTH="15%" ALIGN="right" /></TR></TABLE></TD></TR>
|
||||||
|
<!-- End Buttons -->
|
||||||
|
</TD></TR>
|
||||||
|
<!-- End Dialog -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Spacer Row -->
|
||||||
|
<TR><TD> </TD></TR>
|
||||||
|
|
||||||
|
<TR><TD>
|
||||||
|
<!-- Begin Footer -->
|
||||||
|
<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0" BGCOLOR="#ffffff"><TR><TD HEIGHT="5"><SPACER TYPE="block" HEIGHT="5" /></TD></TR><TR><TD CLASS="FooterText" ALIGN="center">
|
||||||
|
<A HREF="https://meshcentral.com">Meshcentral.com Customer Support</A>
|
||||||
|
::
|
||||||
|
<A HREF="http://go.microsoft.com/fwlink/?LinkId=154571">ClickOnce and .NET Framework Resources</A>
|
||||||
|
</TD></TR><TR><TD HEIGHT="5"><SPACER TYPE="block" HEIGHT="5" /></TD></TR><TR><TD HEIGHT="1" bgcolor="#cecece"><SPACER TYPE="block" HEIGHT="1" /></TD></TR></TABLE>
|
||||||
|
<!-- End Footer -->
|
||||||
|
</TD></TR>
|
||||||
|
|
||||||
|
</TABLE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
@ -60,6 +60,9 @@ module.exports.CreateRedirServer = function (parent, db, args, certificates) {
|
|||||||
obj.app.post(url + 'amtevents.ashx', obj.parent.webserver.handleAmtEventRequest);
|
obj.app.post(url + 'amtevents.ashx', obj.parent.webserver.handleAmtEventRequest);
|
||||||
obj.app.get(url + 'meshsettings', obj.parent.webserver.handleMeshSettingsRequest);
|
obj.app.get(url + 'meshsettings', obj.parent.webserver.handleMeshSettingsRequest);
|
||||||
obj.app.get(url + 'meshagents', obj.parent.webserver.handleMeshAgentRequest);
|
obj.app.get(url + 'meshagents', obj.parent.webserver.handleMeshAgentRequest);
|
||||||
|
|
||||||
|
// Indicates the clickonce folder is public
|
||||||
|
obj.app.use(url + 'clickonce', obj.express.static(obj.parent.path.join(__dirname, 'public/clickonce')));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a free port starting with the specified one and going up.
|
// Find a free port starting with the specified one and going up.
|
||||||
|
@ -280,320 +280,320 @@
|
|||||||
<div id=p11 style=display:none>
|
<div id=p11 style=display:none>
|
||||||
<h1 id=p11deviceNameHeader><span id=p11deviceName></span> - Desktop</h1>
|
<h1 id=p11deviceNameHeader><span id=p11deviceName></span> - Desktop</h1>
|
||||||
<div id="p14warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
|
<div id="p14warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
|
||||||
<div class="icon2" style="float:left;margin:7px" />
|
<div class=icon2 style="float:left;margin:7px"></div>
|
||||||
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="p14warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()">
|
||||||
|
<div class=icon2 style="float:left;margin:7px"></div>
|
||||||
|
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
|
||||||
|
</div>
|
||||||
|
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
||||||
|
<tr id=deskarea1>
|
||||||
|
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||||
|
<div style="float:right;text-align:right">
|
||||||
|
<span id="p14power"></span>
|
||||||
|
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Left" onclick="drotate(-1)">↺</div>
|
||||||
|
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Right" onclick="drotate(1)">↻</div>
|
||||||
|
<input id="deskFullBtn" type="button" title="Toggle full screen mode" onkeypress="return false" onkeydown="return false" value="Full" onclick="deskToggleFull()" style="margin-right:3px">
|
||||||
|
<input id="deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px;display:none">
|
||||||
|
<input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick=deskSaveImage() style=margin-right:3px>
|
||||||
|
<input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
||||||
|
<input type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="margin-right:3px">
|
||||||
|
<input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px;display:none">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="idx_deskFullBtn2" onclick=deskToggleFull() style="float:left;font-size:large;cursor:pointer;display:none"> X</div>
|
||||||
|
<input type="button" id="autoconnectbutton1" value="AutoConnect" onclick=autoConnectDesktop(event) onkeypress="return false" onkeydown="return false" style="display:none">
|
||||||
|
<span id=connectbutton1span> <input type=button id=connectbutton1 value="Connect" onclick=connectDesktop(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||||||
|
<span id=connectbutton1hspan> <input type=button id=connectbutton1h value="HW Connect" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||||||
|
<span id=disconnectbutton1span> <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false"></span>
|
||||||
|
<span id="deskstatus">Disconnected</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id=deskarea2>
|
||||||
|
<td>
|
||||||
|
<div style="background-color:gray"><div id="progressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id=deskarea3>
|
||||||
|
<td id=deskarea3x style="background:black;text-align:center;height:400px;position:relative">
|
||||||
|
<div id="DeskFocus" style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
|
||||||
|
<canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></canvas>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id=deskarea4>
|
||||||
|
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<input id="DeskCAD" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id="p14warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()">
|
<div id=p12 style=display:none>
|
||||||
<div class="icon2" style="float:left;margin:7px" />
|
<h1><span id=p12deviceName></span> - Terminal</h1>
|
||||||
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
|
<div id="p12warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showFeaturesDlg()>
|
||||||
|
<div class="icon2" style="float:left;margin:7px"></div>
|
||||||
|
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
||||||
|
</div>
|
||||||
|
<div id="p12warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showPowerActionDlg()>
|
||||||
|
<div class="icon2" style="float:left;margin:7px"></div>
|
||||||
|
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
|
||||||
|
</div>
|
||||||
|
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||||
|
<div style="float:right;text-align:right">
|
||||||
|
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
|
||||||
|
<span id="connectbutton2span"> <input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||||||
|
<span id="connectbutton2hspan"> <input type="button" id="connectbutton2h" value="HW Connect" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||||||
|
<span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
|
||||||
|
<span id="termstatus">Disconnected</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div style="background-color:gray"><div id="termprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="background:black;text-align:center;height:500px;position:relative">
|
||||||
|
<pre id="Term" style="background:black;margin:0;padding:0"></pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||||
|
<div style="float:right;text-align:right">
|
||||||
|
<input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
|
||||||
|
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
|
||||||
|
<select id="specialkeylist" onkeypress="return false"></select>
|
||||||
|
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div id=p13 style=display:none>
|
||||||
|
<h1><span id=p13deviceName></span> - Files</h1>
|
||||||
|
<table id="p13toolbar" style="width: 100%" cellpadding="0" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
|
||||||
|
<div style="float:right;text-align:right">
|
||||||
|
<input id="filesActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) onkeypress="return false" onkeydown="return false" type="button" style="display:none">
|
||||||
|
<input id=p13Connect value="Connect" onclick=connectFiles(event) onkeypress="return false" onkeydown="return false" type="button">
|
||||||
|
<span id=p13Status>Disconnected</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
|
||||||
|
<div id="p13rightOfButtons" style="float:right;margin-top:3px"></div>
|
||||||
|
<div>
|
||||||
|
<input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
|
||||||
|
<input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />
|
||||||
|
<input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />
|
||||||
|
<input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />
|
||||||
|
<input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />
|
||||||
|
<input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />
|
||||||
|
<input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="background-color:#E4E9E7;height:28px">
|
||||||
|
<div style=float:right>
|
||||||
|
<select id=p13sortdropdown onchange=p13updateFiles()>
|
||||||
|
<option value=1 selected="selected">Sort by name</option>
|
||||||
|
<option value=2>Sort by size</option>
|
||||||
|
<option value=3>Sort by date</option>
|
||||||
|
<option value=4>Descend by name</option>
|
||||||
|
<option value=5>Descend by size</option>
|
||||||
|
<option value=6>Descend by date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div> <span id="p13currentpath"></span></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div id="p13filetable" style="width:100%;height:500px;overflow:auto;-webkit-user-select:none">
|
||||||
|
<div id="p13bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✓</b></div>
|
||||||
|
<div id="p13bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✗</b></div>
|
||||||
|
<span id="p13files"></span>
|
||||||
|
</div>
|
||||||
|
<table id="p13toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
|
||||||
|
<tr><td class=style6 style="text-align:left"> <span id="bottomstatus"></span></td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id=p14 style=display:none>
|
||||||
|
<h1><span id=p14deviceName></span> - Intel® AMT</h1>
|
||||||
|
<iframe id=p14iframe style="width:100%;height:650px;border:0;overflow:hidden" src="/commander.htm"></iframe>
|
||||||
|
</div>
|
||||||
|
<div id=p15 style=display:none>
|
||||||
|
<h1><span id=p15deviceName></span> - Console</h1>
|
||||||
|
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
||||||
|
<tr>
|
||||||
|
<td style=background:#C0C0C0>
|
||||||
|
<div style=float:right;padding-right:4px>
|
||||||
|
<span id=p15coreName title="Information about current core running on this agent"></span>
|
||||||
|
<input type=button id=p15uploadCore value="Change Core" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
|
||||||
|
</div>
|
||||||
|
<div id="p15statetext" style=padding:4px></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div style="background-color:gray"><div id="consoleprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="background:black;text-align:center;height:500px;position:relative">
|
||||||
|
<div id="p15agentConsole" style="background:black;margin:0;padding:0;color:lightgray;width:100%;max-width:930px;height:100%;text-align:left;overflow-y:scroll"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||||
|
<table style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<td style="width:99%">
|
||||||
|
<input id=p15consoleText style=width:100% onkeyup=p15consoleSend(event) onfocus=onConsoleFocus(1) onblur=onConsoleFocus(0) />
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
<td style="width:1%"><input id="id_p15consoleClear" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id=p20 style=display:none>
|
||||||
|
<h1><span id=p20meshName></span> - General</h1>
|
||||||
|
<p id=p20info></p>
|
||||||
|
</div>
|
||||||
|
<br id="column_l_bottomgap" />
|
||||||
</div>
|
</div>
|
||||||
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
<div id=footer class=noselect>
|
||||||
<tr id=deskarea1>
|
<table cellpadding=0 cellspacing=10 style="width:100%">
|
||||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
<tr>
|
||||||
<div style="float:right;text-align:right">
|
<td style="text-align:left"></td>
|
||||||
<span id="p14power"></span>
|
<td style="text-align:right"><a href="terms">Terms & Privacy</a></td>
|
||||||
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Left" onclick="drotate(-1)">↺</div>
|
</tr>
|
||||||
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Right" onclick="drotate(1)">↻</div>
|
</table>
|
||||||
<input id="deskFullBtn" type="button" title="Toggle full screen mode" onkeypress="return false" onkeydown="return false" value="Full" onclick="deskToggleFull()" style="margin-right:3px">
|
|
||||||
<input id="deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px;display:none">
|
|
||||||
<input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick=deskSaveImage() style=margin-right:3px>
|
|
||||||
<input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
|
||||||
<input type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="margin-right:3px">
|
|
||||||
<input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px;display:none">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div id="idx_deskFullBtn2" onclick=deskToggleFull() style="float:left;font-size:large;cursor:pointer;display:none"> X</div>
|
|
||||||
<input type="button" id="autoconnectbutton1" value="AutoConnect" onclick=autoConnectDesktop(event) onkeypress="return false" onkeydown="return false" style="display:none">
|
|
||||||
<span id=connectbutton1span> <input type=button id=connectbutton1 value="Connect" onclick=connectDesktop(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
|
||||||
<span id=connectbutton1hspan> <input type=button id=connectbutton1h value="HW Connect" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
|
||||||
<span id=disconnectbutton1span> <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false"></span>
|
|
||||||
<span id="deskstatus">Disconnected</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id=deskarea2>
|
|
||||||
<td>
|
|
||||||
<div style="background-color:gray"><div id="progressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id=deskarea3>
|
|
||||||
<td id=deskarea3x style="background:black;text-align:center;height:400px;position:relative">
|
|
||||||
<div id="DeskFocus" style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
|
|
||||||
<canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></canvas>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id=deskarea4>
|
|
||||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<input id="DeskCAD" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id=p12 style=display:none>
|
|
||||||
<h1><span id=p12deviceName></span> - Terminal</h1>
|
|
||||||
<div id="p12warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showFeaturesDlg()>
|
|
||||||
<div class="icon2" style="float:left;margin:7px"></div>
|
|
||||||
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="p12warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showPowerActionDlg()>
|
<div id=dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:160px;width:400px;display:none">
|
||||||
<div class="icon2" style="float:left;margin:7px"></div>
|
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
|
||||||
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
|
<div id=id_dialogclose style=float:right;padding:5px;cursor:pointer onclick=setDialogMode()><b>X</b></div>
|
||||||
</div>
|
<div id=id_dialogtitle style=padding:5px></div>
|
||||||
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
<div style=width:100%;margin:6px></div>
|
||||||
<tr>
|
</div>
|
||||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
<div style="margin-right:16px;margin-left:8px">
|
||||||
<div style="float:right;text-align:right">
|
<div id=dialog1 style="margin:auto;text-align:center;margin:3px">
|
||||||
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
<div id=id_dialogMessage style="padding:10px"></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div id=dialog2 style="margin:auto;margin:3px">
|
||||||
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
|
<div id=id_dialogOptions></div>
|
||||||
<span id="connectbutton2span"> <input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
</div>
|
||||||
<span id="connectbutton2hspan"> <input type="button" id="connectbutton2h" value="HW Connect" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
<div id=dialog3 style="margin:auto;margin:3px">
|
||||||
<span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
|
<div style=height:26px>
|
||||||
<span id="termstatus">Disconnected</span>
|
<select id=d3uploadMode style=float:right;width:260px onchange=d3modechange()>
|
||||||
</div>
|
<option value=1>Local file upload</option>
|
||||||
</td>
|
<option value=2>Server file selection</option>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div style="background-color:gray"><div id="termprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="background:black;text-align:center;height:500px;position:relative">
|
|
||||||
<pre id="Term" style="background:black;margin:0;padding:0"></pre>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
|
||||||
<div style="float:right;text-align:right">
|
|
||||||
<input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
|
|
||||||
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
|
|
||||||
<select id="specialkeylist" onkeypress="return false"></select>
|
|
||||||
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
|
|
||||||
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
|
|
||||||
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
|
|
||||||
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
|
|
||||||
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id=p13 style=display:none>
|
|
||||||
<h1><span id=p13deviceName></span> - Files</h1>
|
|
||||||
<table id="p13toolbar" style="width: 100%" cellpadding="0" cellspacing="0">
|
|
||||||
<tr>
|
|
||||||
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
|
|
||||||
<div style="float:right;text-align:right">
|
|
||||||
<input id="filesActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) onkeypress="return false" onkeydown="return false" type="button" style="display:none">
|
|
||||||
<input id=p13Connect value="Connect" onclick=connectFiles(event) onkeypress="return false" onkeydown="return false" type="button">
|
|
||||||
<span id=p13Status>Disconnected</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
|
|
||||||
<div id="p13rightOfButtons" style="float:right;margin-top:3px"></div>
|
|
||||||
<div>
|
|
||||||
<input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
|
|
||||||
<input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />
|
|
||||||
<input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />
|
|
||||||
<input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />
|
|
||||||
<input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />
|
|
||||||
<input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />
|
|
||||||
<input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="background-color:#E4E9E7;height:28px">
|
|
||||||
<div style=float:right>
|
|
||||||
<select id=p13sortdropdown onchange=p13updateFiles()>
|
|
||||||
<option value=1 selected="selected">Sort by name</option>
|
|
||||||
<option value=2>Sort by size</option>
|
|
||||||
<option value=3>Sort by date</option>
|
|
||||||
<option value=4>Descend by name</option>
|
|
||||||
<option value=5>Descend by size</option>
|
|
||||||
<option value=6>Descend by date</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
<div>File Selection</div>
|
||||||
</div>
|
</div>
|
||||||
<div> <span id="p13currentpath"></span></div>
|
<div id=d3localmode style=height:26px;display:none>
|
||||||
</td>
|
<form id=d3localmodeform method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
|
||||||
</tr>
|
<input type=text id=d3attrib name=attrib style=display:none />
|
||||||
</table>
|
<input type=file id=d3localFile name=files style=float:right;width:260px onchange=d3setActions() />
|
||||||
<div id="p13filetable" style="width:100%;height:500px;overflow:auto;-webkit-user-select:none">
|
<input type=submit id=d3submit style=display:none />
|
||||||
<div id="p13bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✓</b></div>
|
</form>
|
||||||
<div id="p13bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✗</b></div>
|
<div>Upload File</div>
|
||||||
<span id="p13files"></span>
|
|
||||||
</div>
|
|
||||||
<table id="p13toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
|
|
||||||
<tr><td class=style6 style="text-align:left"> <span id="bottomstatus"></span></td></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id=p14 style=display:none>
|
|
||||||
<h1><span id=p14deviceName></span> - Intel® AMT</h1>
|
|
||||||
<iframe id=p14iframe style="width:100%;height:650px;border:0;overflow:hidden" src="/commander.htm"></iframe>
|
|
||||||
</div>
|
|
||||||
<div id=p15 style=display:none>
|
|
||||||
<h1><span id=p15deviceName></span> - Console</h1>
|
|
||||||
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
|
|
||||||
<tr>
|
|
||||||
<td style=background:#C0C0C0>
|
|
||||||
<div style=float:right;padding-right:4px>
|
|
||||||
<span id=p15coreName title="Information about current core running on this agent"></span>
|
|
||||||
<input type=button id=p15uploadCore value="Change Core" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
|
|
||||||
</div>
|
</div>
|
||||||
<div id="p15statetext" style=padding:4px></div>
|
<div id=d3servermode>
|
||||||
</td>
|
<div style="width:100%;background-color:#d3d9d6;text-align:left;padding:3px" valign=bottom>
|
||||||
</tr>
|
<input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" />
|
||||||
<tr>
|
</div>
|
||||||
<td>
|
<div id=d3serverfiles style="width:100%;height:150px;background-color:white;padding:2px;border:1px solid gray;overflow-y:scroll"></div>
|
||||||
<div style="background-color:gray"><div id="consoleprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
<div id=dialog7 style="margin:auto;margin:3px">
|
||||||
<tr>
|
<div id="d7meshkvm">
|
||||||
<td style="background:black;text-align:center;height:500px;position:relative">
|
<h4 style="width:100%;border-bottom:1px solid gray">Mesh Agent Remote Desktop</h4>
|
||||||
<div id="p15agentConsole" style="background:black;margin:0;padding:0;color:lightgray;width:100%;max-width:930px;height:100%;text-align:left;overflow-y:scroll"></div>
|
<div style="margin:3px 0 3px 0">
|
||||||
</td>
|
<select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl">
|
||||||
</tr>
|
<option value=50>50%</option>
|
||||||
<tr>
|
<option value=40>40%</option>
|
||||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
<option selected=selected value=30>30%</option>
|
||||||
<table style="width:100%">
|
<option value=20>20%</option>
|
||||||
<tr>
|
<option value=10>10%</option>
|
||||||
<td style="width:99%">
|
<option value=5>5%</option>
|
||||||
<input id=p15consoleText style=width:100% onkeyup=p15consoleSend(event) onfocus=onConsoleFocus(1) onblur=onConsoleFocus(0) />
|
<option value=1>1%</option>
|
||||||
</td>
|
</select>
|
||||||
<td> </td>
|
<div style="height:20px">Quality</div>
|
||||||
<td style="width:1%"><input id="id_p15consoleClear" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td>
|
</div>
|
||||||
</tr>
|
<div style="margin:3px 0 3px 0">
|
||||||
</table>
|
<select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
|
||||||
</td>
|
<option selected=selected value=1024>100%</option>
|
||||||
</tr>
|
<option value=896>87.5%</option>
|
||||||
</table>
|
<option value=768>75%</option>
|
||||||
</div>
|
<option value=640>62.5%</option>
|
||||||
<div id=p20 style=display:none>
|
<option value=512>50%</option>
|
||||||
<h1><span id=p20meshName></span> - General</h1>
|
<option value=384>37.5%</option>
|
||||||
<p id=p20info></p>
|
<option value=256>25%</option>
|
||||||
</div>
|
<option value=128>12.5%</option>
|
||||||
<br id="column_l_bottomgap" />
|
</select>
|
||||||
</div>
|
<div style="height:20px">Scaling</div>
|
||||||
<div id=footer class=noselect>
|
</div>
|
||||||
<table cellpadding=0 cellspacing=10 style="width:100%">
|
</div>
|
||||||
<tr>
|
<div id="d7amtkvm">
|
||||||
<td style="text-align:left"></td>
|
<h4 style="width:100%;border-bottom:1px solid gray">Intel® AMT Hardware KVM</h4>
|
||||||
<td style="text-align:right"><a href="terms">Terms & Privacy</a></td>
|
<div style='height:26px'>
|
||||||
</tr>
|
<select id="d7desktopmode" style="float:right;width:200px">
|
||||||
</table>
|
<option value="1">RLE8, Fastest</option>
|
||||||
</div>
|
<option value="2">RLE16, Recommended</option>
|
||||||
<div id=dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:160px;width:400px;display:none">
|
<option value="3">RAW8, Slow</option>
|
||||||
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
|
<option value="4">RAW16, Very Slow</option>
|
||||||
<div id=id_dialogclose style=float:right;padding:5px;cursor:pointer onclick=setDialogMode()><b>X</b></div>
|
</select>
|
||||||
<div id=id_dialogtitle style=padding:5px></div>
|
<div>Image Encoding</div>
|
||||||
<div style=width:100%;margin:6px></div>
|
</div>
|
||||||
</div>
|
<div style="height:60px">
|
||||||
<div style="margin-right:16px;margin-left:8px">
|
<div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
|
||||||
<div id=dialog1 style="margin:auto;text-align:center;margin:3px">
|
<input type="checkbox" id='d7showfocus'>Show Focus Tool<br>
|
||||||
<div id=id_dialogMessage style="padding:10px"></div>
|
<input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br>
|
||||||
</div>
|
</div>
|
||||||
<div id=dialog2 style="margin:auto;margin:3px">
|
<div>Other Settings</div>
|
||||||
<div id=id_dialogOptions></div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id=dialog3 style="margin:auto;margin:3px">
|
|
||||||
<div style=height:26px>
|
|
||||||
<select id=d3uploadMode style=float:right;width:260px onchange=d3modechange()>
|
|
||||||
<option value=1>Local file upload</option>
|
|
||||||
<option value=2>Server file selection</option>
|
|
||||||
</select>
|
|
||||||
<div>File Selection</div>
|
|
||||||
</div>
|
|
||||||
<div id=d3localmode style=height:26px;display:none>
|
|
||||||
<form id=d3localmodeform method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
|
|
||||||
<input type=text id=d3attrib name=attrib style=display:none />
|
|
||||||
<input type=file id=d3localFile name=files style=float:right;width:260px onchange=d3setActions() />
|
|
||||||
<input type=submit id=d3submit style=display:none />
|
|
||||||
</form>
|
|
||||||
<div>Upload File</div>
|
|
||||||
</div>
|
|
||||||
<div id=d3servermode>
|
|
||||||
<div style="width:100%;background-color:#d3d9d6;text-align:left;padding:3px" valign=bottom>
|
|
||||||
<input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" />
|
|
||||||
</div>
|
|
||||||
<div id=d3serverfiles style="width:100%;height:150px;background-color:white;padding:2px;border:1px solid gray;overflow-y:scroll"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id=dialog7 style="margin:auto;margin:3px">
|
|
||||||
<div id="d7meshkvm">
|
|
||||||
<h4 style="width:100%;border-bottom:1px solid gray">Mesh Agent Remote Desktop</h4>
|
|
||||||
<div style="margin:3px 0 3px 0">
|
|
||||||
<select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl">
|
|
||||||
<option value=50>50%</option>
|
|
||||||
<option value=40>40%</option>
|
|
||||||
<option selected=selected value=30>30%</option>
|
|
||||||
<option value=20>20%</option>
|
|
||||||
<option value=10>10%</option>
|
|
||||||
<option value=5>5%</option>
|
|
||||||
<option value=1>1%</option>
|
|
||||||
</select>
|
|
||||||
<div style="height:20px">Quality</div>
|
|
||||||
</div>
|
|
||||||
<div style="margin:3px 0 3px 0">
|
|
||||||
<select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
|
|
||||||
<option selected=selected value=1024>100%</option>
|
|
||||||
<option value=896>87.5%</option>
|
|
||||||
<option value=768>75%</option>
|
|
||||||
<option value=640>62.5%</option>
|
|
||||||
<option value=512>50%</option>
|
|
||||||
<option value=384>37.5%</option>
|
|
||||||
<option value=256>25%</option>
|
|
||||||
<option value=128>12.5%</option>
|
|
||||||
</select>
|
|
||||||
<div style="height:20px">Scaling</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="d7amtkvm">
|
|
||||||
<h4 style="width:100%;border-bottom:1px solid gray">Intel® AMT Hardware KVM</h4>
|
|
||||||
<div style='height:26px'>
|
|
||||||
<select id="d7desktopmode" style="float:right;width:200px">
|
|
||||||
<option value="1">RLE8, Fastest</option>
|
|
||||||
<option value="2">RLE16, Recommended</option>
|
|
||||||
<option value="3">RAW8, Slow</option>
|
|
||||||
<option value="4">RAW16, Very Slow</option>
|
|
||||||
</select>
|
|
||||||
<div>Image Encoding</div>
|
|
||||||
</div>
|
|
||||||
<div style="height:60px">
|
|
||||||
<div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
|
|
||||||
<input type="checkbox" id='d7showfocus'>Show Focus Tool<br>
|
|
||||||
<input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br>
|
|
||||||
</div>
|
</div>
|
||||||
<div>Other Settings</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:4px">
|
||||||
|
<input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
|
||||||
|
<input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
|
||||||
|
<div style="height:25px"><input id=idx_dlgDeleteButton type=button value=Delete style="width:80px;display:none" onclick="dialogclose(2)"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<iframe name="fileUploadFrame" style=display:none></iframe>
|
||||||
<div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:4px">
|
<form style=display:none method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name"><input id=p5fileDragSize name="size"><input id=p5fileDragType name="type"><input id=p5fileDragData name="data"><input id=p5fileDragLink name="link"><input type=submit id=p5loginSubmit2 style=display:none /></form>
|
||||||
<input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
|
<form style=display:none method=post action=uploadnodefile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p13fileDragName name="name"><input id=p13fileDragSize name="size"><input id=p13fileDragType name="type"><input id=p13fileDragData name="data"><input id=p13fileDragLink name="link"><input type=submit id=p13loginSubmit2 style=display:none /></form>
|
||||||
<input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
|
<audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></audio>
|
||||||
<div style="height:25px"><input id=idx_dlgDeleteButton type=button value=Delete style="width:80px;display:none" onclick="dialogclose(2)"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<iframe name="fileUploadFrame" style=display:none></iframe>
|
|
||||||
<form style=display:none method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name"><input id=p5fileDragSize name="size"><input id=p5fileDragType name="type"><input id=p5fileDragData name="data"><input id=p5fileDragLink name="link"><input type=submit id=p5loginSubmit2 style=display:none /></form>
|
|
||||||
<form style=display:none method=post action=uploadnodefile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p13fileDragName name="name"><input id=p13fileDragSize name="size"><input id=p13fileDragType name="type"><input id=p13fileDragData name="data"><input id=p13fileDragLink name="link"><input type=submit id=p13loginSubmit2 style=display:none /></form>
|
|
||||||
<audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></audio>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
|
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
|
||||||
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
|
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
|
||||||
@ -622,6 +622,7 @@
|
|||||||
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
|
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
|
||||||
var amtScanResults = null;
|
var amtScanResults = null;
|
||||||
var debugmode = false;
|
var debugmode = false;
|
||||||
|
var clickOnce = detectClickOnce();
|
||||||
|
|
||||||
function startup() {
|
function startup() {
|
||||||
// Guard against other site's top frames (web bugs).
|
// Guard against other site's top frames (web bugs).
|
||||||
@ -720,35 +721,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if this browser supports clickonce
|
||||||
|
function detectClickOnce() {
|
||||||
|
for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == "application/x-ms-application") { return true; } }
|
||||||
|
var userAgent = window.navigator.userAgent.toUpperCase();
|
||||||
|
return (userAgent.indexOf('.NET CLR 3.5') >= 0) || (userAgent.indexOf('(WINDOWS NT ') >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
function updateSiteAdmin() {
|
function updateSiteAdmin() {
|
||||||
var noServerBackup = {{{noServerBackup}}};
|
var noServerBackup = {{{noServerBackup}}};
|
||||||
var siteRights = userinfo.siteadmin;
|
var siteRights = userinfo.siteadmin;
|
||||||
if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
|
if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
|
||||||
|
|
||||||
// Update account actions
|
// Update account actions
|
||||||
QV('p2AccountActions', (features & 4) == 0); // Hide Account Actions if in single user mode
|
QV('p2AccountActions', (features & 4) == 0); // Hide Account Actions if in single user mode
|
||||||
QV('p2ServerActions', siteRights & 5);
|
QV('p2ServerActions', siteRights & 5);
|
||||||
QV('p2ServerActionsBackup', siteRights & 1);
|
QV('p2ServerActionsBackup', siteRights & 1);
|
||||||
QV('p2ServerActionsRestore', siteRights & 4);
|
QV('p2ServerActionsRestore', siteRights & 4);
|
||||||
QV('p2ServerActionsVersion', siteRights & 16);
|
QV('p2ServerActionsVersion', siteRights & 16);
|
||||||
QV('MainMenuMyFiles', siteRights & 8);
|
QV('MainMenuMyFiles', siteRights & 8);
|
||||||
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { go(1); }
|
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { go(1); }
|
||||||
|
|
||||||
// Update user management state
|
// Update user management state
|
||||||
if ((userinfo.siteadmin & 2) != 0)
|
if ((userinfo.siteadmin & 2) != 0)
|
||||||
{
|
{
|
||||||
// We are user administrator
|
// We are user administrator
|
||||||
if (users == null) { meshserver.Send({ action: 'users' }); }
|
if (users == null) { meshserver.Send({ action: 'users' }); }
|
||||||
if (wssessions == null) { meshserver.Send({ action: 'wssessioncount' }); }
|
if (wssessions == null) { meshserver.Send({ action: 'wssessioncount' }); }
|
||||||
} else {
|
} else {
|
||||||
// We are not user administrator
|
// We are not user administrator
|
||||||
users = null;
|
users = null;
|
||||||
wssessions = null;
|
wssessions = null;
|
||||||
updateUsers();
|
updateUsers();
|
||||||
if (xxcurrentView == 4) go(1);
|
if (xxcurrentView == 4) go(1);
|
||||||
}
|
}
|
||||||
meshserver.Send({ action: 'events' });
|
meshserver.Send({ action: 'events' });
|
||||||
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
|
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMessage(server, message) {
|
function onMessage(server, message) {
|
||||||
@ -883,6 +891,14 @@
|
|||||||
events_update();
|
events_update();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'getcookie': {
|
||||||
|
if (message.tag == 'clickonce') {
|
||||||
|
var basicPort = "{{{serverRedirPort}}}"==""?"{{{serverPublicPort}}}":"{{{serverRedirPort}}}";
|
||||||
|
rdpurl = "http://" + window.location.hostname + ":" + basicPort + "/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F" + window.location.hostname + "%2Fmeshrelay.ashx%3Fauth=" + message.cookie + "&CH={{{webcerthash}}}&AP=" + message.protocol + "&HOL=1";
|
||||||
|
window.open(rdpurl, '_blank');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'event': {
|
case 'event': {
|
||||||
if (!message.event.nolog) { events.unshift(message.event); events_update(); }
|
if (!message.event.nolog) { events.unshift(message.event); events_update(); }
|
||||||
switch (message.event.action) {
|
switch (message.event.action) {
|
||||||
@ -1737,10 +1753,10 @@
|
|||||||
|
|
||||||
// Context menu for clicks other than on feature
|
// Context menu for clicks other than on feature
|
||||||
var contextmenu_items = [
|
var contextmenu_items = [
|
||||||
{ text: 'Refresh', callback: function () { refreshMap(true, true); } },
|
{ text: 'Refresh', callback: function () { refreshMap(true, true); } },
|
||||||
{ text: 'Zoom to fit extent', callback: function () { zoomToFitExtent(); } },
|
{ text: 'Zoom to fit extent', callback: function () { zoomToFitExtent(); } },
|
||||||
{ text: 'Center map here', callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
|
{ text: 'Center map here', callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
|
||||||
{ text: 'Place node here', callback: function(obj) { placeNode(obj.coordinate); } }
|
{ text: 'Place node here', callback: function(obj) { placeNode(obj.coordinate); } }
|
||||||
];
|
];
|
||||||
|
|
||||||
function stringToIntHash(str) {
|
function stringToIntHash(str) {
|
||||||
@ -2394,10 +2410,14 @@
|
|||||||
|
|
||||||
// Show bottom buttons
|
// Show bottom buttons
|
||||||
x = '<div style=float:right;font-size:x-small>';
|
x = '<div style=float:right;font-size:x-small>';
|
||||||
if ((meshrights & 4) != 0) x += '<a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '")>Delete Device</a>';
|
if ((meshrights & 4) != 0) x += '<a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '") title="Remove this device">Delete Device</a>';
|
||||||
x += '</div><div style=font-size:x-small>';
|
x += '</div><div style=font-size:x-small>';
|
||||||
if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '")>Interfaces</a> ';
|
if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '") title="Show device network interface information">Interfaces</a> ';
|
||||||
if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '")>Location</a> ';
|
if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '") title="Show device locations information">Location</a> ';
|
||||||
|
|
||||||
|
// RDP link, show this link only of the remote machine is Windows.
|
||||||
|
if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0) && (node.agent.id > 0) && (node.agent.id < 5)) { x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","RDP") title="Requires Microsoft ClickOnce support in your browser.">RDP</a> '; }
|
||||||
|
|
||||||
x += '</div><br>'
|
x += '</div><br>'
|
||||||
|
|
||||||
QH('p10html3', x);
|
QH('p10html3', x);
|
||||||
@ -2606,6 +2626,10 @@
|
|||||||
meshserver.Send({ action: 'removedevices', nodeids: [ nodeid ] });
|
meshserver.Send({ action: 'removedevices', nodeids: [ nodeid ] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function p10clickOnce(nodeid, protocol) {
|
||||||
|
meshserver.Send({ action: 'getcookie', nodeid: nodeid, tcpport: 3389, tag: 'clickonce', protocol: 'rdp' });
|
||||||
|
}
|
||||||
|
|
||||||
// Show current location
|
// Show current location
|
||||||
var d2map = null;
|
var d2map = null;
|
||||||
function p10showNodeLocationDialog() {
|
function p10showNodeLocationDialog() {
|
||||||
@ -4565,5 +4589,5 @@
|
|||||||
function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = parsedUri[x]; break; } case 1: { r[name] = parsedUri[x]; var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } } } return r; }
|
function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = parsedUri[x]; break; } case 1: { r[name] = parsedUri[x]; var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } } } return r; }
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
959
webserver.js
959
webserver.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user