mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-24 06:05:53 -05:00
Merge branch 'master' into plugin-admin
This commit is contained in:
commit
b33ca1daff
@ -1815,6 +1815,19 @@ function createMeshCore(agent) {
|
||||
break;
|
||||
case 'STATUS':
|
||||
var nextboot = require('win-bcd').getKey('safeboot');
|
||||
if (nextboot)
|
||||
{
|
||||
switch(nextboot)
|
||||
{
|
||||
case 'Network':
|
||||
case 'network':
|
||||
nextboot = 'SAFE_MODE_NETWORK';
|
||||
break;
|
||||
default:
|
||||
nextboot = 'SAFE_MODE';
|
||||
break;
|
||||
}
|
||||
}
|
||||
response = 'Current: ' + require('win-bcd').bootMode + ' , NextBoot: ' + (nextboot ? nextboot : 'NORMAL');
|
||||
break;
|
||||
}
|
||||
|
@ -195,28 +195,29 @@ module.exports.CertificateOperations = function (parent) {
|
||||
}
|
||||
|
||||
// Return the certificate of the remote HTTPS server
|
||||
obj.loadCertificate = function (url, tag, func) {
|
||||
obj.loadCertificate = function (url, hostname, tag, func) {
|
||||
const u = require('url').parse(url);
|
||||
if (u.protocol == 'https:') {
|
||||
// Read the certificate from HTTPS
|
||||
const tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { servername: u.hostname, rejectUnauthorized: false }, function () { this.xxcert = this.getPeerCertificate(); this.end(); });
|
||||
if (hostname == null) { hostname = u.hostname; }
|
||||
const tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { servername: hostname, rejectUnauthorized: false }, function () { this.xxcert = this.getPeerCertificate(); this.end(); });
|
||||
tlssocket.xxurl = url;
|
||||
tlssocket.xxfunc = func;
|
||||
tlssocket.xxtag = tag;
|
||||
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert.raw.toString('binary'), this.xxtag); });
|
||||
tlssocket.on('error', function () { this.xxfunc(this.xxurl, null, this.xxtag); });
|
||||
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert.raw.toString('binary'), hostname, this.xxtag); });
|
||||
tlssocket.on('error', function () { this.xxfunc(this.xxurl, null, hostname, this.xxtag); });
|
||||
} else if (u.protocol == 'file:') {
|
||||
// Read the certificate from a file
|
||||
obj.fs.readFile(url.substring(7), 'utf8', function (err, data) {
|
||||
if (err) { func(url, null, tag); return; }
|
||||
var x1 = data.indexOf('-----BEGIN CERTIFICATE-----'), x2 = data.indexOf('-----END CERTIFICATE-----');
|
||||
if ((x1 >= 0) && (x2 > x1)) {
|
||||
func(url, Buffer.from(data.substring(x1 + 27, x2), 'base64').toString('binary'), tag);
|
||||
func(url, Buffer.from(data.substring(x1 + 27, x2), 'base64').toString('binary'), hostname, tag);
|
||||
} else {
|
||||
func(url, data, tag);
|
||||
func(url, data, hostname, tag);
|
||||
}
|
||||
});
|
||||
} else { func(url, null, tag); }
|
||||
} else { func(url, null, hostname, tag); }
|
||||
};
|
||||
|
||||
// Check if a configuration file exists
|
||||
@ -495,13 +496,12 @@ module.exports.CertificateOperations = function (parent) {
|
||||
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField("CN").value;
|
||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||
r.WebIssuer = webCertificate.issuer.getField("CN").value;
|
||||
r.CommonName = webCertificate.subject.getField("CN").value;
|
||||
if (r.CommonName.startsWith('*.')) {
|
||||
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||
if (commonName.startsWith('*.')) { console.log("ERROR: Server can't use a wildcard name: " + commonName); process.exit(0); return; }
|
||||
r.CommonName = commonName;
|
||||
if (commonName == "un-configured") { // If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard).
|
||||
commonName = webCertificate.subject.getField("CN").value;
|
||||
if (commonName.startsWith('*.')) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||
}
|
||||
r.CommonNames = [ r.CommonName.toLowerCase() ];
|
||||
r.CommonName = commonName;
|
||||
r.CommonNames = [commonName.toLowerCase()];
|
||||
var altNames = webCertificate.getExtension("subjectAltName");
|
||||
if (altNames) {
|
||||
for (i = 0; i < altNames.altNames.length; i++) {
|
||||
|
@ -35,6 +35,9 @@ module.exports.makeFilename = function (v) { return v.split('\\').join('').split
|
||||
// Move an element from one position in an array to a new position
|
||||
module.exports.ArrayElementMove = function(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
|
||||
|
||||
// Format a string with arguments, "replaces {0} and {1}..."
|
||||
module.exports.format = function (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; }); };
|
||||
|
||||
// Print object for HTML
|
||||
module.exports.ObjectToStringEx = function (x, c) {
|
||||
var r = "", i;
|
||||
|
@ -53,6 +53,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
|
||||
}
|
||||
|
||||
// Remove this agent from the list of agents with bad web certificates
|
||||
if (obj.badWebCert) { delete parent.wsagentsWithBadWebCerts[obj.badWebCert]; }
|
||||
|
||||
// Get the current mesh
|
||||
const mesh = parent.meshes[obj.dbMeshKey];
|
||||
|
||||
@ -381,6 +384,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
} else {
|
||||
// Check that the server hash matches our own web certificate hash (SHA384)
|
||||
if ((getWebCertHash(domain) != msg.substring(2, 50)) && (getWebCertFullHash(domain) != msg.substring(2, 50))) {
|
||||
if (parent.parent.supportsProxyCertificatesRequest !== false) {
|
||||
obj.badWebCert = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64');
|
||||
parent.wsagentsWithBadWebCerts[obj.badWebCert] = obj; // Add this agent to the list of of agents with bad web certificates.
|
||||
parent.parent.updateProxyCertificates(false);
|
||||
}
|
||||
parent.agentStats.agentBadWebCertHashCount++;
|
||||
console.log('Agent bad web cert hash (Agent:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (Buffer.from(getWebCertHash(domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (new Buffer(getWebCertFullHash(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')) + '.');
|
||||
|
175
meshcentral.js
175
meshcentral.js
@ -396,34 +396,34 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Show a list of all configuration files in the database
|
||||
if (obj.args.dblistconfigfiles) {
|
||||
obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log('No files found.'); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return;
|
||||
obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log("No files found."); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return;
|
||||
}
|
||||
|
||||
// Display the content of a configuration file in the database
|
||||
if (obj.args.dbshowconfigfile) {
|
||||
if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
|
||||
if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
|
||||
obj.db.getConfigFile(obj.args.dbshowconfigfile, function (err, docs) {
|
||||
if (err == null) {
|
||||
if (docs.length == 0) { console.log('File not found.'); } else {
|
||||
if (docs.length == 0) { console.log("File not found."); } else {
|
||||
var data = obj.db.decryptData(obj.args.configkey, docs[0].data);
|
||||
if (data == null) { console.log('Invalid config key.'); } else { console.log(data); }
|
||||
if (data == null) { console.log("Invalid config key."); } else { console.log(data); }
|
||||
}
|
||||
} else { console.log('Unable to read from database.'); }
|
||||
} else { console.log("Unable to read from database."); }
|
||||
process.exit();
|
||||
}); return;
|
||||
}
|
||||
|
||||
// Delete all configuration files from database
|
||||
if (obj.args.dbdeleteconfigfiles) {
|
||||
console.log('Deleting all configuration files from the database...'); obj.db.RemoveAllOfType('cfile', function () { console.log('Done.'); process.exit(); });
|
||||
console.log("Deleting all configuration files from the database..."); obj.db.RemoveAllOfType('cfile', function () { console.log('Done.'); process.exit(); });
|
||||
}
|
||||
|
||||
// Push all relevent files from meshcentral-data into the database
|
||||
if (obj.args.dbpushconfigfiles) {
|
||||
if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
|
||||
if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
|
||||
if ((obj.args.dbpushconfigfiles !== true) && (typeof obj.args.dbpushconfigfiles != 'string')) {
|
||||
console.log('Usage: --dbpulldatafiles (path) This will import files from folder into the database');
|
||||
console.log(' --dbpulldatafiles This will import files from meshcentral-data into the db.');
|
||||
console.log("Usage: --dbpulldatafiles (path) This will import files from folder into the database");
|
||||
console.log(" --dbpulldatafiles This will import files from meshcentral-data into the db.");
|
||||
process.exit();
|
||||
} else {
|
||||
if ((obj.args.dbpushconfigfiles == '*') || (obj.args.dbpushconfigfiles === true)) { obj.args.dbpushconfigfiles = obj.datapath; }
|
||||
@ -454,20 +454,20 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Pull all database files into meshcentral-data
|
||||
if (obj.args.dbpullconfigfiles) {
|
||||
if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
|
||||
if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
|
||||
if (typeof obj.args.dbpullconfigfiles != 'string') {
|
||||
console.log('Usage: --dbpulldatafiles (path)');
|
||||
console.log("Usage: --dbpulldatafiles (path)");
|
||||
process.exit();
|
||||
} else {
|
||||
obj.db.GetAllType('cfile', function (err, docs) {
|
||||
if (err == null) {
|
||||
if (docs.length == 0) {
|
||||
console.log('File not found.');
|
||||
console.log("File not found.");
|
||||
} else {
|
||||
for (var i in docs) {
|
||||
const file = docs[i]._id.split('/')[1], binary = obj.db.decryptData(obj.args.configkey, docs[i].data);
|
||||
if (binary == null) {
|
||||
console.log('Invalid config key.');
|
||||
console.log("Invalid config key.");
|
||||
} else {
|
||||
var fullFileName = obj.path.join(obj.args.dbpullconfigfiles, file);
|
||||
try { obj.fs.writeFileSync(fullFileName, binary); } catch (ex) { console.log('Unable to write to ' + fullFileName); process.exit(); return; }
|
||||
@ -476,7 +476,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('Unable to read from database.');
|
||||
console.log("Unable to read from database.");
|
||||
}
|
||||
process.exit();
|
||||
});
|
||||
@ -603,10 +603,10 @@ function CreateMeshCentralServer(config, args) {
|
||||
var key = null;
|
||||
if (typeof obj.args.configkey == 'string') { key = obj.args.configkey; }
|
||||
else if (typeof obj.args.loadconfigfromdb == 'string') { key = obj.args.loadconfigfromdb; }
|
||||
if (key == null) { console.log('Error, --configkey is required.'); process.exit(); return; }
|
||||
if (key == null) { console.log("Error, --configkey is required."); process.exit(); return; }
|
||||
obj.db.getAllConfigFiles(key, function (configFiles) {
|
||||
if (configFiles == null) { console.log('Error, no configuration files found or invalid configkey.'); process.exit(); return; }
|
||||
if (!configFiles['config.json']) { console.log('Error, could not file config.json from database.'); process.exit(); return; }
|
||||
if (configFiles == null) { console.log("Error, no configuration files found or invalid configkey."); process.exit(); return; }
|
||||
if (!configFiles['config.json']) { console.log("Error, could not file config.json from database."); process.exit(); return; }
|
||||
obj.configurationFiles = configFiles;
|
||||
|
||||
// Parse the new configuration file
|
||||
@ -744,9 +744,9 @@ function CreateMeshCentralServer(config, args) {
|
||||
var adminname = obj.args.admin.split('/');
|
||||
if (adminname.length == 1) { adminname = 'user//' + adminname[0]; }
|
||||
else if (adminname.length == 2) { adminname = 'user/' + adminname[0] + '/' + adminname[1]; }
|
||||
else { console.log('Invalid administrator name.'); process.exit(); return; }
|
||||
else { console.log("Invalid administrator name."); process.exit(); return; }
|
||||
obj.db.Get(adminname, function (err, user) {
|
||||
if (user.length != 1) { console.log('Invalid user name.'); process.exit(); return; }
|
||||
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
||||
user[0].siteadmin = 4294967295; // 0xFFFFFFFF
|
||||
obj.db.Set(user[0], function () {
|
||||
if (user[0].domain == '') { console.log('User ' + user[0].name + ' set to site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' set to site administrator.'); }
|
||||
@ -762,9 +762,9 @@ function CreateMeshCentralServer(config, args) {
|
||||
var adminname = obj.args.unadmin.split('/');
|
||||
if (adminname.length == 1) { adminname = 'user//' + adminname[0]; }
|
||||
else if (adminname.length == 2) { adminname = 'user/' + adminname[0] + '/' + adminname[1]; }
|
||||
else { console.log('Invalid administrator name.'); process.exit(); return; }
|
||||
else { console.log("Invalid administrator name."); process.exit(); return; }
|
||||
obj.db.Get(adminname, function (err, user) {
|
||||
if (user.length != 1) { console.log('Invalid user name.'); process.exit(); return; }
|
||||
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
||||
if (user[0].siteadmin) { delete user[0].siteadmin; }
|
||||
obj.db.Set(user[0], function () {
|
||||
if (user[0].domain == '') { console.log('User ' + user[0].name + ' is not a site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' is not a site administrator.'); }
|
||||
@ -793,15 +793,15 @@ function CreateMeshCentralServer(config, args) {
|
||||
while (obj.dbconfig.amtWsEventSecret == null) { process.nextTick(); }
|
||||
var username = buf.toString('hex');
|
||||
var nodeid = obj.args.getwspass;
|
||||
var pass = obj.crypto.createHash('sha384').update(username.toLowerCase() + ":" + nodeid + ":" + obj.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
|
||||
console.log('--- Intel(r) AMT WSMAN eventing credentials ---');
|
||||
console.log('Username: ' + username);
|
||||
console.log('Password: ' + pass);
|
||||
console.log('Argument: ' + nodeid);
|
||||
var pass = obj.crypto.createHash('sha384').update(username.toLowerCase() + ':' + nodeid + ':' + obj.dbconfig.amtWsEventSecret).digest('base64').substring(0, 12).split('/').join('x').split('\\').join('x');
|
||||
console.log("--- Intel(r) AMT WSMAN eventing credentials ---");
|
||||
console.log("Username: " + username);
|
||||
console.log("Password: " + pass);
|
||||
console.log("Argument: " + nodeid);
|
||||
process.exit();
|
||||
});
|
||||
} else {
|
||||
console.log('Invalid NodeID.');
|
||||
console.log("Invalid NodeID.");
|
||||
process.exit();
|
||||
}
|
||||
return;
|
||||
@ -809,7 +809,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Start plugin manager if configuration allows this.
|
||||
if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null)) {
|
||||
obj.pluginHandler = require("./pluginHandler.js").pluginHandler(obj);
|
||||
obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
|
||||
}
|
||||
|
||||
// Load the default meshcore and meshcmd
|
||||
@ -838,7 +838,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.letsencrypt != null) {
|
||||
obj.letsencrypt.getCertificate(certs, obj.StartEx3); // Use Let's Encrypt certificate
|
||||
} else {
|
||||
console.log('ERROR: Unable to setup GreenLock module.');
|
||||
console.log("ERROR: Unable to setup GreenLock module.");
|
||||
obj.StartEx3(certs); // Let's Encrypt did not load, just use the configured certificates
|
||||
}
|
||||
}
|
||||
@ -847,48 +847,23 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Start the server with the given certificates, but check if we have web certificates to load
|
||||
obj.StartEx3 = function (certs) {
|
||||
var i, webCertLoadCount = 0;
|
||||
obj.certificates = certs;
|
||||
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
||||
|
||||
// Load any domain web certificates
|
||||
for (i in obj.config.domains) {
|
||||
for (var i in obj.config.domains) {
|
||||
// Load any Intel AMT ACM activation certificates
|
||||
obj.certificateOperations.loadIntelAmtAcmCerts(obj.config.domains[i].amtacmactivation);
|
||||
|
||||
if (obj.config.domains[i].certurl != null) {
|
||||
// Fix the URL and add 'https://' if needed
|
||||
if (typeof obj.config.domains[i].certurl == 'string') {
|
||||
obj.supportsProxyCertificatesRequest = true; // If a certurl is set, enable proxy cert requests
|
||||
// Then, fix the URL and add 'https://' if needed
|
||||
if (obj.config.domains[i].certurl.indexOf('://') < 0) { obj.config.domains[i].certurl = 'https://' + obj.config.domains[i].certurl; }
|
||||
|
||||
// Load web certs
|
||||
webCertLoadCount++;
|
||||
obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, obj.config.domains[i], function (url, cert, xdomain) {
|
||||
if (cert != null) {
|
||||
// Hash the entire cert
|
||||
var hash = obj.crypto.createHash('sha384').update(Buffer.from(cert, 'binary')).digest('hex');
|
||||
if (xdomain.certhash != hash) { xdomain.certkeyhash = hash; xdomain.certhash = hash; }
|
||||
|
||||
try {
|
||||
// Decode a RSA certificate and hash the public key, if this is not RSA, skip this.
|
||||
var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert));
|
||||
xdomain.certkeyhash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
|
||||
//console.log('V1: ' + xdomain.certkeyhash);
|
||||
} catch (ex) { }
|
||||
|
||||
console.log('Loaded web certificate from ' + url);
|
||||
console.log(' SHA384 cert hash: ' + xdomain.certhash);
|
||||
if (xdomain.certhash != xdomain.certkeyhash) { console.log(' SHA384 key hash: ' + xdomain.certkeyhash); }
|
||||
} else {
|
||||
console.log('Failed to load web certificate at: ' + url);
|
||||
}
|
||||
webCertLoadCount--;
|
||||
if (webCertLoadCount == 0) { obj.StartEx4(); } // Done loading all certificates
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// No certificate to load, start the server
|
||||
if (webCertLoadCount == 0) { obj.StartEx4(); }
|
||||
if (obj.supportsProxyCertificatesRequest == true) { obj.updateProxyCertificates(true); }
|
||||
obj.StartEx4(); // Keep going
|
||||
}
|
||||
|
||||
// Start the server with the given certificates
|
||||
@ -901,7 +876,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
// Write server version and run mode
|
||||
var productionMode = (process.env.NODE_ENV && (process.env.NODE_ENV == 'production'));
|
||||
var runmode = (obj.args.lanonly ? 2 : (obj.args.wanonly ? 1 : 0));
|
||||
console.log('MeshCentral v' + obj.currentVer + ', ' + (['Hybrid (LAN + WAN) mode', 'WAN mode', 'LAN mode'][runmode]) + (productionMode ? ', Production mode.' : '.'));
|
||||
console.log("MeshCentral v" + obj.currentVer + ', ' + (["Hybrid (LAN + WAN) mode", "WAN mode", "LAN mode"][runmode]) + (productionMode ? ", Production mode." : '.'));
|
||||
|
||||
// Check that no sub-domains have the same DNS as the parent
|
||||
for (i in obj.config.domains) {
|
||||
@ -1027,9 +1002,9 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
|
||||
}, 300000);
|
||||
|
||||
obj.debug('main', 'Server started');
|
||||
obj.debug('main', "Server started");
|
||||
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
|
||||
obj.updateServerState('state', 'running');
|
||||
obj.updateServerState('state', "running");
|
||||
|
||||
// Setup auto-backup defaults
|
||||
if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupintervalhours: 24, keeplastdaysbackup: 10 }; }
|
||||
@ -1043,6 +1018,62 @@ function CreateMeshCentralServer(config, args) {
|
||||
});
|
||||
};
|
||||
|
||||
// Refresh any certificate hashs from the reverse proxy
|
||||
obj.pendingProxyCertificatesRequests = 0;
|
||||
obj.lastProxyCertificatesRequest = null;
|
||||
obj.supportsProxyCertificatesRequest = false;
|
||||
obj.updateProxyCertificates = function (force) {
|
||||
if (force !== true) {
|
||||
if ((obj.pendingProxyCertificatesRequests > 0) || (obj.supportsProxyCertificatesRequest == false)) return;
|
||||
if ((obj.lastProxyCertificatesRequest != null) && ((Date.now() - obj.lastProxyCertificatesRequest) < 120000)) return; // Don't allow this call more than every 2 minutes.
|
||||
obj.lastProxyCertificatesRequest = Date.now();
|
||||
}
|
||||
|
||||
// Load any domain web certificates
|
||||
for (var i in obj.config.domains) {
|
||||
if (obj.config.domains[i].certurl != null) {
|
||||
// Load web certs
|
||||
obj.pendingProxyCertificatesRequests++;
|
||||
var dnsname = obj.config.domains[i].dns;
|
||||
if ((dnsname == null) && (obj.config.settings.cert != null)) { dnsname = obj.config.settings.cert; }
|
||||
obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, dnsname, obj.config.domains[i], function (url, cert, xhostname, xdomain) {
|
||||
obj.pendingProxyCertificatesRequests--;
|
||||
if (cert != null) {
|
||||
// Hash the entire cert
|
||||
var hash = obj.crypto.createHash('sha384').update(Buffer.from(cert, 'binary')).digest('hex');
|
||||
if (xdomain.certhash != hash) { // The certificate has changed.
|
||||
xdomain.certkeyhash = hash;
|
||||
xdomain.certhash = hash;
|
||||
|
||||
try {
|
||||
// Decode a RSA certificate and hash the public key, if this is not RSA, skip this.
|
||||
var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert));
|
||||
xdomain.certkeyhash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
|
||||
//console.log('V1: ' + xdomain.certkeyhash);
|
||||
} catch (ex) {
|
||||
delete xdomain.certkeyhash;
|
||||
}
|
||||
|
||||
if (obj.webserver) {
|
||||
obj.webserver.webCertificateHashs[xdomain.id] = obj.webserver.webCertificateFullHashs[xdomain.id] = Buffer.from(hash, 'hex').toString('binary');
|
||||
if (xdomain.certkeyhash != null) { obj.webserver.webCertificateHashs[xdomain.id] = Buffer.from(xdomain.certkeyhash, 'hex').toString('binary'); }
|
||||
|
||||
// Disconnect all agents with bad web certificates
|
||||
for (var i in obj.webserver.wsagentsWithBadWebCerts) { obj.webserver.wsagentsWithBadWebCerts[i].close(1); }
|
||||
}
|
||||
|
||||
console.log(obj.common.format("Loaded web certificate from \"{0}\", host: \"{1}\"", url, xhostname));
|
||||
console.log(obj.common.format(" SHA384 cert hash: {0}", xdomain.certhash));
|
||||
if ((xdomain.certkeyhash != null) && (xdomain.certhash != xdomain.certkeyhash)) { console.log(obj.common.format(" SHA384 key hash: {0}", xdomain.certkeyhash)); }
|
||||
}
|
||||
} else {
|
||||
console.log(obj.common.format("Failed to load web certificate at: \"{0}\", host: \"{1}\"", url, xhostname));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform maintenance operations (called every hour)
|
||||
obj.maintenanceActions = function () {
|
||||
// Check for self-update that targets a specific version
|
||||
@ -1066,19 +1097,19 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (!obj.db) return;
|
||||
|
||||
// Dispatch an event saying the server is now stopping
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' });
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: "Server stopped" });
|
||||
|
||||
// Set all nodes to power state of unknown (0)
|
||||
obj.db.storePowerEvent({ time: new Date(), nodeid: '*', power: 0, s: 2 }, obj.multiServer, function () { // s:2 indicates that the server is shutting down.
|
||||
if (restoreFile) {
|
||||
obj.debug('main', 'Server stopped, updating settings: ' + restoreFile);
|
||||
console.log('Updating settings folder...');
|
||||
obj.debug('main', obj.common.format("Server stopped, updating settings: {0}", restoreFile));
|
||||
console.log("Updating settings folder...");
|
||||
|
||||
var yauzl = require("yauzl");
|
||||
var yauzl = require('yauzl');
|
||||
yauzl.open(restoreFile, { lazyEntries: true }, function (err, zipfile) {
|
||||
if (err) throw err;
|
||||
zipfile.readEntry();
|
||||
zipfile.on("entry", function (entry) {
|
||||
zipfile.on('entry', function (entry) {
|
||||
if (/\/$/.test(entry.fileName)) {
|
||||
// Directory file names end with '/'.
|
||||
// Note that entires for directories themselves are optional.
|
||||
@ -1088,22 +1119,22 @@ function CreateMeshCentralServer(config, args) {
|
||||
// file entry
|
||||
zipfile.openReadStream(entry, function (err, readStream) {
|
||||
if (err) throw err;
|
||||
readStream.on("end", function () { zipfile.readEntry(); });
|
||||
readStream.on('end', function () { zipfile.readEntry(); });
|
||||
// console.log('Extracting:', obj.getConfigFilePath(entry.fileName));
|
||||
readStream.pipe(obj.fs.createWriteStream(obj.getConfigFilePath(entry.fileName)));
|
||||
});
|
||||
}
|
||||
});
|
||||
zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
|
||||
zipfile.on('end', function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
|
||||
});
|
||||
} else {
|
||||
obj.debug('main', 'Server stopped');
|
||||
obj.debug('main', "Server stopped");
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the server state
|
||||
obj.updateServerState('state', 'stopped');
|
||||
obj.updateServerState('state', "stopped");
|
||||
};
|
||||
|
||||
// Event Dispatch
|
||||
|
36
meshuser.js
36
meshuser.js
@ -120,19 +120,29 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
} else return null;
|
||||
var rootfolder = meshpath[0], rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
|
||||
if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
|
||||
var path = parent.path.join(parent.filespath, domainx, rootfoldersplit[0] + "-" + rootfoldersplit[2]);
|
||||
var path = parent.path.join(parent.filespath, domainx, rootfoldersplit[0] + '-' + rootfoldersplit[2]);
|
||||
for (var i = 1; i < meshpath.length; i++) { if (common.IsFilenameValid(meshpath[i]) == false) { path = null; break; } path += ("/" + meshpath[i]); }
|
||||
return path;
|
||||
}
|
||||
|
||||
// TODO: Replace this with something better?
|
||||
// Copy a file using the best technique available
|
||||
function copyFile(src, dest, func, tag) {
|
||||
var ss = fs.createReadStream(src), ds = fs.createWriteStream(dest);
|
||||
ss.pipe(ds);
|
||||
ds.ss = ss;
|
||||
if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
|
||||
else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
|
||||
ds.on('close', function () { func(tag); });
|
||||
if (fs.copyFile) {
|
||||
// NodeJS v8.5 and higher
|
||||
fs.copyFile(src, dest, function (err) { func(tag); })
|
||||
} else {
|
||||
// Older NodeJS
|
||||
try {
|
||||
var ss = fs.createReadStream(src), ds = fs.createWriteStream(dest);
|
||||
ss.on('error', function () { func(tag); });
|
||||
ds.on('error', function () { func(tag); });
|
||||
ss.pipe(ds);
|
||||
ds.ss = ss;
|
||||
if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
|
||||
else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
|
||||
ds.on('close', function () { func(tag); });
|
||||
} catch (ex) { }
|
||||
}
|
||||
}
|
||||
|
||||
// Route a command to a target node
|
||||
@ -607,9 +617,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
|
||||
if ((command.fileop == 'createfolder') && (common.IsFilenameValid(command.newfolder) == true)) {
|
||||
// Create a new folder
|
||||
try { fs.mkdirSync(path + "/" + command.newfolder); } catch (e) {
|
||||
try { fs.mkdirSync(path); } catch (e) { }
|
||||
try { fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { }
|
||||
try { fs.mkdirSync(path + '/' + command.newfolder); } catch (ex) {
|
||||
try { fs.mkdirSync(path); } catch (ex) { }
|
||||
try { fs.mkdirSync(path + '/' + command.newfolder); } catch (ex) { }
|
||||
}
|
||||
}
|
||||
else if (command.fileop == 'delete') {
|
||||
@ -619,9 +629,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (common.IsFilenameValid(command.delfiles[i]) == true) {
|
||||
var fullpath = parent.path.join(path, command.delfiles[i]);
|
||||
if (command.rec == true) {
|
||||
deleteFolderRecursive(fullpath); // TODO, make this an async function
|
||||
try { deleteFolderRecursive(fullpath); } catch (ex) { } // TODO, make this an async function
|
||||
} else {
|
||||
try { fs.rmdirSync(fullpath); } catch (e) { try { fs.unlinkSync(fullpath); } catch (e) { } }
|
||||
try { fs.rmdirSync(fullpath); } catch (ex) { try { fs.unlinkSync(fullpath); } catch (xe) { } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.4.3-l",
|
||||
"version": "0.4.3-s",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -3,10 +3,10 @@
|
||||
border: none;
|
||||
margin: 2px;
|
||||
margin-top: 3px;
|
||||
float: right;
|
||||
border-radius: 3px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.topButton:hover {
|
||||
|
File diff suppressed because one or more lines are too long
@ -514,7 +514,7 @@
|
||||
<span id="DeskTimer" title="Session time"></span>
|
||||
<select id=termdisplays style="display:none" onchange=deskSetDisplay(event) onkeypress="return false" onkeydown="return false"></select>
|
||||
<input id=DeskToolsButton type=button value=Tools title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()" />
|
||||
<span id=DeskChatButton class="deskarea" title="Open chat window to this computer"><img src='images/icon-chat.png' onclick=deviceChat() height=16 width=16 style=padding-top:2px /></span>
|
||||
<span id=DeskChatButton class="deskarea" title="Open chat window to this computer"><img src='images/icon-chat.png' onclick=deviceChat(event) height=16 width=16 style=padding-top:2px /></span>
|
||||
<span id=DeskNotifyButton title="Display a notification on the remote computer"><img src='images/icon-notify.png' onclick=deviceToastFunction() height=16 width=16 style=padding-top:2px /></span>
|
||||
<span id=DeskOpenWebButton title="Open a web address on remote computer"><img src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 style=padding-top:2px /></span>
|
||||
</div>
|
||||
@ -4549,11 +4549,15 @@
|
||||
|
||||
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
|
||||
|
||||
function deviceChat() {
|
||||
function deviceChat(e) {
|
||||
if (xxdialogMode) return;
|
||||
var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
|
||||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||||
if (e && (e.shiftKey == true)) {
|
||||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||||
} else {
|
||||
window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
|
||||
}
|
||||
meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
|
||||
}
|
||||
|
||||
@ -6192,6 +6196,7 @@
|
||||
function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
|
||||
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
|
||||
function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
|
||||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
|
||||
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
|
||||
function p13viewfile() {
|
||||
var checkboxes = document.getElementsByName('fd');
|
||||
@ -7768,12 +7773,12 @@
|
||||
var h = '';
|
||||
if (f.t < 3 || f.t == 4) {
|
||||
var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
|
||||
h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||||
h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '"> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||||
} else {
|
||||
var link = shortname, publiclink = '';
|
||||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
|
||||
if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
|
||||
h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
|
||||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
|
||||
if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
|
||||
h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '"> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
|
||||
}
|
||||
|
||||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||||
@ -7869,9 +7874,35 @@
|
||||
function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
|
||||
function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e && e.keyCode == 13)) { dialogclose(1); } }
|
||||
var isFilenameValid = (function(){ var x1=/^[^\\/:\*\?"<>\|]+$/, x2=/^\./, x3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname){ return x1.test(fname)&&!x2.test(fname)&&!x3.test(fname)&&(fname[0] != '.'); } })();
|
||||
function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
|
||||
function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="p5updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /><span id=p5confirmOverwriteSpan style=display:none><br /><label><input type=checkbox id=p5confirmOverwrite onchange="p5updateUploadDialogOk(\'p5uploadinput\')" />' + "Confirm overwrite?" + '</label></span></form>'); p5updateUploadDialogOk('p5uploadinput'); }
|
||||
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
|
||||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
|
||||
function p5updateUploadDialogOk() {
|
||||
// Check if these are files we can upload, remove all folders.
|
||||
var xallfiles = Q('p5uploadinput').files, files = [];
|
||||
for (var i in xallfiles) { if ((xallfiles[i].size != null) && (xallfiles[i].size != 0)) { files.push(xallfiles[i]); } }
|
||||
|
||||
// Check if these files are duplicates of existing files.
|
||||
var filetreex = filetree, allfiles = [], overWriteCount = 0;
|
||||
for (var i in filetreelocation) {
|
||||
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) { filetreex = filetreex.f[filetreelocation[i]]; }
|
||||
}
|
||||
QE('idx_dlgOkButton', xallfiles.length > 0);
|
||||
if (xallfiles.length > 0) {
|
||||
if (filetreex.f != null) {
|
||||
for (var i in filetreex.f) { allfiles.push(i); }
|
||||
for (var i = 0; i < xallfiles.length; i++) {
|
||||
if (allfiles.indexOf(xallfiles[i].name) >= 0) { overWriteCount++; } // TODO: If the server is Windows, we need to lowercase both names.
|
||||
}
|
||||
}
|
||||
QV('p5confirmOverwriteSpan', overWriteCount > 0);
|
||||
if (overWriteCount > 0) {
|
||||
QE('idx_dlgOkButton', Q('p5confirmOverwrite').checked);
|
||||
} else {
|
||||
Q('p5confirmOverwrite').checked = false;
|
||||
QE('idx_dlgOkButton', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
function p5viewfile() {
|
||||
var checkboxes = document.getElementsByName('fc');
|
||||
@ -7885,7 +7916,16 @@
|
||||
*/
|
||||
|
||||
var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
|
||||
function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
|
||||
function p5copyFile(cut) {
|
||||
var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
|
||||
console.log('yy', checkboxes[i].value);
|
||||
p5clipboard.push(checkboxes[i].value);
|
||||
}
|
||||
}
|
||||
p5updateClipview();
|
||||
}
|
||||
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
|
||||
function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
|
||||
function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
|
||||
@ -8341,8 +8381,9 @@
|
||||
}
|
||||
|
||||
function showCreateNewAccountDialogValidate(x) {
|
||||
var ve = validateEmail(Q('p4email').value);
|
||||
var ve = true;
|
||||
if (serverinfo.emailcheck) {
|
||||
ve = validateEmail(Q('p4email').value);
|
||||
QE('p4verifiedEmail', ve);
|
||||
QE('p4invitationEmail', ve && Q('p4resetNextLogin').checked && Q('p4verifiedEmail').checked);
|
||||
if (ve == false) { Q('p4verifiedEmail').checked = false; }
|
||||
@ -8609,8 +8650,8 @@
|
||||
function p30showUserChangePassDialog(multiFactor) {
|
||||
if (xxdialogMode) return;
|
||||
var x = '';
|
||||
x += addHtmlValue("Password", '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Password", '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Password", '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Password", '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
if (features & 0x00010000) { x += addHtmlValue("Password hint", '<input id=p4hint type=text style=width:230px maxlength=256></input>'); }
|
||||
|
||||
if (passRequirements) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -12,13 +12,14 @@
|
||||
</head>
|
||||
<body style="font-family:Arial,Helvetica,sans-serif">
|
||||
<div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
|
||||
<div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
|
||||
<div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
|
||||
<div id="camButton" class="icon2 topButton" title="Activate camera & microphone" style="display:none" onclick="camButtonClick()"></div>
|
||||
<div id="micButton" class="icon6 topButton" title="Activate microphone" style="display:none" onclick="micButtonClick()"></div>
|
||||
<div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
|
||||
<div style="display:inline-block;width:2px"></div>
|
||||
<div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b>MeshMessenger<span id="xtitle"></span></b></div>
|
||||
<div style="position:absolute;background-color:#036;right:0;height:38px">
|
||||
<div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
|
||||
<div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
|
||||
<div id="camButton" class="icon2 topButton" title="Activate camera & microphone" style="display:none" onclick="camButtonClick()"></div>
|
||||
<div id="micButton" class="icon6 topButton" title="Activate microphone" style="display:none" onclick="micButtonClick()"></div>
|
||||
<div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
|
||||
</div>
|
||||
<div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b><span id="xtitle">MeshMessenger</span></b></div>
|
||||
</div>
|
||||
<div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
|
||||
<div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
|
||||
@ -65,7 +66,7 @@
|
||||
var currentFileDownload = null;
|
||||
|
||||
// Set the title
|
||||
if (args.title) { QH('xtitle', ' - ' + args.title); document.title = document.title + ' - ' + args.title; }
|
||||
if (args.title) { QH('xtitle', args.title.split(' ').join(' ')); document.title = document.title + ' - ' + args.title; }
|
||||
|
||||
// Setup web notifications
|
||||
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||
|
File diff suppressed because one or more lines are too long
@ -500,7 +500,7 @@
|
||||
<span id="DeskTimer" title="Session time"></span>
|
||||
<select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onkeypress="return false" onkeydown="return false"></select>
|
||||
<input id="DeskToolsButton" type="button" value="Outils" title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">
|
||||
<span id="DeskChatButton" class="deskarea" title="Ouvrir la fenêtre de discussion sur cet ordinateur"><img src="images/icon-chat.png" onclick="deviceChat()" height="16" width="16" style="padding-top:2px"></span>
|
||||
<span id="DeskChatButton" class="deskarea" title="Ouvrir la fenêtre de discussion sur cet ordinateur"><img src="images/icon-chat.png" onclick="deviceChat(event)" height="16" width="16" style="padding-top:2px"></span>
|
||||
<span id="DeskNotifyButton" title="Display a notification on the remote computer"><img src="images/icon-notify.png" onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span>
|
||||
<span id="DeskOpenWebButton" title="Open a web address on remote computer"><img src="images/icon-url2.png" onclick="deviceUrlFunction()" height="16" width="16" style="padding-top:2px"></span>
|
||||
</div>
|
||||
@ -4500,11 +4500,15 @@
|
||||
|
||||
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
|
||||
|
||||
function deviceChat() {
|
||||
function deviceChat(e) {
|
||||
if (xxdialogMode) return;
|
||||
var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
|
||||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||||
if (e && (e.shiftKey == true)) {
|
||||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||||
} else {
|
||||
window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
|
||||
}
|
||||
meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
|
||||
}
|
||||
|
||||
@ -6143,6 +6147,7 @@
|
||||
function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
|
||||
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
|
||||
function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
|
||||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
|
||||
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
|
||||
function p13viewfile() {
|
||||
var checkboxes = document.getElementsByName('fd');
|
||||
@ -7719,12 +7724,12 @@
|
||||
var h = '';
|
||||
if (f.t < 3 || f.t == 4) {
|
||||
var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
|
||||
h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||||
h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '"> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||||
} else {
|
||||
var link = shortname, publiclink = '';
|
||||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
|
||||
if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
|
||||
h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
|
||||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
|
||||
if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
|
||||
h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '"> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
|
||||
}
|
||||
|
||||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||||
@ -7820,9 +7825,35 @@
|
||||
function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
|
||||
function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e && e.keyCode == 13)) { dialogclose(1); } }
|
||||
var isFilenameValid = (function(){ var x1=/^[^\\/:\*\?"<>\|]+$/, x2=/^\./, x3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname){ return x1.test(fname)&&!x2.test(fname)&&!x3.test(fname)&&(fname[0] != '.'); } })();
|
||||
function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
|
||||
function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="p5updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /><span id=p5confirmOverwriteSpan style=display:none><br /><label><input type=checkbox id=p5confirmOverwrite onchange="p5updateUploadDialogOk(\'p5uploadinput\')" />' + "Confirm overwrite?" + '</label></span></form>'); p5updateUploadDialogOk('p5uploadinput'); }
|
||||
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
|
||||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
|
||||
function p5updateUploadDialogOk() {
|
||||
// Check if these are files we can upload, remove all folders.
|
||||
var xallfiles = Q('p5uploadinput').files, files = [];
|
||||
for (var i in xallfiles) { if ((xallfiles[i].size != null) && (xallfiles[i].size != 0)) { files.push(xallfiles[i]); } }
|
||||
|
||||
// Check if these files are duplicates of existing files.
|
||||
var filetreex = filetree, allfiles = [], overWriteCount = 0;
|
||||
for (var i in filetreelocation) {
|
||||
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) { filetreex = filetreex.f[filetreelocation[i]]; }
|
||||
}
|
||||
QE('idx_dlgOkButton', xallfiles.length > 0);
|
||||
if (xallfiles.length > 0) {
|
||||
if (filetreex.f != null) {
|
||||
for (var i in filetreex.f) { allfiles.push(i); }
|
||||
for (var i = 0; i < xallfiles.length; i++) {
|
||||
if (allfiles.indexOf(xallfiles[i].name) >= 0) { overWriteCount++; } // TODO: If the server is Windows, we need to lowercase both names.
|
||||
}
|
||||
}
|
||||
QV('p5confirmOverwriteSpan', overWriteCount > 0);
|
||||
if (overWriteCount > 0) {
|
||||
QE('idx_dlgOkButton', Q('p5confirmOverwrite').checked);
|
||||
} else {
|
||||
Q('p5confirmOverwrite').checked = false;
|
||||
QE('idx_dlgOkButton', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
function p5viewfile() {
|
||||
var checkboxes = document.getElementsByName('fc');
|
||||
@ -7836,7 +7867,16 @@
|
||||
*/
|
||||
|
||||
var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
|
||||
function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
|
||||
function p5copyFile(cut) {
|
||||
var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
|
||||
console.log('yy', checkboxes[i].value);
|
||||
p5clipboard.push(checkboxes[i].value);
|
||||
}
|
||||
}
|
||||
p5updateClipview();
|
||||
}
|
||||
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
|
||||
function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
|
||||
function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
|
||||
@ -8292,8 +8332,9 @@
|
||||
}
|
||||
|
||||
function showCreateNewAccountDialogValidate(x) {
|
||||
var ve = validateEmail(Q('p4email').value);
|
||||
var ve = true;
|
||||
if (serverinfo.emailcheck) {
|
||||
ve = validateEmail(Q('p4email').value);
|
||||
QE('p4verifiedEmail', ve);
|
||||
QE('p4invitationEmail', ve && Q('p4resetNextLogin').checked && Q('p4verifiedEmail').checked);
|
||||
if (ve == false) { Q('p4verifiedEmail').checked = false; }
|
||||
@ -8560,8 +8601,8 @@
|
||||
function p30showUserChangePassDialog(multiFactor) {
|
||||
if (xxdialogMode) return;
|
||||
var x = '';
|
||||
x += addHtmlValue("Mot de passe", '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Mot de passe", '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Mot de passe", '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
x += addHtmlValue("Mot de passe", '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||||
if (features & 0x00010000) { x += addHtmlValue("Password hint", '<input id=p4hint type=text style=width:230px maxlength=256></input>'); }
|
||||
|
||||
if (passRequirements) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -10,13 +10,14 @@
|
||||
</head>
|
||||
<body style="font-family:Arial,Helvetica,sans-serif">
|
||||
<div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
|
||||
<div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
|
||||
<div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
|
||||
<div id="camButton" class="icon2 topButton" title="Activer caméra et microphone" style="display:none" onclick="camButtonClick()"></div>
|
||||
<div id="micButton" class="icon6 topButton" title="Activer le microphone" style="display:none" onclick="micButtonClick()"></div>
|
||||
<div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
|
||||
<div style="display:inline-block;width:2px"></div>
|
||||
<div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b>MeshMessenger<span id="xtitle"></span></b></div>
|
||||
<div style="position:absolute;background-color:#036;right:0;height:38px">
|
||||
<div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
|
||||
<div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
|
||||
<div id="camButton" class="icon2 topButton" title="Activer caméra et microphone" style="display:none" onclick="camButtonClick()"></div>
|
||||
<div id="micButton" class="icon6 topButton" title="Activer le microphone" style="display:none" onclick="micButtonClick()"></div>
|
||||
<div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
|
||||
</div>
|
||||
<div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b><span id="xtitle">MeshMessenger</span></b></div>
|
||||
</div>
|
||||
<div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
|
||||
<div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
|
||||
@ -63,7 +64,7 @@
|
||||
var currentFileDownload = null;
|
||||
|
||||
// Set the title
|
||||
if (args.title) { QH('xtitle', ' - ' + args.title); document.title = document.title + ' - ' + args.title; }
|
||||
if (args.title) { QH('xtitle', args.title.split(' ').join(' ')); document.title = document.title + ' - ' + args.title; }
|
||||
|
||||
// Setup web notifications
|
||||
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||
|
35
webserver.js
35
webserver.js
@ -156,20 +156,21 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
|
||||
// Main lists
|
||||
obj.wsagents = {}; // NodeId --> Agent
|
||||
obj.wsagents = {}; // NodeId --> Agent
|
||||
obj.wsagentsWithBadWebCerts = {}; // NodeId --> Agent
|
||||
obj.wsagentsDisconnections = {};
|
||||
obj.wsagentsDisconnectionsTimer = null;
|
||||
obj.duplicateAgentsLog = {};
|
||||
obj.wssessions = {}; // UserId --> Array Of Sessions
|
||||
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
||||
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
||||
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
||||
obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
|
||||
obj.wsrelays = {}; // Id -> Relay
|
||||
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
||||
var tlsSessionStore = {}; // Store TLS session information for quick resume.
|
||||
var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
|
||||
obj.wssessions = {}; // UserId --> Array Of Sessions
|
||||
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
||||
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
||||
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
||||
obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
|
||||
obj.wsrelays = {}; // Id -> Relay
|
||||
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
||||
var tlsSessionStore = {}; // Store TLS session information for quick resume.
|
||||
var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
|
||||
|
||||
// Setup randoms
|
||||
obj.crypto.randomBytes(48, function (err, buf) { obj.httpAuthRandom = buf; });
|
||||
@ -2690,11 +2691,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Delete a folder and all sub items. (TODO: try to make all async version)
|
||||
function deleteFolderRec(path) {
|
||||
if (obj.fs.existsSync(path) == false) return;
|
||||
obj.fs.readdirSync(path).forEach(function (file, index) {
|
||||
var pathx = path + "/" + file;
|
||||
if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
|
||||
});
|
||||
obj.fs.rmdirSync(path);
|
||||
try {
|
||||
obj.fs.readdirSync(path).forEach(function (file, index) {
|
||||
var pathx = path + '/' + file;
|
||||
if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
|
||||
});
|
||||
obj.fs.rmdirSync(path);
|
||||
} catch (ex) { }
|
||||
}
|
||||
|
||||
// Handle Intel AMT events
|
||||
|
Loading…
Reference in New Issue
Block a user