mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-24 22:25:52 -05:00
Guest desktop sharing with time range.
This commit is contained in:
parent
0acde2323d
commit
b53200afda
@ -226,7 +226,6 @@
|
||||
"geoLocation": { "type": "boolean", "default": false, "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." },
|
||||
"novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based noVNC client." },
|
||||
"mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." },
|
||||
"maxGuestSessionSharingTime": { "type": "integer", "default": 60, "minimum": 1, "maximum": 5760, "description": "Maximum amount of time in minutes that a remote desktop session can be shared with a guest." },
|
||||
"webEmailsPath": { "type": "string", "description": "Path where to find custom email templates for this domain." },
|
||||
"customUI": { "type": "object" },
|
||||
"consentMessages": {
|
||||
|
22
meshuser.js
22
meshuser.js
@ -446,7 +446,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
|
||||
// Build server information object
|
||||
var serverinfo = { domain: domain.id, name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1) && (user._id.split('/')[2].startsWith('~') == false)), domainauth: (domain.auth == 'sspi'), serverTime: Date.now() };
|
||||
serverinfo.maxGuestSessionSharingTime = (typeof domain.maxguestsessionsharingtime == 'number') ? domain.maxguestsessionsharingtime : 60;
|
||||
serverinfo.languages = parent.renderLanguages;
|
||||
serverinfo.tlshash = Buffer.from(parent.webCertificateHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
|
||||
if ((domain.sessionrecording) && (domain.sessionrecording.onlyselecteddevicegroups === true)) { serverinfo.devGroupSessionRecording = 1; } // Allow enabling of session recording
|
||||
@ -4676,11 +4675,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
break;
|
||||
}
|
||||
case 'createDeviceShareLink': {
|
||||
var err = null, maxExpireMinutes = (typeof domain.maxguestsessionsharingtime == 'number') ? domain.maxguestsessionsharingtime : 60;
|
||||
var err = null;
|
||||
if (common.validateString(command.nodeid, 8, 128) == false) { err = 'Invalid node id'; } // Check the nodeid
|
||||
else if (common.validateString(command.guestname, 1, 128) == false) { err = 'Invalid guest name'; } // Check the guest name
|
||||
else if (common.validateInt(command.expire, 1, maxExpireMinutes) == false) { err = 'Invalid expire time'; } // Check the expire time in hours
|
||||
else if ((command.expire != null) && (typeof command.expire != 'number')) { err = 'Invalid expire time'; } // Check the expire time in hours
|
||||
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 (common.validateInt(command.consent, 0, 256) == false) { err = 'Invalid flags'; } // Check the flags
|
||||
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.nodeid.split('/').length == 1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
|
||||
var snode = command.nodeid.split('/');
|
||||
@ -4702,10 +4704,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if ((rights != 0xFFFFFFFF) && ((rights & 4352) != 0)) return;
|
||||
|
||||
// Create cookie
|
||||
var publicid = getRandomPassword();
|
||||
var startTime = Date.now(), expireTime = Date.now() + (60000 * command.expire);
|
||||
var publicid = getRandomPassword(), startTime, expireTime;
|
||||
if (command.expire != null) {
|
||||
// Now until expire in hours
|
||||
startTime = Date.now();
|
||||
expireTime = Date.now() + (60000 * command.expire);
|
||||
} else {
|
||||
// Time range in seconds
|
||||
startTime = command.start * 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);
|
||||
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.expire = expireTime;
|
||||
|
||||
// Create the server url
|
||||
|
2
public/scripts/flatpickr.js
Normal file
2
public/scripts/flatpickr.js
Normal file
File diff suppressed because one or more lines are too long
13
public/styles/flatpickr.min.css
vendored
Normal file
13
public/styles/flatpickr.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -166,7 +166,6 @@
|
||||
"_geoLocation": true,
|
||||
"_novnc": false,
|
||||
"_mstsc": true,
|
||||
"_maxGuestSessionSharingTime": 5760,
|
||||
"_WebEmailsPath": "/myserver/email-templates",
|
||||
"_consentMessages": {
|
||||
"title": "MeshCentral",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
<link type="text/css" href="styles/ol.css" media="screen" rel="stylesheet" title="CSS" />
|
||||
<link type="text/css" href="styles/ol3-contextmenu.min.css" media="screen" rel="stylesheet" title="CSS" />
|
||||
<link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
|
||||
<link type="text/css" href="styles/flatpickr.min.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/meshcentral{{{min}}}.js"></script>
|
||||
@ -31,6 +32,7 @@
|
||||
<script type="text/javascript" src="scripts/qrcode.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 type="text/javascript" src="scripts/flatpickr.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/u2f-api{{{min}}}.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/charts{{{min}}}.js"></script>
|
||||
<script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
|
||||
@ -3071,6 +3073,7 @@
|
||||
if (node == null) break;
|
||||
x += addHtmlValue("Device", node.name);
|
||||
x += addHtmlValue("Guest Name", message.guestname);
|
||||
x += addHtmlValue("Start Time", printDateTime(new Date(message.start)));
|
||||
x += addHtmlValue("Expire Time", printDateTime(new Date(message.expire)));
|
||||
var y = [];
|
||||
if (message.consent & 1) { y.push("Notify"); }
|
||||
@ -6157,6 +6160,7 @@
|
||||
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: decodeURIComponent('{{{extitle}}}'), msg: Q('d2devToast').value });
|
||||
}
|
||||
|
||||
/*
|
||||
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 up to 1 hour." + '<br /><br />';
|
||||
@ -6168,9 +6172,45 @@
|
||||
setDialogMode(2, "Share Device", 3, showShareDeviceEx, x);
|
||||
showShareDeviceValidate();
|
||||
}
|
||||
*/
|
||||
|
||||
function showShareDeviceValidate() { QE('idx_dlgOkButton', Q('d2inviteName').value.trim().length > 0); }
|
||||
function showShareDeviceEx() { meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), expire: parseInt(Q('d2inviteExpire').value), consent: parseInt(Q('d2userConsent').value) }); }
|
||||
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() />');
|
||||
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>'; }
|
||||
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 += '<div id=d2modenow>';
|
||||
x += addHtmlValue("Expire Time", '<select id=d2inviteExpire style=float:right;width:250px>' + y + '</select>');
|
||||
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 += '</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>');
|
||||
setDialogMode(2, "Share Device", 3, showShareDeviceEx, x);
|
||||
showShareDeviceValidate();
|
||||
var tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
var rangeTime = flatpickr('#d2timeRangeSelector', { mode: 'range', enableTime: true, minDate: new Date(), defaultDate: [ new Date(), tomorrow ] });
|
||||
xxdialogTag = rangeTime;
|
||||
}
|
||||
|
||||
function showShareDeviceValidate() {
|
||||
QV('d2modenow', Q('d2timeRange').value == 0);
|
||||
QV('d2moderange', Q('d2timeRange').value == 1);
|
||||
var ok = true;
|
||||
|
||||
if (Q('d2inviteName').value.trim().length == 0) { ok = false; }
|
||||
|
||||
QE('idx_dlgOkButton', ok);
|
||||
}
|
||||
function showShareDeviceEx(b, tag) {
|
||||
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) });
|
||||
} 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) });
|
||||
}
|
||||
}
|
||||
|
||||
function deviceActionFunction() {
|
||||
if (xxdialogMode) return;
|
||||
|
@ -172,7 +172,7 @@
|
||||
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
|
||||
var webPageFullScreen = false;
|
||||
var expire = '{{{expire}}}';
|
||||
if (expire != '') { QH('p11power', format("Expires at {0}", printTime(new Date(parseInt(expire))))) }
|
||||
if (expire != '') { QH('p11power', printFlexDateTime(new Date(parseInt(expire)))); }
|
||||
|
||||
function start() {
|
||||
window.onresize = deskAdjust;
|
||||
@ -1161,6 +1161,7 @@
|
||||
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>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<div id=page_content style=max-height:calc(100vh-138px)>
|
||||
<div id=column_l>
|
||||
<h1 id="mainTitle"></h1>
|
||||
<p style=margin-left:20px id="mainMessage"></p>
|
||||
<p id="mainMessage"></p>
|
||||
<br />
|
||||
</div>
|
||||
<div id=footer>
|
||||
@ -52,6 +52,7 @@
|
||||
|
||||
var title = '';
|
||||
if (titleid == 1) { title = "Account Verification"; }
|
||||
if (titleid == 2) { title = "Desktop Sharing"; }
|
||||
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
||||
QH('mainTitle', title);
|
||||
|
||||
@ -71,8 +72,13 @@
|
||||
}
|
||||
case 9: { msg = "ERROR: Invalid account check."; break; }
|
||||
case 10: { msg = "ERROR: Invalid account check, verification url is only valid for 30 minutes."; break; }
|
||||
case 11: { msg = "Sharing link not valid yet."; break; }
|
||||
case 12: { msg = "Sharing link is expired."; break; }
|
||||
}
|
||||
QH('mainMessage', msg + ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.');
|
||||
|
||||
// Add login page link
|
||||
if ((msgid != 11) && (msgid != 12)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
||||
QH('mainMessage', msg);
|
||||
|
||||
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; }); };
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<td style="width:100%;text-align:center;color:#c8c8c8;font-size:larger">
|
||||
<h1 id="mainTitle"></h1>
|
||||
<p style=margin-left:20px id="mainMessage"></p>
|
||||
<p id="mainMessage"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="height:20px">
|
||||
@ -53,6 +53,7 @@
|
||||
|
||||
var title = '';
|
||||
if (titleid == 1) { title = "Account Verification"; }
|
||||
if (titleid == 2) { title = "Desktop Sharing"; }
|
||||
QH('topTitle', Q('topTitle').innerText + ' - ' + title);
|
||||
QH('mainTitle', title);
|
||||
|
||||
@ -72,8 +73,13 @@
|
||||
}
|
||||
case 9: { msg = "ERROR: Invalid account check."; break; }
|
||||
case 10: { msg = "ERROR: Invalid account check, verification url is only valid for 30 minutes."; break; }
|
||||
case 11: { msg = "Sharing link not valid yet."; break; }
|
||||
case 12: { msg = "Sharing link is expired."; break; }
|
||||
}
|
||||
QH('mainMessage', msg + '<br /><br /><a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.');
|
||||
|
||||
// Add login page link
|
||||
if ((msgid != 11) && (msgid != 12)) { msg += ' <a href="' + domainurl + (urlargs.key ? ('?key=' + urlargs.key) : '') + '">' + "Go to login page" + '</a>.' }
|
||||
QH('mainMessage', msg);
|
||||
|
||||
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; }); };
|
||||
|
||||
|
16
webserver.js
16
webserver.js
@ -2922,19 +2922,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// 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) || (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') || (c.expire <= Date.now())) { res.sendStatus(404); return; }
|
||||
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; }
|
||||
|
||||
// Check the start time
|
||||
if ((c.start > Date.now()) || (c.start > c.expire)) { 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: 2, 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) {
|
||||
if ((err != null) || (docs.length == 0)) { res.sendStatus(404); return; }
|
||||
// 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: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||
|
||||
// Search for the device share public identifier
|
||||
// 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) { res.sendStatus(404); return; }
|
||||
if (found == false) { 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; }
|
||||
|
||||
// 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: 2, msgid: 11, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; }
|
||||
|
||||
// Looks good, let's create the outbound session cookies.
|
||||
// Consent flags are 1 = Notify, 8 = Prompt, 64 = Privacy Bar.
|
||||
|
Loading…
Reference in New Issue
Block a user