mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-11-07 12:52:54 -05:00
Many server improvements & stability fixes.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
120
meshagent.js
120
meshagent.js
@@ -258,7 +258,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
obj.send(obj.common.ShortToStr(1) + msg.substring(2, 50) + obj.nonce); // Command 1, hash + nonce. Use the web hash given by the agent.
|
obj.send(obj.common.ShortToStr(1) + msg.substring(2, 50) + obj.nonce); // Command 1, hash + nonce. Use the web hash given by the agent.
|
||||||
} else {
|
} else {
|
||||||
// Check that the server hash matches our own web certificate hash (SHA384)
|
// Check that the server hash matches our own web certificate hash (SHA384)
|
||||||
if ((getWebCertHash(obj.domain) != msg.substring(2, 50)) && (getWebCertFullHash(obj.domain) != msg.substring(2, 50))) { console.log('Agent bad web cert hash (Agent:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (Buffer.from(getWebCertHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (new Buffer(getWebCertFullHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').'); return; }
|
if ((getWebCertHash(obj.domain) != msg.substring(2, 50)) && (getWebCertFullHash(obj.domain) != msg.substring(2, 50))) {
|
||||||
|
console.log('Agent bad web cert hash (Agent:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (Buffer.from(getWebCertHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (new Buffer(getWebCertFullHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').');
|
||||||
|
console.log('Agent reported web cert hash:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex')) + '.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
|
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
|
||||||
@@ -365,6 +369,31 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
obj.send(obj.common.ShortToStr(1) + getWebCertHash(obj.domain) + obj.nonce); // Command 1, hash + nonce
|
obj.send(obj.common.ShortToStr(1) + getWebCertHash(obj.domain) + obj.nonce); // Command 1, hash + nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the mesh for this device, in some cases, we may auto-create the mesh.
|
||||||
|
function getMeshAutoCreate() {
|
||||||
|
var mesh = obj.parent.meshes[obj.dbMeshKey];
|
||||||
|
if ((mesh == null) && (typeof obj.domain.orphanagentuser == 'string')) {
|
||||||
|
var adminUser = obj.parent.users['user/' + domain.id + '/' + obj.domain.orphanagentuser.toLowerCase()];
|
||||||
|
if ((adminUser != null) && (adminUser.siteadmin == 0xFFFFFFFF)) {
|
||||||
|
// Mesh name is hex instead of base64
|
||||||
|
var meshname = Buffer.from(obj.meshid, 'base64').toString('hex').substring(0, 18);
|
||||||
|
|
||||||
|
// Create a new mesh for this device
|
||||||
|
var links = {};
|
||||||
|
links[adminUser._id] = { name: adminUser.name, rights: 0xFFFFFFFF };
|
||||||
|
mesh = { type: 'mesh', _id: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', domain: domain.id, links: links };
|
||||||
|
obj.db.Set(obj.common.escapeLinksFieldName(mesh));
|
||||||
|
obj.parent.meshes[obj.dbMeshKey] = mesh;
|
||||||
|
|
||||||
|
if (adminUser.links == null) user.links = {};
|
||||||
|
adminUser.links[obj.dbMeshKey] = { rights: 0xFFFFFFFF };
|
||||||
|
obj.db.SetUser(adminUser);
|
||||||
|
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey, adminUser._id], obj, { etype: 'mesh', username: adminUser.name, meshid: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
// Once we get all the information about an agent, run this to hook everything up to the server
|
// Once we get all the information about an agent, run this to hook everything up to the server
|
||||||
function completeAgentConnection() {
|
function completeAgentConnection() {
|
||||||
if ((obj.authenticated != 1) || (obj.meshid == null) || obj.pendingCompleteAgentConnection) return;
|
if ((obj.authenticated != 1) || (obj.meshid == null) || obj.pendingCompleteAgentConnection) return;
|
||||||
@@ -380,21 +409,69 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
if (domainAgentSessionCount >= domain.limits.maxagentsessions) { return; } // Too many, hold the connection.
|
if (domainAgentSessionCount >= domain.limits.maxagentsessions) { return; } // Too many, hold the connection.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Check that the mesh exists
|
// Check that the mesh exists
|
||||||
var mesh = obj.parent.meshes[obj.dbMeshKey];
|
var mesh = obj.parent.meshes[obj.dbMeshKey];
|
||||||
if (mesh == null) { console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
if (mesh == null) {
|
||||||
|
var holdConnection = true;
|
||||||
|
if (typeof obj.domain.orphanagentuser == 'string') {
|
||||||
|
var adminUser = obj.parent.users['user/' + domain.id + '/' + obj.args.orphanagentuser];
|
||||||
|
if ((adminUser != null) && (adminUser.siteadmin == 0xFFFFFFFF)) {
|
||||||
|
// Create a new mesh for this device
|
||||||
|
holdConnection = false;
|
||||||
|
var links = {};
|
||||||
|
links[user._id] = { name: adminUser.name, rights: 0xFFFFFFFF };
|
||||||
|
mesh = { type: 'mesh', _id: obj.dbMeshKey, name: obj.meshid, mtype: 2, desc: '', domain: domain.id, links: links };
|
||||||
|
obj.db.Set(obj.common.escapeLinksFieldName(mesh));
|
||||||
|
obj.parent.meshes[obj.meshid] = mesh;
|
||||||
|
obj.parent.parent.AddEventDispatch([obj.meshid], ws);
|
||||||
|
|
||||||
|
if (adminUser.links == null) user.links = {};
|
||||||
|
adminUser.links[obj.meshid] = { rights: 0xFFFFFFFF };
|
||||||
|
//adminUser.subscriptions = obj.parent.subscribe(adminUser._id, ws);
|
||||||
|
obj.db.SetUser(user);
|
||||||
|
obj.parent.parent.DispatchEvent(['*', meshid, user._id], obj, { etype: 'mesh', username: user.name, meshid: obj.meshid, name: obj.meshid, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holdConnection == true) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
*/
|
||||||
|
|
||||||
// Check that the node exists
|
// Check that the node exists
|
||||||
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
|
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
|
||||||
var device;
|
var device;
|
||||||
|
|
||||||
// Mark when we connected to this agent
|
|
||||||
obj.connectTime = Date.now();
|
|
||||||
obj.db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
|
|
||||||
|
|
||||||
// See if this node exists in the database
|
// See if this node exists in the database
|
||||||
if (nodes.length == 0) {
|
if (nodes.length == 0) {
|
||||||
|
// This device does not exist, use the meshid given by the device
|
||||||
|
|
||||||
|
// See if this mesh exists, if it does not we may want to create it.
|
||||||
|
var mesh = getMeshAutoCreate();
|
||||||
|
|
||||||
|
// Check if the mesh exists
|
||||||
|
if (mesh == null) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mesh is the right type
|
||||||
|
if (mesh.mtype != 2) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark when this device connected
|
||||||
|
obj.connectTime = Date.now();
|
||||||
|
obj.db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
|
||||||
|
|
||||||
// This node does not exist, create it.
|
// This node does not exist, create it.
|
||||||
device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null };
|
device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null };
|
||||||
obj.db.Set(device);
|
obj.db.Set(device);
|
||||||
@@ -407,15 +484,42 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
|
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Device already exists, look if changes has occured
|
|
||||||
device = nodes[0];
|
device = nodes[0];
|
||||||
|
|
||||||
|
// This device exists, meshid given by the device must be ignored, use the server side one.
|
||||||
|
if (device.meshid != obj.dbMeshKey) {
|
||||||
|
obj.dbMeshKey = device.meshid;
|
||||||
|
obj.meshid = device.meshid.split('/')[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if this mesh exists, if it does not we may want to create it.
|
||||||
|
var mesh = getMeshAutoCreate();
|
||||||
|
|
||||||
|
// Check if the mesh exists
|
||||||
|
if (mesh == null) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mesh is the right type
|
||||||
|
if (mesh.mtype != 2) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark when this device connected
|
||||||
|
obj.connectTime = Date.now();
|
||||||
|
obj.db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
|
||||||
|
|
||||||
|
// Device already exists, look if changes has occured
|
||||||
var changes = [], change = 0, log = 0;
|
var changes = [], change = 0, log = 0;
|
||||||
if (device.agent == null) { device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; }
|
if (device.agent == null) { device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; }
|
||||||
if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); }
|
if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); }
|
||||||
if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); }
|
if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); }
|
||||||
if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); }
|
if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); }
|
||||||
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities
|
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities
|
||||||
if (device.meshid != obj.dbMeshKey) { obj.dbMeshKey = device.meshid; obj.meshid = device.meshid.split('/')[2]; } // If the mesh does not match, the server mesh is the correct one. This is because we allow the server to change the mesh of a device server-side.
|
|
||||||
if (change == 1) {
|
if (change == 1) {
|
||||||
obj.db.Set(device);
|
obj.db.Set(device);
|
||||||
|
|
||||||
|
|||||||
33
meshuser.js
33
meshuser.js
@@ -642,6 +642,22 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
|
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
|
||||||
obj.parent.parent.DispatchEvent([deluserid], obj, 'close');
|
obj.parent.parent.DispatchEvent([deluserid], obj, 'close');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'userbroadcast':
|
||||||
|
{
|
||||||
|
// Broadcast a message to all currently connected users.
|
||||||
|
if ((user.siteadmin & 2) == 0) break;
|
||||||
|
if (obj.common.validateUsername(command.msg, 1, 256) == false) break; // Notification message is between 1 and 256 characters
|
||||||
|
|
||||||
|
// Create the notification message
|
||||||
|
var notification = { "action": "msg", "type": "notify", "value": command.msg };
|
||||||
|
|
||||||
|
// Send the notification on all user sessions for this server
|
||||||
|
for (var i in obj.parent.wssessions2) { try { obj.parent.wssessions2[i].send(JSON.stringify(notification)); } catch (ex) { } }
|
||||||
|
|
||||||
|
// TODO: Notify all sessions on other peers.
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'adduser':
|
case 'adduser':
|
||||||
@@ -879,7 +895,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
|
|
||||||
// We only create Agent-less Intel AMT mesh (Type1), or Agent mesh (Type2)
|
// We only create Agent-less Intel AMT mesh (Type1), or Agent mesh (Type2)
|
||||||
if ((command.meshtype == 1) || (command.meshtype == 2)) {
|
if ((command.meshtype == 1) || (command.meshtype == 2)) {
|
||||||
// Create a type 1 agent-less Intel AMT mesh.
|
|
||||||
obj.parent.crypto.randomBytes(48, function (err, buf) {
|
obj.parent.crypto.randomBytes(48, function (err, buf) {
|
||||||
meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||||
var links = {};
|
var links = {};
|
||||||
@@ -1674,17 +1689,25 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
|
|
||||||
// Check is 2-step login is supported
|
// Check is 2-step login is supported
|
||||||
const twoStepLoginSupported = ((domain.auth != 'sspi') && (obj.parent.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly !== true) && (obj.args.nousers !== true));
|
const twoStepLoginSupported = ((domain.auth != 'sspi') && (obj.parent.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly !== true) && (obj.args.nousers !== true));
|
||||||
if ((twoStepLoginSupported == false) || (typeof command.otp != 'string')) break;
|
if ((twoStepLoginSupported == false) || (typeof command.otp != 'string')) {
|
||||||
|
ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if Yubikey support is present
|
// Check if Yubikey support is present or OTP no exactly 44 in length
|
||||||
if ((typeof domain.yubikey != 'object') || (typeof domain.yubikey.id != 'string') || (typeof domain.yubikey.secret != 'string')) break;
|
if ((typeof domain.yubikey != 'object') || (typeof domain.yubikey.id != 'string') || (typeof domain.yubikey.secret != 'string') || (command.otp.length != 44)) {
|
||||||
|
ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if command.otp is modhex encoded, reject if not.
|
||||||
|
|
||||||
// Query the YubiKey server to validate the OTP
|
// Query the YubiKey server to validate the OTP
|
||||||
var yubikeyotp = require('yubikeyotp');
|
var yubikeyotp = require('yubikeyotp');
|
||||||
var request = { otp: command.otp, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true }
|
var request = { otp: command.otp, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true }
|
||||||
if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; }
|
if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; }
|
||||||
yubikeyotp.verifyOTP(request, function (err, results) {
|
yubikeyotp.verifyOTP(request, function (err, results) {
|
||||||
if (results.status == 'OK') {
|
if ((results != null) && (results.status == 'OK')) {
|
||||||
var keyIndex = obj.parent.crypto.randomBytes(4).readUInt32BE(0);
|
var keyIndex = obj.parent.crypto.randomBytes(4).readUInt32BE(0);
|
||||||
var keyId = command.otp.substring(0, 12);
|
var keyId = command.otp.substring(0, 12);
|
||||||
if (user.otphkeys == null) { user.otphkeys = []; }
|
if (user.otphkeys == null) { user.otphkeys = []; }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.2.8-d",
|
"version": "0.2.8-g",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -299,9 +299,14 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class=h1></td>
|
<td class=h1></td>
|
||||||
<td class=style14>
|
<td class=style14>
|
||||||
|
<div style="float:right">
|
||||||
<input type=button onclick=showCreateNewAccountDialog() value="New Account..." />
|
<input type=button onclick=showUserBroadcastDialog() value="Broadcast" />
|
||||||
<input id=UserSearchInput type=text style=width:120px placeholder=Filter onchange=onUserSearchInputChanged() onkeyup=onUserSearchInputChanged() autocomplete=off onfocus=onUserSearchFocus(1) onblur=onUserSearchFocus(0) />
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<input type=button onclick=showCreateNewAccountDialog() value="New Account..." />
|
||||||
|
<input id=UserSearchInput type=text style=width:120px placeholder=Filter onchange=onUserSearchInputChanged() onkeyup=onUserSearchInputChanged() autocomplete=off onfocus=onUserSearchFocus(1) onblur=onUserSearchFocus(0) />
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class=h2></td>
|
<td class=h2></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -6349,6 +6354,17 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showUserBroadcastDialog() {
|
||||||
|
if (xxdialogMode) return;
|
||||||
|
var x = 'Broadcast a message to all connected users.<textarea id=broadcastMessage value="" style=width:370px;height:100px;resize:none maxlength=256 /></textarea>';
|
||||||
|
setDialogMode(2, "Broadcast Message", 3, showUserBroadcastDialogEx, x);
|
||||||
|
Q('broadcastMessage').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUserBroadcastDialogEx() {
|
||||||
|
meshserver.send({ action: 'userbroadcast', msg: Q('broadcastMessage').value });
|
||||||
|
}
|
||||||
|
|
||||||
function showCreateNewAccountDialog() {
|
function showCreateNewAccountDialog() {
|
||||||
if (xxdialogMode) return;
|
if (xxdialogMode) return;
|
||||||
var x = '';
|
var x = '';
|
||||||
|
|||||||
23
webserver.js
23
webserver.js
@@ -1076,10 +1076,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if it looks like we are using a real TLS certificate.
|
||||||
|
function isTrustedCert() {
|
||||||
|
if (obj.args.notls == true) return false; // We are not using TLS, so not trusted cert.
|
||||||
|
if (obj.args.tlsoffload != null) return true; // We are using TLS offload, a real cert is likely used.
|
||||||
|
if (obj.parent.config.letsencrypt != null) return true; // We are using Let's Encrypt, real cert in use.
|
||||||
|
if (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) return false; // Our cert is issued by self-signed cert.
|
||||||
|
if (obj.certificates.CommonName == 'un-configured') return false; // Out cert is named with a fake name
|
||||||
|
return true; // This is a guess
|
||||||
|
}
|
||||||
|
|
||||||
// Get the link to the root certificate if needed
|
// Get the link to the root certificate if needed
|
||||||
function getRootCertLink() {
|
function getRootCertLink() {
|
||||||
// Check if the HTTPS certificate is issued from MeshCentralRoot, if so, add download link to root certificate.
|
// Check if the HTTPS certificate is issued from MeshCentralRoot, if so, add download link to root certificate.
|
||||||
if ((obj.args.notls == null) && (obj.tlsSniCredentials == null) && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) && (obj.certificates.CommonName != 'un-configured')) { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
|
if ((obj.args.notls == null) && (obj.args.tlsoffload == null) && (obj.parent.config.letsencrypt == null) && (obj.tlsSniCredentials == null) && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) && (obj.certificates.CommonName != 'un-configured')) { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2193,18 +2203,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Two more headers to take a look at:
|
// Two more headers to take a look at:
|
||||||
// 'Public-Key-Pins': 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; max-age=10'
|
// 'Public-Key-Pins': 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; max-age=10'
|
||||||
// 'strict-transport-security': 'max-age=31536000; includeSubDomains'
|
// 'strict-transport-security': 'max-age=31536000; includeSubDomains'
|
||||||
/*
|
|
||||||
var headers = null;
|
var headers = null;
|
||||||
if (obj.args.notls) {
|
if (isTrustedCert() == false) {
|
||||||
// Default headers if no TLS is used
|
// Default headers if no TLS is used
|
||||||
headers = { 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src http: ws: data: 'self';script-src http: 'unsafe-inline';style-src http: 'unsafe-inline'" };
|
//headers = { 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src http: ws: data: 'self';script-src http: 'unsafe-inline';style-src http: 'unsafe-inline'" };
|
||||||
} else {
|
} else {
|
||||||
// Default headers if TLS is used
|
// Default headers if TLS is used
|
||||||
headers = { 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src https: wss: data: 'self';script-src https: 'unsafe-inline';style-src https: 'unsafe-inline'" };
|
//headers = { 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src https: wss: data: 'self';script-src https: 'unsafe-inline';style-src https: 'unsafe-inline'" };
|
||||||
|
|
||||||
|
// Set Strict-Transport-Security if we are using a trusted certificate or TLS offload.
|
||||||
|
headers = { 'Strict-Transport-Security': 'max-age=31536000;includeSubDomains' };
|
||||||
}
|
}
|
||||||
if (parent.config.settings.accesscontrolalloworigin != null) { headers['Access-Control-Allow-Origin'] = parent.config.settings.accesscontrolalloworigin; }
|
if (parent.config.settings.accesscontrolalloworigin != null) { headers['Access-Control-Allow-Origin'] = parent.config.settings.accesscontrolalloworigin; }
|
||||||
res.set(headers);
|
res.set(headers);
|
||||||
*/
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user