mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-25 14:45:52 -05:00
Added terminal device sharing.
This commit is contained in:
parent
76cd48105f
commit
1b2a63977b
@ -564,6 +564,7 @@
|
|||||||
<Content Include="views\messenger.handlebars" />
|
<Content Include="views\messenger.handlebars" />
|
||||||
<Content Include="views\mstsc.handlebars" />
|
<Content Include="views\mstsc.handlebars" />
|
||||||
<Content Include="views\player.handlebars" />
|
<Content Include="views\player.handlebars" />
|
||||||
|
<Content Include="views\terminal.handlebars" />
|
||||||
<Content Include="views\terms-mobile.handlebars" />
|
<Content Include="views\terms-mobile.handlebars" />
|
||||||
<Content Include="views\terms.handlebars" />
|
<Content Include="views\terms.handlebars" />
|
||||||
<Content Include="views\xterm.handlebars" />
|
<Content Include="views\xterm.handlebars" />
|
||||||
|
1
db.js
1
db.js
@ -463,6 +463,7 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
case 'ugrp': { dbUGrpChange(change, true); break; } // A user account has created
|
case 'ugrp': { dbUGrpChange(change, true); break; } // A user account has created
|
||||||
}
|
}
|
||||||
} else if (change.operationType == 'delete') {
|
} else if (change.operationType == 'delete') {
|
||||||
|
if ((change.documentKey == null) || (change.documentKey._id == null)) return;
|
||||||
var splitId = change.documentKey._id.split('/');
|
var splitId = change.documentKey._id.split('/');
|
||||||
switch (splitId[0]) {
|
switch (splitId[0]) {
|
||||||
case 'node': {
|
case 'node': {
|
||||||
|
@ -621,7 +621,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
|||||||
performRelay();
|
performRelay();
|
||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
} else if ((cookie != null) && (cookie.nid != null) && (typeof cookie.r == 'number') && (typeof cookie.cf == 'number') && (typeof cookie.gn == 'string')) {
|
} else if ((cookie != null) && (cookie.nid != null) && (typeof cookie.r == 'number') && (typeof cookie.p == 'number') && (typeof cookie.cf == 'number') && (typeof cookie.gn == 'string')) {
|
||||||
// We have routing instructions in the cookie, but first, check user access for this node.
|
// We have routing instructions in the cookie, but first, check user access for this node.
|
||||||
parent.db.Get(cookie.nid, function (err, docs) {
|
parent.db.Get(cookie.nid, function (err, docs) {
|
||||||
if (docs.length == 0) { console.log('ERR: Node not found'); try { obj.close(); } catch (e) { } return; } // Disconnect websocket
|
if (docs.length == 0) { console.log('ERR: Node not found'); try { obj.close(); } catch (e) { } return; } // Disconnect websocket
|
||||||
@ -633,7 +633,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
|||||||
// Send connection request to agent
|
// Send connection request to agent
|
||||||
if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); }
|
if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); }
|
||||||
const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
|
const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
|
||||||
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', userid: user._id, value: '*/meshrelay.ashx?p=2&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, usage: 2, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
|
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', userid: user._id, value: '*/meshrelay.ashx?p=' + cookie.p + '&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, usage: 2, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
|
||||||
if (typeof domain.consentmessages == 'object') {
|
if (typeof domain.consentmessages == 'object') {
|
||||||
if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; }
|
if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; }
|
||||||
if (typeof domain.consentmessages.desktop == 'string') { command.soptions.consentMsgDesktop = domain.consentmessages.desktop; }
|
if (typeof domain.consentmessages.desktop == 'string') { command.soptions.consentMsgDesktop = domain.consentmessages.desktop; }
|
||||||
|
10
meshuser.js
10
meshuser.js
@ -4707,6 +4707,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
else if ((command.start != null) && (typeof command.start != 'number')) { err = 'Invalid start time'; } // Check the start time in seconds
|
else if ((command.start != null) && (typeof command.start != 'number')) { err = 'Invalid start time'; } // Check the start time in seconds
|
||||||
else if ((command.end != null) && (typeof command.end != 'number')) { err = 'Invalid end time'; } // Check the end time in seconds
|
else if ((command.end != null) && (typeof command.end != 'number')) { err = 'Invalid end time'; } // Check the end time in seconds
|
||||||
else if (common.validateInt(command.consent, 0, 256) == false) { err = 'Invalid flags'; } // Check the flags
|
else if (common.validateInt(command.consent, 0, 256) == false) { err = 'Invalid flags'; } // Check the flags
|
||||||
|
else if (common.validateInt(command.p, 1, 2) == false) { err = 'Invalid protocol'; } // Check the protocol, 1 = Terminal, 2 = Desktop
|
||||||
else if ((command.expire == null) && ((command.start == null) || (command.end == null) || (command.start > command.end))) { err = 'No time specified'; } // Check that a time range is present
|
else if ((command.expire == null) && ((command.start == null) || (command.end == null) || (command.start > command.end))) { err = 'No time specified'; } // Check that a time range is present
|
||||||
else {
|
else {
|
||||||
if (command.nodeid.split('/').length == 1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
|
if (command.nodeid.split('/').length == 1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
|
||||||
@ -4740,7 +4741,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
expireTime = command.end * 1000;
|
expireTime = command.end * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
const inviteCookie = parent.parent.encodeCookie({ a: 5, uid: user._id, gn: command.guestname, nid: node._id, cf: command.consent, start: startTime, expire: expireTime, pid: publicid }, parent.parent.invitationLinkEncryptionKey);
|
const inviteCookie = parent.parent.encodeCookie({ a: 5, p: command.p, uid: user._id, gn: command.guestname, nid: node._id, cf: command.consent, start: startTime, expire: expireTime, pid: publicid }, parent.parent.invitationLinkEncryptionKey);
|
||||||
if (inviteCookie == null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'createDeviceShareLink', responseid: command.responseid, result: 'Unable to generate shareing cookie' })); } catch (ex) { } } return; }
|
if (inviteCookie == null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'createDeviceShareLink', responseid: command.responseid, result: 'Unable to generate shareing cookie' })); } catch (ex) { } } return; }
|
||||||
command.start = startTime;
|
command.start = startTime;
|
||||||
command.expire = expireTime;
|
command.expire = expireTime;
|
||||||
@ -4750,13 +4751,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
|
var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
|
||||||
var xdomain = (domain.dns == null) ? domain.id : '';
|
var xdomain = (domain.dns == null) ? domain.id : '';
|
||||||
if (xdomain != '') xdomain += '/';
|
if (xdomain != '') xdomain += '/';
|
||||||
var url = 'https://' + serverName + ':' + httpsPort + '/' + xdomain + 'desktop?c=' + inviteCookie;
|
var page = (command.p == 1) ? 'terminal' : 'desktop';
|
||||||
if (serverName.split('.') == 1) { url = '/' + xdomain + 'desktop?c=' + inviteCookie; }
|
var url = 'https://' + serverName + ':' + httpsPort + '/' + xdomain + page + '?c=' + inviteCookie;
|
||||||
|
if (serverName.split('.') == 1) { url = '/' + xdomain + page + '?c=' + inviteCookie; }
|
||||||
command.url = url;
|
command.url = url;
|
||||||
ws.send(JSON.stringify(command));
|
ws.send(JSON.stringify(command));
|
||||||
|
|
||||||
// Create a device sharing database entry
|
// Create a device sharing database entry
|
||||||
parent.db.Set({ type: 'deviceshare', nodeid: node._id, domain: node.domain, publicid: publicid, startTime: startTime, expireTime: expireTime, userid: user._id, guestName: command.guestname, consent: command.consent, url: url });
|
parent.db.Set({ _id: 'deviceshare-' + publicid, type: 'deviceshare', nodeid: node._id, p: command.p, domain: node.domain, publicid: publicid, startTime: startTime, expireTime: expireTime, userid: user._id, guestName: command.guestname, consent: command.consent, url: url });
|
||||||
|
|
||||||
// Send out an event that we added a device share
|
// Send out an event that we added a device share
|
||||||
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
||||||
|
2
public/scripts/agent-desktop-0.0.2-min.js
vendored
2
public/scripts/agent-desktop-0.0.2-min.js
vendored
File diff suppressed because one or more lines are too long
@ -76,7 +76,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
|
|||||||
var controlMsg;
|
var controlMsg;
|
||||||
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
|
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
|
||||||
if (controlMsg.ctrlChannel != '102938') { obj.m.ProcessData(msg); return; }
|
if (controlMsg.ctrlChannel != '102938') { obj.m.ProcessData(msg); return; }
|
||||||
//console.log(controlMsg);
|
|
||||||
if ((typeof args != 'undefined') && args.redirtrace) { console.log('RedirRecv', controlMsg); }
|
if ((typeof args != 'undefined') && args.redirtrace) { console.log('RedirRecv', controlMsg); }
|
||||||
if (controlMsg.type == 'console') {
|
if (controlMsg.type == 'console') {
|
||||||
obj.setConsoleMessage(controlMsg.msg, controlMsg.msgid, controlMsg.msgargs, controlMsg.timeout);
|
obj.setConsoleMessage(controlMsg.msg, controlMsg.msgid, controlMsg.msgargs, controlMsg.timeout);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3107,7 +3107,7 @@
|
|||||||
if (message.consent & 64) { y.push("Privacy bar"); }
|
if (message.consent & 64) { y.push("Privacy bar"); }
|
||||||
if (y.length == 0) { y.push("None"); }
|
if (y.length == 0) { y.push("None"); }
|
||||||
x += addHtmlValue("User Consent", y.join(', '));
|
x += addHtmlValue("User Consent", y.join(', '));
|
||||||
x += '<div id=agentInvitationLinkDiv style="text-align:center;font-size:large;margin:16px"><a href="' + message.url + '" id=agentInvitationLink rel="noreferrer noopener" target="_blank" style=cursor:pointer>' + "Remote Desktop Link" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy link to clipboard" + '" style=cursor:pointer onclick=d2CopyInviteToClip()></div></div>';
|
x += '<div id=agentInvitationLinkDiv style="text-align:center;font-size:large;margin:16px"><a href="' + message.url + '" id=agentInvitationLink rel="noreferrer noopener" target="_blank" style=cursor:pointer>' + ((message.p == 1)?"Remote Terminal Link":"Remote Desktop Link") + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy link to clipboard" + '" style=cursor:pointer onclick=d2CopyInviteToClip()></div></div>';
|
||||||
setDialogMode(2, "Share Device", 1, null, x);
|
setDialogMode(2, "Share Device", 1, null, x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6042,15 +6042,14 @@
|
|||||||
for (var i = 0; i < deviceShares.length; i++) {
|
for (var i = 0; i < deviceShares.length; i++) {
|
||||||
var dshare = deviceShares[i];
|
var dshare = deviceShares[i];
|
||||||
var trash = '<a href="' + dshare.url + '" rel="noreferrer noopener" target=_blank title="' + "Device Sharing Link" + '" style=cursor:pointer><img src=images/link2.png border=0 height=10 width=10></a> <a href=# onclick=\'return p30removeDeviceSharing(event,"' + encodeURIComponentEx(currentNode._id) + '","' + encodeURIComponentEx(dshare.publicid) + '","' + encodeURIComponentEx(dshare.guestName) + '")\' title="' + "Remove device sharing" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
|
var trash = '<a href="' + dshare.url + '" rel="noreferrer noopener" target=_blank title="' + "Device Sharing Link" + '" style=cursor:pointer><img src=images/link2.png border=0 height=10 width=10></a> <a href=# onclick=\'return p30removeDeviceSharing(event,"' + encodeURIComponentEx(currentNode._id) + '","' + encodeURIComponentEx(dshare.publicid) + '","' + encodeURIComponentEx(dshare.guestName) + '")\' title="' + "Remove device sharing" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
|
||||||
var details = printFlexDateTime(new Date(dshare.startTime)) + ' to ' + printFlexDateTime(new Date(dshare.expireTime));
|
var details = format("{0}, {1} to {2}", ((dshare.p == 1)?"Terminal":"Desktop"), printFlexDateTime(new Date(dshare.startTime)), printFlexDateTime(new Date(dshare.expireTime)));
|
||||||
if (dshare.consent) { if ((dshare.consent & 8) != 0) { details += ', Prompt for consent'; } }
|
if (dshare.consent) { if (((dshare.consent & 8) != 0) || ((dshare.consent & 16) != 0)) { details += ", Prompt for consent"; } }
|
||||||
x += '<tr ' + (((++count % 2) == 0) ? 'style=background-color:#DDD' : '') + '><td style=width:30%><div class=m' + 2 + '></div><div> ' + dshare.guestName + '<div></div></div></td><td style=width:70%><div style=float:right>' + trash + '</div><div>' + details + '</div></td></tr>';
|
x += '<tr ' + (((++count % 2) == 0) ? 'style=background-color:#DDD' : '') + '><td style=width:30%><div class=m' + 2 + '></div><div> ' + dshare.guestName + '<div></div></div></td><td style=width:70%><div style=float:right>' + trash + '</div><div>' + details + '</div></td></tr>';
|
||||||
}
|
}
|
||||||
x += '</tbody></table>';
|
x += '</tbody></table>';
|
||||||
}
|
}
|
||||||
QH('p10html4', x);
|
QH('p10html4', x);
|
||||||
|
|
||||||
|
|
||||||
// Change the URL
|
// Change the URL
|
||||||
var urlviewmode = '';
|
var urlviewmode = '';
|
||||||
if (((features & 0x10000000) == 0) && (xxcurrentView >= 10) && (xxcurrentView <= 19) && (currentNode != null)) {
|
if (((features & 0x10000000) == 0) && (xxcurrentView >= 10) && (xxcurrentView <= 19) && (currentNode != null)) {
|
||||||
@ -6208,24 +6207,11 @@
|
|||||||
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devToast').value });
|
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devToast').value });
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
function showShareDevice() {
|
function showShareDevice() {
|
||||||
if (xxdialogMode) return;
|
if (xxdialogMode) return;
|
||||||
var y = '', x = "Creates a link that allows a guest without an account to remote desktop into this device for up to 1 hour." + '<br /><br />';
|
var y = '', x = "Creates a link that allows a guest without an account to remote control this device for a limited time." + '<br /><br />';
|
||||||
x += addHtmlValue("Guest Name", '<input id=d2inviteName style=width:250px maxlength=128 type=text onkeyup=showShareDeviceValidate() />');
|
|
||||||
var options = { 1 : "1 minute", 5 : "5 minutes", 10 : "10 minutes", 15 : "15 minutes", 30 : "30 minutes", 45 : "45 minutes", 60 : "60 minutes", 120 : "2 hours", 240 : "4 hours", 480 : "8 hours", 720 : "12 hours", 960 : "16 hours", 1440 : "24 hours", 2880 : "2 days", 5760 : "4 days" }
|
|
||||||
for (var i in options) { if (serverinfo.maxGuestSessionSharingTime >= i) { y += '<option value=' + i + '>' + options[i] + '</option>'; } }
|
|
||||||
x += addHtmlValue("Expire Time", '<select id=d2inviteExpire style=float:right;width:250px>' + y + '</select>');
|
|
||||||
x += addHtmlValue("User Consent", '<select id=d2userConsent style=float:right;width:250px><option value=73>' + "Prompt for consent" + '</option><option value=65>' + "Notify Only" + '</option></select>');
|
|
||||||
setDialogMode(2, "Share Device", 3, showShareDeviceEx, x);
|
|
||||||
showShareDeviceValidate();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function showShareDevice() {
|
|
||||||
if (xxdialogMode) return;
|
|
||||||
var y = '', x = "Creates a link that allows a guest without an account to remote desktop into this device for a limited time." + '<br /><br />';
|
|
||||||
x += addHtmlValue("Guest Name", '<input id=d2inviteName style=width:250px maxlength=128 type=text onkeyup=showShareDeviceValidate() />');
|
x += addHtmlValue("Guest Name", '<input id=d2inviteName style=width:250px maxlength=128 type=text onkeyup=showShareDeviceValidate() />');
|
||||||
|
x += addHtmlValue("Type", '<select id=d2shareType style=float:right;width:250px onchange=showShareDeviceValidate()><option value=2>' + "Desktop" + '</option><option value=1>' + "Terminal" + '</option></select>');
|
||||||
var options = { 1 : "1 minute", 5 : "5 minutes", 10 : "10 minutes", 15 : "15 minutes", 30 : "30 minutes", 45 : "45 minutes", 60 : "60 minutes", 120 : "2 hours", 240 : "4 hours", 480 : "8 hours", 720 : "12 hours", 960 : "16 hours", 1440 : "24 hours", 2880 : "2 days", 5760 : "4 days" }
|
var options = { 1 : "1 minute", 5 : "5 minutes", 10 : "10 minutes", 15 : "15 minutes", 30 : "30 minutes", 45 : "45 minutes", 60 : "60 minutes", 120 : "2 hours", 240 : "4 hours", 480 : "8 hours", 720 : "12 hours", 960 : "16 hours", 1440 : "24 hours", 2880 : "2 days", 5760 : "4 days" }
|
||||||
for (var i in options) { y += '<option value=' + i + '>' + options[i] + '</option>'; }
|
for (var i in options) { y += '<option value=' + i + '>' + options[i] + '</option>'; }
|
||||||
x += addHtmlValue("Validity", '<select id=d2timeRange style=float:right;width:250px onchange=showShareDeviceValidate()><option value=0>' + "Starting now" + '</option><option value=1>' + "Time range" + '</option></select>');
|
x += addHtmlValue("Validity", '<select id=d2timeRange style=float:right;width:250px onchange=showShareDeviceValidate()><option value=0>' + "Starting now" + '</option><option value=1>' + "Time range" + '</option></select>');
|
||||||
@ -6234,7 +6220,7 @@
|
|||||||
x += '</div><div id=d2moderange style=display:none>';
|
x += '</div><div id=d2moderange style=display:none>';
|
||||||
x += addHtmlValue("Time Range", '<input id=d2timeRangeSelector style=float:right;width:250px class=flatpickr type="text" placeholder="Select Date & Time.." data-id="altinput">');
|
x += addHtmlValue("Time Range", '<input id=d2timeRangeSelector style=float:right;width:250px class=flatpickr type="text" placeholder="Select Date & Time.." data-id="altinput">');
|
||||||
x += '</div>';
|
x += '</div>';
|
||||||
x += addHtmlValue("User Consent", '<select id=d2userConsent style=float:right;width:250px><option value=73>' + "Prompt for consent" + '</option><option value=65>' + "Notify Only" + '</option></select>');
|
x += addHtmlValue("User Consent", '<select id=d2userConsent style=float:right;width:250px><option value=1>' + "Prompt for consent" + '</option><option value=0>' + "Notify Only" + '</option></select>');
|
||||||
setDialogMode(2, "Share Device", 3, showShareDeviceEx, x);
|
setDialogMode(2, "Share Device", 3, showShareDeviceEx, x);
|
||||||
showShareDeviceValidate();
|
showShareDeviceValidate();
|
||||||
var tomorrow = new Date();
|
var tomorrow = new Date();
|
||||||
@ -6253,10 +6239,13 @@
|
|||||||
QE('idx_dlgOkButton', ok);
|
QE('idx_dlgOkButton', ok);
|
||||||
}
|
}
|
||||||
function showShareDeviceEx(b, tag) {
|
function showShareDeviceEx(b, tag) {
|
||||||
|
var consent = 0;
|
||||||
|
if (Q('d2shareType').value == 1) { if (Q('d2userConsent').value == 1) { consent = 18; } else { consent = 2; } } // Terminal Consent: 2 = Notify, 16 = Prompt
|
||||||
|
if (Q('d2shareType').value == 2) { if (Q('d2userConsent').value == 1) { consent = 73; } else { consent = 65; } } // Desktop Consent: 1 = Notify, 8 = Prompt, 64 = Privacy bar
|
||||||
if (Q('d2timeRange').value == 0) {
|
if (Q('d2timeRange').value == 0) {
|
||||||
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), expire: parseInt(Q('d2inviteExpire').value), consent: parseInt(Q('d2userConsent').value) });
|
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: parseInt(Q('d2shareType').value), expire: parseInt(Q('d2inviteExpire').value), consent: consent });
|
||||||
} else {
|
} else {
|
||||||
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), start: Math.floor(tag.selectedDates[0].getTime() / 1000), end: Math.floor(tag.selectedDates[1].getTime() / 1000), consent: parseInt(Q('d2userConsent').value) });
|
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: parseInt(Q('d2shareType').value), start: Math.floor(tag.selectedDates[0].getTime() / 1000), end: Math.floor(tag.selectedDates[1].getTime() / 1000), consent: consent });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,8 +397,7 @@
|
|||||||
desktop.contype = 2;
|
desktop.contype = 2;
|
||||||
} else if ((contype == null) || (contype == 1) || (contype == 3)) {
|
} else if ((contype == null) || (contype == 1) || (contype == 3)) {
|
||||||
// Setup the Mesh Agent remote desktop
|
// Setup the Mesh Agent remote desktop
|
||||||
var meshserver = null;
|
desktop = CreateAgentRedirect(null, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
|
||||||
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
|
|
||||||
desktop.m.mouseCursorActive(true);
|
desktop.m.mouseCursorActive(true);
|
||||||
desktop.debugmode = debugmode;
|
desktop.debugmode = debugmode;
|
||||||
desktop.m.debugmode = debugmode;
|
desktop.m.debugmode = debugmode;
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
if (titleid == 1) { title = "Account Verification"; }
|
if (titleid == 1) { title = "Account Verification"; }
|
||||||
if (titleid == 2) { title = "Desktop Sharing"; }
|
if (titleid == 2) { title = "Desktop Sharing"; }
|
||||||
if (titleid == 3) { title = "Server Under Maintenance"; }
|
if (titleid == 3) { title = "Server Under Maintenance"; }
|
||||||
|
if (titleid == 4) { title = "Terminal Sharing"; }
|
||||||
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
||||||
QH('mainTitle', title);
|
QH('mainTitle', title);
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
if (titleid == 1) { title = "Account Verification"; }
|
if (titleid == 1) { title = "Account Verification"; }
|
||||||
if (titleid == 2) { title = "Desktop Sharing"; }
|
if (titleid == 2) { title = "Desktop Sharing"; }
|
||||||
if (titleid == 3) { title = "Server Under Maintenance"; }
|
if (titleid == 3) { title = "Server Under Maintenance"; }
|
||||||
|
if (titleid == 4) { title = "Terminal Sharing"; }
|
||||||
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
||||||
QH('mainTitle', title);
|
QH('mainTitle', title);
|
||||||
|
|
||||||
|
454
views/terminal.handlebars
Normal file
454
views/terminal.handlebars
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="robots" content="noindex,nofollow">
|
||||||
|
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
|
||||||
|
<link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
|
||||||
|
<link rel="apple-touch-icon" href="/favicon-303x303.png" />
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1{{min}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0{{{min}}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.1{{{min}}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0{{{min}}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/amt-terminal-0.0.2{{min}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/xterm{{{min}}}.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/xterm-addon-fit{{{min}}}.js"></script>
|
||||||
|
<script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
|
||||||
|
<title>{{{title}}}</title>
|
||||||
|
</head>
|
||||||
|
<body style="overflow:hidden;background-color:black">
|
||||||
|
<div id=p12 style="overflow:hidden">
|
||||||
|
<div id="p12warning" onclick=showFeaturesDlg()>
|
||||||
|
<div class="icon2"></div>
|
||||||
|
<div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
|
||||||
|
</div>
|
||||||
|
<div id="p12warning2" onclick=showPowerActionDlg()>
|
||||||
|
<div class="icon2"></div>
|
||||||
|
<div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
|
||||||
|
</div>
|
||||||
|
<div class="areaHead" style="position:absolute;top:0;left:0;right:0;height:24px">
|
||||||
|
<div class="toright2">
|
||||||
|
<div id="p11power" style="margin-top:3px;margin-right:4px"></div>
|
||||||
|
<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>
|
||||||
|
<div id="terminalCustomUiButtons" style="float:left"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="idx_termFullBtn2" onclick=deskToggleFull(event)> ✖</div>
|
||||||
|
<span id="connectbutton2span"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) 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><span id="termtitle"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="termarea3xdiv" style="position:absolute;top:28px;bottom:28px;left:0;right:0"></div>
|
||||||
|
<div class="areaFoot" style="position:absolute;bottom:0;left:0;right:0;height:24px">
|
||||||
|
<div class="toright2">
|
||||||
|
<span id="TermLatency" title="Terminal Session Latency"></span>
|
||||||
|
<span id="TermTimer" title="Session time"></span>
|
||||||
|
<span id="terminalSettingsButtons" style="display:none">
|
||||||
|
<input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()" />
|
||||||
|
<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()" />
|
||||||
|
</span>
|
||||||
|
<span id="terminalSizeDropDown" style="display:none">
|
||||||
|
<select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option></select>
|
||||||
|
</span>
|
||||||
|
<span id="specialKeyDropDown">
|
||||||
|
<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()" />
|
||||||
|
</span>
|
||||||
|
</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')" style="display:none" />
|
||||||
|
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" style="display:none" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id=p12TermConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
|
||||||
|
<div id=dialog class="noselect" style="display:none">
|
||||||
|
<div id=dialogHeader>
|
||||||
|
<div tabindex=0 id=id_dialogclose onclick=setDialogMode() onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
|
||||||
|
<div id=id_dialogtitle></div>
|
||||||
|
</div>
|
||||||
|
<div id=dialogBody>
|
||||||
|
<div id=dialog1>
|
||||||
|
<div id=id_dialogMessage style=""></div>
|
||||||
|
</div>
|
||||||
|
<div id=dialog2 style="">
|
||||||
|
<div id=id_dialogOptions></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="idx_dlgButtonBar">
|
||||||
|
<input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)">
|
||||||
|
<input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
|
||||||
|
<div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var sessionActivity = null;
|
||||||
|
var desktop = null;
|
||||||
|
var agentPresent = true;
|
||||||
|
var intelAmtPresent = false;
|
||||||
|
var p11DeskConsoleMsgTimer = null;
|
||||||
|
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
||||||
|
var domain = '{{{domain}}}';
|
||||||
|
var domainUrl = '{{{domainurl}}}';
|
||||||
|
var authCookie = '{{{authCookie}}}';
|
||||||
|
var urlargs = parseUriArgs();
|
||||||
|
var debugmode = urlargs.debug;
|
||||||
|
var attemptWebRTC = false;
|
||||||
|
var updateSessionTimer = null;
|
||||||
|
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
|
||||||
|
var webPageFullScreen = false;
|
||||||
|
var terminal = null;
|
||||||
|
var p12TermConsoleMsgTimer = null;
|
||||||
|
var xterm = null;
|
||||||
|
var xtermfit = null;
|
||||||
|
var xtermResizeTimer = null;
|
||||||
|
var expire = '{{{expire}}}';
|
||||||
|
if (expire != '') { QH('p11power', printFlexDateTime(new Date(parseInt(expire)))); }
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
//window.onresize = deskAdjust;
|
||||||
|
//document.onkeypress = ondockeypress;
|
||||||
|
//document.onkeydown = ondockeydown;
|
||||||
|
//document.onkeyup = ondockeyup;
|
||||||
|
updateTerminalButtons();
|
||||||
|
|
||||||
|
window.onresize = function () { if (xtermfit != null) { xtermfit.fit(); } }
|
||||||
|
|
||||||
|
// Terminal special keys
|
||||||
|
var x = '';
|
||||||
|
for (var c = 1; c < 27; c++) x += '<option value=\'' + c + '\'>' + "Ctrl" + '-' + String.fromCharCode(64 + c) + ' (' + c + ')</option>';
|
||||||
|
QH('specialkeylist', x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var terminalNode;
|
||||||
|
function setupTerminal() {
|
||||||
|
// Setup the terminal
|
||||||
|
if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); terminal = null; }
|
||||||
|
terminalNode = currentNode;
|
||||||
|
updateTerminalButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show and enable the right buttons
|
||||||
|
function updateTerminalButtons() {
|
||||||
|
var termState = ((terminal != null) && (terminal.state != 0));
|
||||||
|
|
||||||
|
// Show the right buttons
|
||||||
|
QV('disconnectbutton2span', termState == true);
|
||||||
|
QV('connectbutton2span', termState == false);
|
||||||
|
//QV('terminalSizeDropDown', termState == false);
|
||||||
|
|
||||||
|
// Enable buttons
|
||||||
|
QE('connectbutton2', true);
|
||||||
|
|
||||||
|
// Key buttons
|
||||||
|
QE('ctrlcbutton', termState);
|
||||||
|
QE('ctrlxbutton', termState);
|
||||||
|
QE('escbutton', termState);
|
||||||
|
QE('bsbutton', termState);
|
||||||
|
QE('pastebutton', termState);
|
||||||
|
QE('specialkeylist', termState);
|
||||||
|
QE('specialkeylistinput', termState);
|
||||||
|
|
||||||
|
// Terminal settings
|
||||||
|
QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
|
||||||
|
if (terminal) {
|
||||||
|
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||||||
|
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
|
||||||
|
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display extra buttons on legacy terminal
|
||||||
|
var xtermActive = true;
|
||||||
|
QV('termarea3xdiv', xtermActive);
|
||||||
|
QV('bsbutton', !xtermActive);
|
||||||
|
QV('pastebutton', !xtermActive);
|
||||||
|
QV('devListToolbarViewIcons2', xtermActive);
|
||||||
|
QE('termSizeList', terminal == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the terminal state changes
|
||||||
|
function onTerminalStateChange(xterminal, state) {
|
||||||
|
var xstate = state;
|
||||||
|
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
|
||||||
|
var str = StatusStrs[xstate];
|
||||||
|
if (terminal.webRtcActive == true) { str += ", WebRTC"; }
|
||||||
|
QH('termstatus', str);
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
// Disconnected, clear the terminal
|
||||||
|
QH('termtitle', '');
|
||||||
|
QV('termRecordIcon', false);
|
||||||
|
if (xterm == null) {
|
||||||
|
xterminal.m.TermResetScreen();
|
||||||
|
xterminal.m.TermDraw();
|
||||||
|
} else {
|
||||||
|
xterm.dispose();
|
||||||
|
xterm = xtermfit = null;
|
||||||
|
}
|
||||||
|
if (terminal != null) { terminal.Stop(); terminal = null; }
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (xterminal && (xterminal.serverIsRecording == true)) { QV('termRecordIcon', true); }
|
||||||
|
terminal.startTime = new Date();
|
||||||
|
if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
|
||||||
|
if (xterm != null) { xterm.focus(); }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//console.log('Unhandled onTerminalStateChange state', state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
updateTerminalButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSessionTime() {
|
||||||
|
// Terminal
|
||||||
|
var latencyStr = '', seconds = 0;
|
||||||
|
if (terminal && terminal.startTime) {
|
||||||
|
if (terminal.latency && (terminal.latency.current >= 0)) { latencyStr = format('{0} ms, ', terminal.latency.current); }
|
||||||
|
seconds = Math.floor((new Date() - terminal.startTime) / 1000);
|
||||||
|
QH('TermTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
|
||||||
|
} else {
|
||||||
|
QH('TermTimer', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terminal == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
var autoConnectTerminalTimer = null;
|
||||||
|
function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } }
|
||||||
|
|
||||||
|
// Handles a tunnel to a remote shell
|
||||||
|
function CreateRemoteTunnel(onTunnelUpdate, options) {
|
||||||
|
var obj = { protocol: 1 };
|
||||||
|
if ((options != null) && (typeof options.protocol == 'number')) { obj.protocol = options.protocol; }
|
||||||
|
obj.onTunnelUpdate = onTunnelUpdate;
|
||||||
|
obj.xxStateChange = function (state) { }
|
||||||
|
obj.ProcessBinaryData = function (data) { obj.onTunnelUpdate(data); }
|
||||||
|
obj.ProcessData = function (data) { obj.onTunnelUpdate(data); }
|
||||||
|
obj.terminalEmulation = 1;
|
||||||
|
obj.fxEmulation = 0;
|
||||||
|
obj.lineFeed = '\r\n';
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
|
||||||
|
|
||||||
|
// Send the new terminal size to the agent
|
||||||
|
function xTermSendResize() {
|
||||||
|
xtermResizeTimer = null;
|
||||||
|
if ((xterm != null) && (terminal != null) && (terminal.sendCtrlMsg != null)) { terminal.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: xterm.cols, rows: xterm.rows })); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to translate incoming agent console messages
|
||||||
|
var agentConsoleMessages = ['', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data"];
|
||||||
|
function formatAgentConsoleMessage(msg, msgid, msgargs) {
|
||||||
|
var r;
|
||||||
|
if (msgargs == null) { msgargs = []; }
|
||||||
|
while (msgargs.length < 3) { msgargs.push(''); } // We need to call the format function in a way that works with older browsers and minifier, can't use apply() or ...
|
||||||
|
if (msgid && (msgid < agentConsoleMessages.length)) { r = EscapeHtml(format(agentConsoleMessages[msgid], (msgargs[0]), (msgargs[1]), (msgargs[2]))); } else { r = EscapeHtml(msg); }
|
||||||
|
return r.split('\n').join('<br />') + '<br /><br />';
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectTerminal(e, contype, options) {
|
||||||
|
p12clearConsoleMsg();
|
||||||
|
if (!terminal) {
|
||||||
|
// Terminal setup
|
||||||
|
var termoptions = { protocol: ((options != null) && (typeof options.protocol == 'number')) ? options.protocol : 1 };
|
||||||
|
if (options && options.requireLogin) { termoptions.requireLogin = true; }
|
||||||
|
/*
|
||||||
|
if ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) == -1) {
|
||||||
|
if (Q('termSizeList').value == 1) { termoptions.cols = 80; termoptions.rows = 25; termoptions.xterm = true; }
|
||||||
|
else if (Q('termSizeList').value == 2) { termoptions.cols = 100; termoptions.rows = 30; termoptions.xterm = true; }
|
||||||
|
else if (Q('termSizeList').value == 3) {
|
||||||
|
// TODO: Try to improve terminal auto-size.
|
||||||
|
termoptions.cols = Math.floor((Q('column_l').clientWidth - 60) / 10);
|
||||||
|
termoptions.rows = Math.floor((Q('column_l').clientHeight - 120) / 20);
|
||||||
|
termoptions.xterm = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If shift is pressed
|
||||||
|
if ((e && (e.shiftKey == true))) {
|
||||||
|
if (currentNode.agent.id > 4) {
|
||||||
|
if (termoptions.protocol == 1) { termoptions.protocol = 7; } // Switch to user shell
|
||||||
|
} else {
|
||||||
|
if (termoptions.protocol == 1) { termoptions.protocol = 6; } // Switch to Powershell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a mesh agent xterm terminal
|
||||||
|
QV('termarea3xdiv', true);
|
||||||
|
|
||||||
|
// Setup the terminal with auto-fit
|
||||||
|
if (xterm != null) { xterm.dispose(); }
|
||||||
|
xtermfit = new FitAddon.FitAddon();
|
||||||
|
xterm = new Terminal();
|
||||||
|
if (xtermfit) { xterm.loadAddon(xtermfit); }
|
||||||
|
xterm.open(Q('termarea3xdiv')); // termarea3x
|
||||||
|
xterm.onData(function (data) { if (terminal != null) { terminal.sendText(data); } })
|
||||||
|
if (xtermfit) { xtermfit.fit(); }
|
||||||
|
xterm.onTitleChange(function (title) { QH('termtitle', ' - ' + EscapeHtml(title)); });
|
||||||
|
xterm.onResize(function (size) {
|
||||||
|
// Despam resize
|
||||||
|
if (xtermResizeTimer) clearTimeout(xtermResizeTimer);
|
||||||
|
xtermResizeTimer = setTimeout(xTermSendResize, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup a terminal tunnel to the agent
|
||||||
|
terminal = CreateAgentRedirect(null, CreateRemoteTunnel(tunnelUpdate, options), serverPublicNamePort, authCookie, null, domainUrl);
|
||||||
|
terminal.debugmode = debugmode;
|
||||||
|
terminal.m.debugmode = debugmode;
|
||||||
|
terminal.options = { cols: xterm.cols, rows: xterm.rows };
|
||||||
|
if (options && options.requireLogin) { terminal.options.requireLogin = true; }
|
||||||
|
terminal.Start(null);
|
||||||
|
terminal.onStateChanged = onTerminalStateChange;
|
||||||
|
terminal.contype = 1;
|
||||||
|
terminal.attemptWebRTC = false; // Never do WebRTC on terminal, because of a race condition we can't do it.
|
||||||
|
terminal.onConsoleMessageChange = function (server, msg) {
|
||||||
|
if (terminal.consoleMessage) {
|
||||||
|
Q('p12TermConsoleMsg').innerHTML += formatAgentConsoleMessage(terminal.consoleMessage, terminal.consoleMessageId, terminal.consoleMessageArgs);
|
||||||
|
QV('p12TermConsoleMsg', true);
|
||||||
|
if (p12TermConsoleMsgTimer != null) { clearTimeout(p12TermConsoleMsgTimer); }
|
||||||
|
if (terminal.consoleMessageTimeout) { p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, terminal.consoleMessageTimeout * 1000); }
|
||||||
|
} else {
|
||||||
|
p12clearConsoleMsg();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
terminal.Stop();
|
||||||
|
terminal = null;
|
||||||
|
}
|
||||||
|
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
|
||||||
|
}
|
||||||
|
|
||||||
|
var terminalEmulations = ["UTF8 Terminal", "Extended ASCII", "Intel ASCII"];
|
||||||
|
function termToggleType() {
|
||||||
|
if (!terminal || xxdialogMode) return;
|
||||||
|
terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
|
||||||
|
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||||||
|
Q('id_ttypebutton').blur(); // Deselect the connect button so the button does not get key presses.
|
||||||
|
}
|
||||||
|
|
||||||
|
var fxEmulations = ["Intel (F10 = ESC+[OM)", "Alternate (F10 = ESC+0)", "VT100+ (F10 = ESC+[OY)"];
|
||||||
|
function termToggleFx() {
|
||||||
|
if (!terminal || xxdialogMode) return;
|
||||||
|
terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3;
|
||||||
|
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
|
||||||
|
Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
|
||||||
|
}
|
||||||
|
|
||||||
|
function termToggleCr() {
|
||||||
|
if (!terminal || xxdialogMode) return;
|
||||||
|
if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
|
||||||
|
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
|
||||||
|
}
|
||||||
|
|
||||||
|
function termSendKey(key, id) {
|
||||||
|
if (!terminal || xxdialogMode) return;
|
||||||
|
if (xterm != null) {
|
||||||
|
if (terminal.sendText) {
|
||||||
|
// MeshAgent
|
||||||
|
terminal.sendText(String.fromCharCode(key));
|
||||||
|
} else {
|
||||||
|
// CIRA
|
||||||
|
terminal.send(String.fromCharCode(key));
|
||||||
|
}
|
||||||
|
xterm.focus();
|
||||||
|
} else if (terminal != null) {
|
||||||
|
terminal.m.TermSendKey(key);
|
||||||
|
Q(id).blur(); // Deselect the connect button so the button does not get key presses.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTermPasteDialog() {
|
||||||
|
if (!terminal || xxdialogMode) return;
|
||||||
|
Q('pastebutton').blur();
|
||||||
|
setDialogMode(2, "Paste", 3, showTermPasteDialogEx, '<textarea id=d2pasteText style="width:100%;height:184px;resize:none"></textarea>');
|
||||||
|
Q('d2pasteText').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTermPasteDialogEx() {
|
||||||
|
if (!terminal) return;
|
||||||
|
terminal.m.TermSendKeys(Q('d2pasteText').value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send special key
|
||||||
|
function sendSpecialKey() {
|
||||||
|
if (xterm != null) {
|
||||||
|
terminal.sendText(String.fromCharCode(Q('specialkeylist').value));
|
||||||
|
xterm.focus();
|
||||||
|
} else if (terminal != null) {
|
||||||
|
terminal.m.TermSendKey(Q('specialkeylist').value);
|
||||||
|
Q('specialkeylist').blur();
|
||||||
|
Q('specialkeylistinput').blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
|
||||||
|
|
||||||
|
//
|
||||||
|
// POPUP DIALOG
|
||||||
|
//
|
||||||
|
|
||||||
|
// null = Hidden, 1 = Generic Message
|
||||||
|
var xxdialogMode;
|
||||||
|
var xxdialogFunc;
|
||||||
|
var xxdialogButtons;
|
||||||
|
var xxdialogTag;
|
||||||
|
var xxcurrentView = -1;
|
||||||
|
|
||||||
|
// Display a dialog box
|
||||||
|
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
|
||||||
|
function setDialogMode(x, y, b, f, c, tag) {
|
||||||
|
xxdialogMode = x;
|
||||||
|
xxdialogFunc = f;
|
||||||
|
xxdialogButtons = b;
|
||||||
|
xxdialogTag = tag;
|
||||||
|
QE('idx_dlgOkButton', true);
|
||||||
|
QV('idx_dlgOkButton', b & 1);
|
||||||
|
QV('idx_dlgCancelButton', b & 2);
|
||||||
|
QV('id_dialogclose', (b & 2) || (b & 8));
|
||||||
|
QV('idx_dlgDeleteButton', b & 4);
|
||||||
|
QV('idx_dlgButtonBar', b & 7);
|
||||||
|
if (y) QH('id_dialogtitle', y);
|
||||||
|
for (var i = 1; i < 8; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||||||
|
QV('dialog', x);
|
||||||
|
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialogclose(x) {
|
||||||
|
var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
|
||||||
|
setDialogMode();
|
||||||
|
if (((b & 8) || x) && f) f(x, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||||||
|
function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||||||
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
|
||||||
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
function setSessionActivity() { sessionActivity = Date.now(); /*QH('idleTimeoutNotify', '');*/ }
|
||||||
|
function printDate(d) { return d.toLocaleDateString(urlargs.locale); }
|
||||||
|
function printTime(d) { return d.toLocaleTimeString(urlargs.locale); }
|
||||||
|
function printDateTime(d) { return d.toLocaleString(urlargs.locale); }
|
||||||
|
function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return format("Expires at {0}", printTime(d)); } else { return format("Expires {0}", printDateTime(d)); } }
|
||||||
|
|
||||||
|
start();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
43
webserver.js
43
webserver.js
@ -2971,7 +2971,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Check the inbound desktop sharing cookie
|
// Check the inbound desktop sharing cookie
|
||||||
var c = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey, 60); // 60 minute timeout
|
var c = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey, 60); // 60 minute timeout
|
||||||
if ((c == null) || (c.a !== 5) || (typeof c.uid != 'string') || (typeof c.nid != 'string') || (typeof c.gn != 'string') || (typeof c.cf != 'number') || (typeof c.start != 'number') || (typeof c.expire != 'number') || (typeof c.pid != 'string')) { res.sendStatus(404); return; }
|
if ((c == null) || (c.a !== 5) || ((c.p !== 2) && (c.p != null)) || (typeof c.uid != 'string') || (typeof c.nid != 'string') || (typeof c.gn != 'string') || (typeof c.cf != 'number') || (typeof c.start != 'number') || (typeof c.expire != 'number') || (typeof c.pid != 'string')) { res.sendStatus(404); return; }
|
||||||
|
|
||||||
// Check the expired time, expire message.
|
// Check the expired time, expire message.
|
||||||
if (c.expire <= Date.now()) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
if (c.expire <= Date.now()) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||||
@ -2991,7 +2991,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Looks good, let's create the outbound session cookies.
|
// Looks good, let's create the outbound session cookies.
|
||||||
// Consent flags are 1 = Notify, 8 = Prompt, 64 = Privacy Bar.
|
// Consent flags are 1 = Notify, 8 = Prompt, 64 = Privacy Bar.
|
||||||
const authCookie = obj.parent.encodeCookie({ userid: c.uid, domainid: domain.id, nid: c.nid, ip: req.clientIp, gn: c.gn, cf: 65 | c.cf, r: 8, expire: c.expire, pid: c.pid }, obj.parent.loginCookieEncryptionKey);
|
const authCookie = obj.parent.encodeCookie({ userid: c.uid, domainid: domain.id, nid: c.nid, ip: req.clientIp, p: 2, gn: c.gn, cf: 65 | c.cf, r: 8, expire: c.expire, pid: c.pid }, obj.parent.loginCookieEncryptionKey);
|
||||||
|
|
||||||
// Lets respond by sending out the desktop viewer.
|
// Lets respond by sending out the desktop viewer.
|
||||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||||
@ -3001,6 +3001,44 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serve the guest terminal page
|
||||||
|
function handleTerminalRequest(req, res) {
|
||||||
|
const domain = getDomain(req, res);
|
||||||
|
if (domain == null) { return; }
|
||||||
|
if (req.query.c == null) { res.sendStatus(404); return; }
|
||||||
|
|
||||||
|
// Check the inbound desktop sharing cookie
|
||||||
|
var c = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey, 60); // 60 minute timeout
|
||||||
|
if ((c == null) || (c.a !== 5) || (c.p !== 1) || (typeof c.uid != 'string') || (typeof c.nid != 'string') || (typeof c.gn != 'string') || (typeof c.cf != 'number') || (typeof c.start != 'number') || (typeof c.expire != 'number') || (typeof c.pid != 'string')) { res.sendStatus(404); return; }
|
||||||
|
|
||||||
|
// Check the expired time, expire message.
|
||||||
|
if (c.expire <= Date.now()) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 4, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||||
|
|
||||||
|
// Check the public id
|
||||||
|
obj.db.GetAllTypeNodeFiltered([c.nid], domain.id, 'deviceshare', null, function (err, docs) {
|
||||||
|
// Check if any desktop sharing links are present, expire message.
|
||||||
|
if ((err != null) || (docs.length == 0)) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 4, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||||
|
|
||||||
|
// Search for the device share public identifier, expire message.
|
||||||
|
var found = false;
|
||||||
|
for (var i = 0; i < docs.length; i++) { if (docs[i].publicid == c.pid) { found = true; } }
|
||||||
|
if (found == false) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 4, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||||
|
|
||||||
|
// Check the start time, not yet valid message.
|
||||||
|
if ((c.start > Date.now()) || (c.start > c.expire)) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 4, msgid: 11, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||||
|
|
||||||
|
// Looks good, let's create the outbound session cookies.
|
||||||
|
// Consent flags are 2 = Notify, 16 = Prompt
|
||||||
|
const authCookie = obj.parent.encodeCookie({ userid: c.uid, domainid: domain.id, nid: c.nid, ip: req.clientIp, p: 1, gn: c.gn, cf: 2 | c.cf, r: 8, expire: c.expire, pid: c.pid }, obj.parent.loginCookieEncryptionKey);
|
||||||
|
|
||||||
|
// Lets respond by sending out the desktop viewer.
|
||||||
|
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||||
|
parent.debug('web', 'handleTerminalRequest: Sending guest terminal page for \"' + c.uid + '\", guest \"' + c.gn + '\".');
|
||||||
|
res.set({ 'Cache-Control': 'no-store' });
|
||||||
|
render(req, res, getRenderPage('terminal', req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: '', domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), nodeid: c.nid, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, expire: c.expire }, req, domain));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Handle domain redirection
|
// Handle domain redirection
|
||||||
obj.handleDomainRedirect = function (req, res) {
|
obj.handleDomainRedirect = function (req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
@ -4975,6 +5013,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
obj.app.get(url + 'player.htm', handlePlayerRequest);
|
obj.app.get(url + 'player.htm', handlePlayerRequest);
|
||||||
obj.app.get(url + 'player', handlePlayerRequest);
|
obj.app.get(url + 'player', handlePlayerRequest);
|
||||||
obj.app.get(url + 'desktop', handleDesktopRequest);
|
obj.app.get(url + 'desktop', handleDesktopRequest);
|
||||||
|
obj.app.get(url + 'terminal', handleTerminalRequest);
|
||||||
obj.app.ws(url + 'amtactivate', handleAmtActivateWebSocket);
|
obj.app.ws(url + 'amtactivate', handleAmtActivateWebSocket);
|
||||||
obj.app.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler
|
obj.app.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler
|
||||||
obj.app.ws(url + 'meshrelay.ashx', function (ws, req) {
|
obj.app.ws(url + 'meshrelay.ashx', function (ws, req) {
|
||||||
|
Loading…
Reference in New Issue
Block a user