diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj
index 458e9bff..50b23648 100644
--- a/MeshCentralServer.njsproj
+++ b/MeshCentralServer.njsproj
@@ -260,6 +260,7 @@
+
diff --git a/agents/MeshService-signed.exe b/agents/MeshService-signed.exe
index 2589ba3d..9323abaa 100644
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
diff --git a/agents/MeshService.exe b/agents/MeshService.exe
index 15e20346..b0f08bf8 100644
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
diff --git a/agents/MeshService64-signed.exe b/agents/MeshService64-signed.exe
index 263a6417..6070eaa2 100644
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe
index dae399b1..38cf75b2 100644
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
diff --git a/meshcentral.js b/meshcentral.js
index 2699dcbb..6122a7ec 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -1549,8 +1549,14 @@ function CreateMeshCentralServer(config, args) {
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug(1, 'ERR: Bad cookie due to invalid time'); return null; }
o.time = o.time * 1000; // Decode the cookie creation time
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
- if (timeout == null) { timeout = 2; }
- if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ if ((o.expire) == null || (typeof o.expire != 'number')) {
+ // Use a fixed cookie expire time
+ if (timeout == null) { timeout = 2; }
+ if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ } else {
+ // An expire time is included in the cookie (in minutes), use this.
+ if ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ }
return o;
} catch (ex) { obj.debug(1, 'ERR: Bad AESGCM cookie due to exception: ' + ex); return null; }
};
@@ -1571,8 +1577,14 @@ function CreateMeshCentralServer(config, args) {
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug(1, 'ERR: Bad cookie due to invalid time'); return null; }
o.time = o.time * 1000; // Decode the cookie creation time
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
- if (timeout == null) { timeout = 2; }
- if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ if ((o.expire) == null || (typeof o.expire != 'number')) {
+ // Use a fixed cookie expire time
+ if (timeout == null) { timeout = 2; }
+ if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ } else {
+ // An expire time is included in the cookie (in minutes), use this.
+ if ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
+ }
return o;
} catch (ex) { obj.debug(1, 'ERR: Bad AESSHA cookie due to exception: ' + ex); return null; }
};
diff --git a/meshuser.js b/meshuser.js
index 9b80a399..75cefc72 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -2499,6 +2499,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
break;
}
+ case 'createInviteLink': {
+ if (common.validateString(command.meshid, 8, 128) == false) break; // Check the meshid
+ if (common.validateInt(command.expire, 1, 99999) == false) break; // Check the expire time in hours
+ if (common.validateInt(command.flags, 0, 256) == false) break; // Check the flags
+ var mesh = parent.meshes[command.meshid];
+ if (mesh == null) break;
+ const inviteCookie = parent.parent.encodeCookie({ a: 4, mid: command.meshid, f: command.flags, expire: command.expire * 60 }, parent.parent.loginCookieEncryptionKey);
+ if (inviteCookie == null) break;
+ ws.send(JSON.stringify({ action: 'createInviteLink', meshid: command.meshid, expire: command.expire, cookie: inviteCookie }));
+ break;
+ }
default: {
// Unknown user action
console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');
diff --git a/package.json b/package.json
index 40b5c408..19eb02a0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "meshcentral",
- "version": "0.3.5-v",
+ "version": "0.3.5-x",
"keywords": [
"Remote Management",
"Intel AMT",
diff --git a/public/images/macosagent.png b/public/images/macosagent.png
new file mode 100644
index 00000000..bd5cc5b2
Binary files /dev/null and b/public/images/macosagent.png differ
diff --git a/public/images/winagent.png b/public/images/winagent.png
new file mode 100644
index 00000000..a5bcbad0
Binary files /dev/null and b/public/images/winagent.png differ
diff --git a/views/agentinvite.handlebars b/views/agentinvite.handlebars
new file mode 100644
index 00000000..307361b6
--- /dev/null
+++ b/views/agentinvite.handlebars
@@ -0,0 +1,293 @@
+
+
+
+ You have been invited to install a software that will allow a remote operator to fully access your computer remotely including the desktop and files.
+ Only follow the instructions below if this invitation was expected and you know who will be accessing your computer.
+ Selecting your operation system and follow the instructions below.
+
+
+
+
diff --git a/views/default.handlebars b/views/default.handlebars
index 7c3268e3..622a7fea 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -1977,6 +1977,28 @@
}
break;
}
+ case 'createInviteLink': { // Agent installation invitation link
+ if (xxdialogTag != message.meshid) break;
+ var servername = serverinfo.name;
+ if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
+ var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
+ var url;
+ if (serverinfo.https == true) {
+ var portStr = (serverinfo.port == 443) ? '' : (":" + serverinfo.port);
+ url = "https://" + servername + portStr + domainUrl + "agentinvite?c=" + message.cookie;
+ } else {
+ var portStr = (serverinfo.port == 80) ? '' : (":" + serverinfo.port);
+ url = "http://" + servername + portStr + domainUrl + "agentinvite?c=" + message.cookie;
+ }
+ Q('agentInvitationLink').href = url;
+ var t = message.expire + ' hour' + addLetterS(message.expire);
+ if (message.expire == 24) { t = '1 day'; }
+ if (message.expire == 168) { t = '1 week'; }
+ if (message.expire == 5040) { t = '1 month'; }
+ QH('agentInvitationLink', 'Invitation Link (' + t + ')');
+ QV('agentInvitationLinkDiv', true);
+ break;
+ }
case 'stopped': { // Server is stopping.
// Disconnect
autoReconnect = false;
@@ -2547,9 +2569,7 @@
}
if (mesh.mtype == 2) {
r += ' Add Agent';
- if (features & 64) {
- r += ' Invite';
- }
+ r += ' Invite';
}
return r;
}
@@ -2673,23 +2693,51 @@
function inviteAgentToMesh(meshid) {
if (xxdialogMode) return;
- var mesh = meshes[meshid];
- var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".
";
- x += addHtmlValue('Name (optional)', '');
- x += addHtmlValue('Email', '');
- x += addHtmlValue('Operating System', '');
- x += addHtmlValue('Installation Type', '');
- x += addHtmlValue('Message (optional)', '');
+ var x = '', mesh = meshes[meshid];
+ if (features & 64) {
+ x += addHtmlValue('Invitation Type', '') + "";
+ x += "
Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for the \"" + EscapeHtml(mesh.name) + "\" device group.
";
+ x += addHtmlValue('Name (optional)', '');
+ x += addHtmlValue('Email', '');
+ x += addHtmlValue('Operating System', '');
+ x += addHtmlValue('Installation Type', '');
+ x += addHtmlValue('Message (optional)', '');
+ x += '
';
+ }
+ x += '
Invite someone to install the mesh agent by sharing a invitation link. This link points the user to installation instructions for the \"' + EscapeHtml(mesh.name) + '\" device group. The link is public and no account this server is needed.
';
+ x += addHtmlValue('Link Expiration', '');
+ x += '