mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Improved session recording support.
This commit is contained in:
parent
3b1ece80bd
commit
fd09bebebc
@ -1982,7 +1982,7 @@ function OnWebSocket(msg, s, head) {
|
|||||||
s.on('data', function (msg) {
|
s.on('data', function (msg) {
|
||||||
if (this.parent.tunneling == false) {
|
if (this.parent.tunneling == false) {
|
||||||
msg = msg.toString();
|
msg = msg.toString();
|
||||||
if (msg == 'c') {
|
if ((msg == 'c') || (msg == 'cr')) {
|
||||||
this.parent.tunneling = true; this.pipe(this.parent.tcp); this.parent.tcp.pipe(this); debug(1, 'Tunnel active');
|
this.parent.tunneling = true; this.pipe(this.parent.tcp); this.parent.tcp.pipe(this); debug(1, 'Tunnel active');
|
||||||
} else if ((msg.length > 6) && (msg.substring(0, 6) == 'error:')) {
|
} else if ((msg.length > 6) && (msg.substring(0, 6) == 'error:')) {
|
||||||
console.log(msg.substring(6));
|
console.log(msg.substring(6));
|
||||||
|
@ -1042,7 +1042,7 @@ function createMeshCore(agent)
|
|||||||
|
|
||||||
if (this.httprequest.state == 0) {
|
if (this.httprequest.state == 0) {
|
||||||
// Check if this is a relay connection
|
// Check if this is a relay connection
|
||||||
if (data == 'c') { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
|
if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
|
||||||
} else {
|
} else {
|
||||||
// Handle tunnel data
|
// Handle tunnel data
|
||||||
if (this.httprequest.protocol == 0) { // 1 = Terminal, 2 = Desktop, 5 = Files, 6 = PowerShell
|
if (this.httprequest.protocol == 0) { // 1 = Terminal, 2 = Desktop, 5 = Files, 6 = PowerShell
|
||||||
|
@ -188,7 +188,7 @@ require('MeshAgent').AddCommandHandler(function (data)
|
|||||||
|
|
||||||
if (this.httprequest.state == 0) {
|
if (this.httprequest.state == 0) {
|
||||||
// Check if this is a relay connection
|
// Check if this is a relay connection
|
||||||
if (data == 'c') { this.httprequest.state = 1; sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid); }
|
if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid); }
|
||||||
} else {
|
} else {
|
||||||
// Handle tunnel data
|
// Handle tunnel data
|
||||||
if (this.httprequest.protocol == 0)
|
if (this.httprequest.protocol == 0)
|
||||||
|
16
meshrelay.js
16
meshrelay.js
@ -188,8 +188,8 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
|||||||
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, ipaddr1: cleanRemoteAddr(ws._socket.remoteAddress), ipaddr2: cleanRemoteAddr(obj.peer.ws._socket.remoteAddress), time: new Date().toLocaleString(), protocol: req.query.p, nodeid: req.query.nodeid });
|
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, ipaddr1: cleanRemoteAddr(ws._socket.remoteAddress), ipaddr2: cleanRemoteAddr(obj.peer.ws._socket.remoteAddress), time: new Date().toLocaleString(), protocol: req.query.p, nodeid: req.query.nodeid });
|
||||||
recordingEntry(fd, 1, ((req.query.browser) ? 2 : 0), firstBlock, function () {
|
recordingEntry(fd, 1, ((req.query.browser) ? 2 : 0), firstBlock, function () {
|
||||||
relayinfo.peer1.ws.logfile = ws.logfile = { fd: fd, lock: false };
|
relayinfo.peer1.ws.logfile = ws.logfile = { fd: fd, lock: false };
|
||||||
ws.send('c'); // Send connect to both peers
|
ws.send('cr'); // Send connect to both peers, 'cr' indicates the session is being recorded.
|
||||||
relayinfo.peer1.ws.send('c');
|
relayinfo.peer1.ws.send('cr');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -285,7 +285,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
|||||||
var peer = (relayinfo.peer1 == obj) ? relayinfo.peer2 : relayinfo.peer1;
|
var peer = (relayinfo.peer1 == obj) ? relayinfo.peer2 : relayinfo.peer1;
|
||||||
|
|
||||||
// Close the recording file
|
// Close the recording file
|
||||||
if (ws.logfile != null) { parent.parent.fs.close(ws.logfile.fd); ws.logfile = null; peer.ws.logfile = null; }
|
if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, tag) { parent.parent.fs.close(fd); tag.ws.logfile = null; tag.pws.logfile = null; }, { ws: ws, pws: peer.ws }); }
|
||||||
|
|
||||||
// Disconnect the peer
|
// Disconnect the peer
|
||||||
try { if (peer.relaySessionCounted) { parent.relaySessionCount--; delete peer.relaySessionCounted; } } catch (ex) { console.log(ex); }
|
try { if (peer.relaySessionCounted) { parent.relaySessionCount--; delete peer.relaySessionCounted; } } catch (ex) { console.log(ex); }
|
||||||
@ -327,7 +327,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Record a new entry in a recording log
|
// Record a new entry in a recording log
|
||||||
function recordingEntry(fd, type, flags, data, func) {
|
function recordingEntry(fd, type, flags, data, func, tag) {
|
||||||
try {
|
try {
|
||||||
if (typeof data == 'string') {
|
if (typeof data == 'string') {
|
||||||
// String write
|
// String write
|
||||||
@ -337,7 +337,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
|||||||
header.writeInt32BE(blockData.length, 4); // Size
|
header.writeInt32BE(blockData.length, 4); // Size
|
||||||
header.writeIntBE(new Date(), 10, 6); // Time
|
header.writeIntBE(new Date(), 10, 6); // Time
|
||||||
var block = Buffer.concat([header, blockData]);
|
var block = Buffer.concat([header, blockData]);
|
||||||
parent.parent.fs.write(fd, block, 0, block.length, func);
|
parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||||
} else {
|
} else {
|
||||||
// Binary write
|
// Binary write
|
||||||
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||||
@ -346,9 +346,9 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
|||||||
header.writeInt32BE(data.length, 4); // Size
|
header.writeInt32BE(data.length, 4); // Size
|
||||||
header.writeIntBE(new Date(), 10, 6); // Time
|
header.writeIntBE(new Date(), 10, 6); // Time
|
||||||
var block = Buffer.concat([header, data]);
|
var block = Buffer.concat([header, data]);
|
||||||
parent.parent.fs.write(fd, block, 0, block.length, func);
|
parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||||
}
|
}
|
||||||
} catch (ex) { console.log(ex); func(); }
|
} catch (ex) { console.log(ex); func(fd, tag); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark this relay session as authenticated if this is the user end.
|
// Mark this relay session as authenticated if this is the user end.
|
||||||
@ -418,7 +418,7 @@ The recording files are binary and contain a set of:
|
|||||||
|
|
||||||
The header is always 16 bytes long and is encoded like this:
|
The header is always 16 bytes long and is encoded like this:
|
||||||
|
|
||||||
TYPE 2 bytes, 1 = Header, 2 = Network Data
|
TYPE 2 bytes, 1 = Header, 2 = Network Data, 3 = EndBlock
|
||||||
FLAGS 2 bytes, 0x0001 = Binary, 0x0002 = User
|
FLAGS 2 bytes, 0x0001 = Binary, 0x0002 = User
|
||||||
SIZE 4 bytes, Size of the data following this header.
|
SIZE 4 bytes, Size of the data following this header.
|
||||||
TIME 8 bytes, Time this record was written, number of milliseconds since 1 January, 1970 UTC.
|
TIME 8 bytes, Time this record was written, number of milliseconds since 1 January, 1970 UTC.
|
||||||
|
File diff suppressed because one or more lines are too long
@ -84,6 +84,7 @@
|
|||||||
var recFilePtr = 0;
|
var recFilePtr = 0;
|
||||||
var recFileStartTime = 0;
|
var recFileStartTime = 0;
|
||||||
var recFileLastTime = 0;
|
var recFileLastTime = 0;
|
||||||
|
var recFileEndTime = 0;
|
||||||
var recFileMetadata = null;
|
var recFileMetadata = null;
|
||||||
var recFileProtocol = 0;
|
var recFileProtocol = 0;
|
||||||
var agentDesktop = null;
|
var agentDesktop = null;
|
||||||
@ -106,18 +107,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readNextBlock(func) {
|
function readNextBlock(func) {
|
||||||
if ((recFilePtr + 16) > recFile.size) { func(-1); } else {
|
if ((recFilePtr + 16) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
|
||||||
var fr = new FileReader();
|
var fr = new FileReader();
|
||||||
fr.onload = function () {
|
fr.onload = function () {
|
||||||
var type = ReadShort(this.result, 0);
|
var type = ReadShort(this.result, 0);
|
||||||
var flags = ReadShort(this.result, 2);
|
var flags = ReadShort(this.result, 2);
|
||||||
var size = ReadInt(this.result, 4);
|
var size = ReadInt(this.result, 4);
|
||||||
var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
|
var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
|
||||||
if ((recFilePtr + 16 + size) > recFile.size) { func(-1); } else {
|
if ((recFilePtr + 16 + size) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
|
||||||
var fr2 = new FileReader();
|
var fr2 = new FileReader();
|
||||||
fr2.onload = function () {
|
fr2.onload = function () {
|
||||||
recFilePtr += (16 + size);
|
recFilePtr += (16 + size);
|
||||||
QS('progressbar').width = Math.floor(100 * (recFilePtr / recFile.size)) + '%';
|
if (recFileEndTime == 0) {
|
||||||
|
// File pointer progress bar
|
||||||
|
QS('progressbar').width = Math.floor(100 * (recFilePtr / recFile.size)) + '%';
|
||||||
|
} else {
|
||||||
|
// Time progress bar
|
||||||
|
QS('progressbar').width = Math.floor(((recFileLastTime - recFileStartTime) / (recFileEndTime - recFileStartTime)) * 100) + '%';
|
||||||
|
}
|
||||||
func(type, flags, time, this.result);
|
func(type, flags, time, this.result);
|
||||||
};
|
};
|
||||||
fr2.readAsBinaryString(recFile.slice(recFilePtr + 16, recFilePtr + 16 + size));
|
fr2.readAsBinaryString(recFile.slice(recFilePtr + 16, recFilePtr + 16 + size));
|
||||||
@ -127,6 +134,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readLastBlock(func) {
|
||||||
|
if (recFile.size < 32) { func(-1); } else {
|
||||||
|
var fr = new FileReader();
|
||||||
|
fr.onload = function () {
|
||||||
|
var type = ReadShort(this.result, 0);
|
||||||
|
var flags = ReadShort(this.result, 2);
|
||||||
|
var size = ReadInt(this.result, 4);
|
||||||
|
var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
|
||||||
|
if ((type == 3) && (size == 16) && (this.result.substring(16, 32) == 'MeshCentralMCREC')) { func(type, flags, time); } else { func(-1); }
|
||||||
|
};
|
||||||
|
fr.readAsBinaryString(recFile.slice(recFile.size - 32, recFile.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addInfo(name, value) { if (value == null) return ''; return addInfoNoEsc(name, EscapeHtml(value)); }
|
function addInfo(name, value) { if (value == null) return ''; return addInfoNoEsc(name, EscapeHtml(value)); }
|
||||||
|
|
||||||
function addInfoNoEsc(name, value) {
|
function addInfoNoEsc(name, value) {
|
||||||
@ -141,6 +162,7 @@
|
|||||||
if ((recFileMetadata == null) || (recFileMetadata.magic != 'MeshCentralRelaySession') || (recFileMetadata.ver != 1)) { cleanup(); return; }
|
if ((recFileMetadata == null) || (recFileMetadata.magic != 'MeshCentralRelaySession') || (recFileMetadata.ver != 1)) { cleanup(); return; }
|
||||||
var x = '';
|
var x = '';
|
||||||
x += addInfo('Time', recFileMetadata.time);
|
x += addInfo('Time', recFileMetadata.time);
|
||||||
|
if (recFileEndTime != 0) { var secs = Math.floor((recFileEndTime - time) / 1000); x += addInfo('Duration', secs + ' second' + ((secs > 1) ? 's' : '')); }
|
||||||
x += addInfo('Username', recFileMetadata.username);
|
x += addInfo('Username', recFileMetadata.username);
|
||||||
x += addInfo('UserID', recFileMetadata.userid);
|
x += addInfo('UserID', recFileMetadata.userid);
|
||||||
x += addInfo('SessionID', recFileMetadata.sessionid);
|
x += addInfo('SessionID', recFileMetadata.sessionid);
|
||||||
@ -178,6 +200,7 @@
|
|||||||
amtDesktop = CreateAmtRemoteDesktop('Desk');
|
amtDesktop = CreateAmtRemoteDesktop('Desk');
|
||||||
amtDesktop.onScreenSizeChange = deskAdjust;
|
amtDesktop.onScreenSizeChange = deskAdjust;
|
||||||
amtDesktop.State = 3;
|
amtDesktop.State = 3;
|
||||||
|
amtDesktop.Start();
|
||||||
deskAdjust();
|
deskAdjust();
|
||||||
}
|
}
|
||||||
QV('metadatadiv', true);
|
QV('metadatadiv', true);
|
||||||
@ -213,15 +236,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((type == 2) && flagBinary && !flagUser) {
|
if ((type == 2) && flagBinary && !flagUser) {
|
||||||
|
// Device --> User data
|
||||||
if (recFileProtocol == 2) {
|
if (recFileProtocol == 2) {
|
||||||
// MeshCentral Remote Desktop
|
// MeshCentral Remote Desktop
|
||||||
agentDesktop.ProcessData(data);
|
agentDesktop.ProcessData(data);
|
||||||
} else if (recFileProtocol == 101) {
|
} else if (recFileProtocol == 101) {
|
||||||
// Intel AMT KVM
|
// Intel AMT KVM
|
||||||
//if ((readState == 0) && (rstr2hex(data) == '140000000400000000')) { readState = 1; }
|
if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) { readState = 1; } // We are not authenticated, KVM data starts here.
|
||||||
if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) { readState = 1; }
|
|
||||||
else if (readState == 1) { amtDesktop.ProcessData(data); }
|
else if (readState == 1) { amtDesktop.ProcessData(data); }
|
||||||
//console.log(rstr2hex(data));
|
}
|
||||||
|
} else if ((type == 2) && flagBinary && flagUser) {
|
||||||
|
// User --> Device data
|
||||||
|
if (recFileProtocol == 101) {
|
||||||
|
// Intel AMT KVM
|
||||||
|
if (rstr2hex(data) == '0000000008080001000700070003050200000000') { amtDesktop.bpp = 1; } // Switch to 1 byte per pixel.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +266,7 @@
|
|||||||
readState = 0;
|
readState = 0;
|
||||||
waitTimerArgs = null;
|
waitTimerArgs = null;
|
||||||
currentDeltaTimeTotalSec = 0;
|
currentDeltaTimeTotalSec = 0;
|
||||||
|
recFileEndTime = 0;
|
||||||
if (waitTimer != null) { clearTimeout(waitTimer); waitTimer = null; }
|
if (waitTimer != null) { clearTimeout(waitTimer); waitTimer = null; }
|
||||||
QH('deskstatus', '');
|
QH('deskstatus', '');
|
||||||
QE('PlayButton', false);
|
QE('PlayButton', false);
|
||||||
@ -267,6 +296,7 @@
|
|||||||
recFile = files[0];
|
recFile = files[0];
|
||||||
recFilePtr = 0;
|
recFilePtr = 0;
|
||||||
readNextBlock(processFirstBlock);
|
readNextBlock(processFirstBlock);
|
||||||
|
readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
|
||||||
}
|
}
|
||||||
|
|
||||||
var dragtimer = null;
|
var dragtimer = null;
|
||||||
@ -309,6 +339,7 @@
|
|||||||
recFile = files[0];
|
recFile = files[0];
|
||||||
recFilePtr = 0;
|
recFilePtr = 0;
|
||||||
readNextBlock(processFirstBlock);
|
readNextBlock(processFirstBlock);
|
||||||
|
readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
|
||||||
Q('OpenFileButton').blur();
|
Q('OpenFileButton').blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,13 +389,18 @@
|
|||||||
QE('RestartButton', false);
|
QE('RestartButton', false);
|
||||||
QS('progressbar').width = '0px';
|
QS('progressbar').width = '0px';
|
||||||
QH('timespan', '00:00:00');
|
QH('timespan', '00:00:00');
|
||||||
if (agentDesktop) { agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height); }
|
if (agentDesktop) {
|
||||||
if (amtDesktop) { amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height); amtDesktop = CreateAmtRemoteDesktop('Desk'); amtDesktop.onScreenSizeChange = deskAdjust; amtDesktop.State = 3; }
|
agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
|
||||||
|
} else if (amtDesktop) {
|
||||||
|
amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height);
|
||||||
|
amtDesktop = CreateAmtRemoteDesktop('Desk');
|
||||||
|
amtDesktop.onScreenSizeChange = deskAdjust;
|
||||||
|
amtDesktop.State = 3;
|
||||||
|
amtDesktop.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearConsoleMsg() {
|
function clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); }
|
||||||
console.log('clearConsoleMsg');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle the web page to full screen
|
// Toggle the web page to full screen
|
||||||
function toggleAspectRatio(toggle) {
|
function toggleAspectRatio(toggle) {
|
||||||
@ -404,9 +440,9 @@
|
|||||||
} else {
|
} else {
|
||||||
var wNew = ((deskW * parentH) / deskH) + 'px';
|
var wNew = ((deskW * parentH) / deskH) + 'px';
|
||||||
//if (webPageFullScreen || fullscreen) {
|
//if (webPageFullScreen || fullscreen) {
|
||||||
//QS('Desk').height = null;
|
//QS('Desk').height = null;
|
||||||
//} else {
|
//} else {
|
||||||
QS('Desk').height = '100%';
|
QS('Desk').height = '100%';
|
||||||
//}
|
//}
|
||||||
QS('Desk').width = wNew;
|
QS('Desk').width = wNew;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
|
|||||||
obj.webchannel = null;
|
obj.webchannel = null;
|
||||||
obj.webrtc = null;
|
obj.webrtc = null;
|
||||||
obj.debugmode = 0;
|
obj.debugmode = 0;
|
||||||
|
obj.serverIsRecording = false;
|
||||||
if (domainUrl == null) { domainUrl = '/'; }
|
if (domainUrl == null) { domainUrl = '/'; }
|
||||||
|
|
||||||
// Console Message
|
// Console Message
|
||||||
@ -95,7 +96,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
|
|||||||
obj.xxOnMessage = function (e) {
|
obj.xxOnMessage = function (e) {
|
||||||
//console.log('Recv', e.data, e.data.byteLength, obj.State);
|
//console.log('Recv', e.data, e.data.byteLength, obj.State);
|
||||||
if (obj.State < 3) {
|
if (obj.State < 3) {
|
||||||
if (e.data == 'c') {
|
if ((e.data == 'c') || (e.data == 'cr')) {
|
||||||
|
if (e.data == 'cr') { obj.serverIsRecording = true; }
|
||||||
try { obj.socket.send(obj.protocol); } catch (ex) { }
|
try { obj.socket.send(obj.protocol); } catch (ex) { }
|
||||||
obj.xxStateChange(3);
|
obj.xxStateChange(3);
|
||||||
|
|
||||||
|
@ -245,6 +245,11 @@ var CreateAmtRedirect = function (module, authCookie) {
|
|||||||
if (obj.amtaccumulator.length > 8) { obj.m.ProcessData(obj.amtaccumulator.substring(8)); }
|
if (obj.amtaccumulator.length > 8) { obj.m.ProcessData(obj.amtaccumulator.substring(8)); }
|
||||||
cmdsize = obj.amtaccumulator.length;
|
cmdsize = obj.amtaccumulator.length;
|
||||||
break;
|
break;
|
||||||
|
case 0xF0:
|
||||||
|
// console.log('Session is being recorded');
|
||||||
|
obj.serverIsRecording = true;
|
||||||
|
cmdsize = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length);
|
console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length);
|
||||||
obj.Stop(4);
|
obj.Stop(4);
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -443,6 +443,7 @@
|
|||||||
<div class='deskareaicon' title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
|
<div class='deskareaicon' title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
|
||||||
<div class='deskareaicon' title="Rotate Left" onclick="drotate(-1)">↺</div>
|
<div class='deskareaicon' title="Rotate Left" onclick="drotate(-1)">↺</div>
|
||||||
<div class='deskareaicon' title="Rotate Right" onclick="drotate(1)">↻</div>
|
<div class='deskareaicon' title="Rotate Right" onclick="drotate(1)">↻</div>
|
||||||
|
<div id="deskRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px"></div>
|
||||||
<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="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() class="mR">
|
<input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick=deskSaveImage() class="mR">
|
||||||
<input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() class="mR" />
|
<input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() class="mR" />
|
||||||
@ -541,6 +542,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="areaHead">
|
<td class="areaHead">
|
||||||
<div class="toright2">
|
<div class="toright2">
|
||||||
|
<div id="termRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
|
||||||
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
|
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -600,6 +602,7 @@
|
|||||||
<td class="areaHead">
|
<td class="areaHead">
|
||||||
<div class="toright2">
|
<div class="toright2">
|
||||||
<input id="filesActionsBtn" type=button title="Perform power actions on the device" value=Actions onclick=deviceActionFunction() />
|
<input id="filesActionsBtn" type=button title="Perform power actions on the device" value=Actions onclick=deviceActionFunction() />
|
||||||
|
<div id="filesRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) type="button" style="display:none">
|
<input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) type="button" style="display:none">
|
||||||
@ -4816,6 +4819,7 @@
|
|||||||
desktopNode = desktop = null;
|
desktopNode = desktop = null;
|
||||||
QV('DeskFocus', false);
|
QV('DeskFocus', false);
|
||||||
QV('termdisplays', false);
|
QV('termdisplays', false);
|
||||||
|
QV('deskRecordIcon', false);
|
||||||
deskFocusBtn.value = 'All Focus';
|
deskFocusBtn.value = 'All Focus';
|
||||||
if (fullscreen == true) { deskToggleFull(); }
|
if (fullscreen == true) { deskToggleFull(); }
|
||||||
webRtcDesktopReset();
|
webRtcDesktopReset();
|
||||||
@ -4823,6 +4827,9 @@
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
if (desktop.serverIsRecording == true) { QV('deskRecordIcon', true); }
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
//console.log('Unknown onDesktopStateChange state', state);
|
//console.log('Unknown onDesktopStateChange state', state);
|
||||||
break;
|
break;
|
||||||
@ -5380,12 +5387,14 @@
|
|||||||
// Disconnected, clear the terminal
|
// Disconnected, clear the terminal
|
||||||
QE('termSizeList', true);
|
QE('termSizeList', true);
|
||||||
QH('termtitle', '');
|
QH('termtitle', '');
|
||||||
|
QV('termRecordIcon', false);
|
||||||
xterminal.m.TermResetScreen();
|
xterminal.m.TermResetScreen();
|
||||||
xterminal.m.TermDraw();
|
xterminal.m.TermDraw();
|
||||||
if (terminal != null) { terminal.Stop(); terminal = null; }
|
if (terminal != null) { terminal.Stop(); terminal = null; }
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
QE('termSizeList', false);
|
QE('termSizeList', false);
|
||||||
|
if (xterminal.serverIsRecording == true) { QV('termRecordIcon', true); }
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
QE('termSizeList', false);
|
QE('termSizeList', false);
|
||||||
@ -5531,12 +5540,14 @@
|
|||||||
p13filetreelocation = [];
|
p13filetreelocation = [];
|
||||||
QH('p13currentpath', '');
|
QH('p13currentpath', '');
|
||||||
QE('p13FolderUp', false);
|
QE('p13FolderUp', false);
|
||||||
|
QV('filesRecordIcon', false);
|
||||||
p13setActions();
|
p13setActions();
|
||||||
if (files != null) { files.Stop(); files = null; }
|
if (files != null) { files.Stop(); files = null; }
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
p13targetpath = '';
|
p13targetpath = '';
|
||||||
files.sendText({ action: 'ls', reqid: 1, path: '' });
|
files.sendText({ action: 'ls', reqid: 1, path: '' });
|
||||||
|
if (files.serverIsRecording == true) { QV('filesRecordIcon', true); }
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//console.log('Unknown onFilesStateChange state', state);
|
//console.log('Unknown onFilesStateChange state', state);
|
||||||
|
File diff suppressed because one or more lines are too long
@ -579,7 +579,7 @@
|
|||||||
socket.onerror = function (e) { /*console.error(e);*/ }
|
socket.onerror = function (e) { /*console.error(e);*/ }
|
||||||
socket.onclose = function () { disconnect(); }
|
socket.onclose = function () { disconnect(); }
|
||||||
socket.onmessage = function (msg) {
|
socket.onmessage = function (msg) {
|
||||||
if ((state < 2) && (typeof msg.data == 'string') && (msg.data == 'c')) {
|
if ((state < 2) && (typeof msg.data == 'string') && ((msg.data == 'c') || (msg.data == 'cr'))) {
|
||||||
hangUpButtonClick(0, true);
|
hangUpButtonClick(0, true);
|
||||||
hangUpButtonClick(1, true);
|
hangUpButtonClick(1, true);
|
||||||
hangUpButtonClick(2, true);
|
hangUpButtonClick(2, true);
|
||||||
|
37
webserver.js
37
webserver.js
@ -1978,6 +1978,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: user._id, username: user.name, ipaddr: cleanRemoteAddr(ws._socket.remoteAddress), nodeid: node._id, intelamt: true, protocol: (req.query.p == 2) ? 101 : 100, time: new Date().toLocaleString() })
|
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: user._id, username: user.name, ipaddr: cleanRemoteAddr(ws._socket.remoteAddress), nodeid: node._id, intelamt: true, protocol: (req.query.p == 2) ? 101 : 100, time: new Date().toLocaleString() })
|
||||||
recordingEntry(fd, 1, 0, firstBlock, function () { });
|
recordingEntry(fd, 1, 0, firstBlock, function () { });
|
||||||
ws.logfile = { fd: fd, lock: false };
|
ws.logfile = { fd: fd, lock: false };
|
||||||
|
if (req.query.p == 2) { ws.send(Buffer.from(String.fromCharCode(0xF0), 'binary')); } // Intel AMT Redirection: Indicate the session is being recorded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2073,7 +2074,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
||||||
|
|
||||||
// Close the recording file
|
// Close the recording file
|
||||||
if (ws.logfile != null) { obj.fs.close(ws.logfile.fd); ws.logfile = null; }
|
if (ws.logfile != null) {
|
||||||
|
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) {
|
||||||
|
obj.fs.close(fd);
|
||||||
|
ws.logfile = null;
|
||||||
|
}, ws);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the web socket is closed, close the associated TCP connection.
|
// If the web socket is closed, close the associated TCP connection.
|
||||||
@ -2082,7 +2088,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
||||||
|
|
||||||
// Close the recording file
|
// Close the recording file
|
||||||
if (ws.logfile != null) { obj.fs.close(ws.logfile.fd); ws.logfile = null; }
|
if (ws.logfile != null) {
|
||||||
|
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) {
|
||||||
|
obj.fs.close(fd);
|
||||||
|
ws.logfile = null;
|
||||||
|
}, ws);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.forwardclient.onStateChange = function (ciraconn, state) {
|
ws.forwardclient.onStateChange = function (ciraconn, state) {
|
||||||
@ -2156,7 +2167,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
||||||
|
|
||||||
// Close the recording file
|
// Close the recording file
|
||||||
if (ws.logfile != null) { obj.fs.close(ws.logfile.fd); ws.logfile = null; }
|
if (ws.logfile != null) {
|
||||||
|
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
|
||||||
|
obj.fs.close(fd);
|
||||||
|
ws.logfile = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the web socket is closed, close the associated TCP connection.
|
// If the web socket is closed, close the associated TCP connection.
|
||||||
@ -2165,7 +2181,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
||||||
|
|
||||||
// Close the recording file
|
// Close the recording file
|
||||||
if (ws.logfile != null) { obj.fs.close(ws.logfile.fd); ws.logfile = null; }
|
if (ws.logfile != null) {
|
||||||
|
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
|
||||||
|
obj.fs.close(fd);
|
||||||
|
ws.logfile = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Compute target port
|
// Compute target port
|
||||||
@ -3467,7 +3488,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function cleanRemoteAddr(addr) { if (addr.startsWith('::ffff:')) { return addr.substring(7); } else { return addr; } }
|
function cleanRemoteAddr(addr) { if (addr.startsWith('::ffff:')) { return addr.substring(7); } else { return addr; } }
|
||||||
|
|
||||||
// Record a new entry in a recording log
|
// Record a new entry in a recording log
|
||||||
function recordingEntry(fd, type, flags, data, func) {
|
function recordingEntry(fd, type, flags, data, func, tag) {
|
||||||
try {
|
try {
|
||||||
if (typeof data == 'string') {
|
if (typeof data == 'string') {
|
||||||
// String write
|
// String write
|
||||||
@ -3477,7 +3498,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
header.writeInt32BE(blockData.length, 4); // Size
|
header.writeInt32BE(blockData.length, 4); // Size
|
||||||
header.writeIntBE(new Date(), 10, 6); // Time
|
header.writeIntBE(new Date(), 10, 6); // Time
|
||||||
var block = Buffer.concat([header, blockData]);
|
var block = Buffer.concat([header, blockData]);
|
||||||
obj.fs.write(fd, block, 0, block.length, func);
|
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||||
} else {
|
} else {
|
||||||
// Binary write
|
// Binary write
|
||||||
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||||
@ -3486,9 +3507,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
header.writeInt32BE(data.length, 4); // Size
|
header.writeInt32BE(data.length, 4); // Size
|
||||||
header.writeIntBE(new Date(), 10, 6); // Time
|
header.writeIntBE(new Date(), 10, 6); // Time
|
||||||
var block = Buffer.concat([header, data]);
|
var block = Buffer.concat([header, data]);
|
||||||
obj.fs.write(fd, block, 0, block.length, func);
|
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||||
}
|
}
|
||||||
} catch (ex) { console.log(ex); func(); }
|
} catch (ex) { console.log(ex); func(fd, tag); }
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
Loading…
Reference in New Issue
Block a user