Added built-in Let's Encrypt support using GreenLock.
This commit is contained in:
parent
f6ef228de6
commit
65d6775303
|
@ -28,7 +28,7 @@
|
||||||
<Compile Include="amtevents.js" />
|
<Compile Include="amtevents.js" />
|
||||||
<Compile Include="amtscanner.js" />
|
<Compile Include="amtscanner.js" />
|
||||||
<Compile Include="amtscript.js" />
|
<Compile Include="amtscript.js" />
|
||||||
<Compile Include="letsEncrypt.js" />
|
<Compile Include="letsencrypt.js" />
|
||||||
<Compile Include="meshaccelerator.js" />
|
<Compile Include="meshaccelerator.js" />
|
||||||
<Compile Include="meshmail.js" />
|
<Compile Include="meshmail.js" />
|
||||||
<Compile Include="meshscanner.js" />
|
<Compile Include="meshscanner.js" />
|
||||||
|
|
|
@ -213,7 +213,7 @@ module.exports.CertificateOperations = function () {
|
||||||
}
|
}
|
||||||
caindex++;
|
caindex++;
|
||||||
} while (caok == true);
|
} while (caok == true);
|
||||||
r.ca = calist;
|
r.web.ca = calist;
|
||||||
|
|
||||||
// Decode certificate arguments
|
// Decode certificate arguments
|
||||||
var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
|
var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
|
||||||
|
|
147
letsEncrypt.js
147
letsEncrypt.js
|
@ -1,81 +1,118 @@
|
||||||
/**
|
/**
|
||||||
* @description MeshCentral letsEncrypt module
|
* @description MeshCentral letsEncrypt module, uses GreenLock to do all the work.
|
||||||
* @author Ylian Saint-Hilaire
|
* @author Ylian Saint-Hilaire
|
||||||
* @copyright Intel Corporation 2018
|
* @copyright Intel Corporation 2018
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
* @version v0.0.1
|
* @version v0.0.2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports.CreateLetsEncrypt = function (parent) {
|
module.exports.CreateLetsEncrypt = function (parent) {
|
||||||
|
try {
|
||||||
|
const greenlock = require('greenlock');;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.webrootPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges');
|
obj.redirWebServerHooked = false;
|
||||||
obj.workPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges', 'work');
|
obj.leDomains = null;
|
||||||
obj.logsPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges', 'logs');
|
obj.leResults = null;
|
||||||
|
|
||||||
|
// Setup the certificate storage paths
|
||||||
|
obj.configPath = obj.parent.path.join(obj.parent.datapath, 'letsencrypt');
|
||||||
|
obj.webrootPath = obj.parent.path.join(obj.parent.datapath, 'letsencrypt', 'webroot');
|
||||||
|
try { obj.parent.fs.mkdirSync(obj.configPath); } catch (e) { }
|
||||||
try { obj.parent.fs.mkdirSync(obj.webrootPath); } catch (e) { }
|
try { obj.parent.fs.mkdirSync(obj.webrootPath); } catch (e) { }
|
||||||
try { obj.parent.fs.mkdirSync(obj.workPath); } catch (e) { }
|
|
||||||
try { obj.parent.fs.mkdirSync(obj.logsPath); } catch (e) { }
|
|
||||||
|
|
||||||
console.log('CreateLetsEncrypt-1', obj.webrootPath);
|
// Storage Backend, store data in the "meshcentral-data/letencrypt" folder.
|
||||||
console.log('CreateLetsEncrypt-1', obj.workPath);
|
var leStore = require('le-store-certbot').create({ configDir: obj.configPath, webrootPath: obj.webrootPath, debug: obj.parent.args.debug > 0 });
|
||||||
console.log('CreateLetsEncrypt-1', obj.logsPath);
|
|
||||||
|
|
||||||
obj.lex = require('greenlock-express').create({
|
// ACME Challenge Handlers
|
||||||
// Set to https://acme-v01.api.letsencrypt.org/directory in production
|
var leHttpChallenge = require('le-challenge-fs').create({ webrootPath: obj.webrootPath, debug: obj.parent.args.debug > 0 });
|
||||||
server: 'staging'
|
|
||||||
|
|
||||||
// If you wish to replace the default plugins, you may do so here
|
// Function to agree to terms of service
|
||||||
, challenges: {
|
function leAgree(opts, agreeCb) { agreeCb(null, opts.tosUrl); }
|
||||||
'http-01': require('le-challenge-fs').create({ webrootPath: obj.webrootPath })
|
|
||||||
|
// Create the main GreenLock code module.
|
||||||
|
var greenlockargs = {
|
||||||
|
server: (obj.parent.config.letsencrypt.production === true) ? greenlock.productionServerUrl : greenlock.stagingServerUrl,
|
||||||
|
store: leStore,
|
||||||
|
challenges: { 'http-01': leHttpChallenge },
|
||||||
|
challengeType: 'http-01',
|
||||||
|
agreeToTerms: leAgree,
|
||||||
|
debug: obj.parent.args.debug > 0
|
||||||
}
|
}
|
||||||
, store: require('le-store-certbot').create({
|
if (obj.parent.args.debug == null) { greenlockargs.log = function (debug) { } } // If not in debug mode, ignore all console output from greenlock (makes things clean).
|
||||||
//configDir: '/etc/letsencrypt',
|
obj.le = greenlock.create(greenlockargs);
|
||||||
//privkeyPath: ':configDir/live/:hostname/privkey.pem',
|
|
||||||
//fullchainPath: ':configDir/live/:hostname/fullchain.pem',
|
|
||||||
//certPath: ':configDir/live/:hostname/cert.pem',
|
|
||||||
//chainPath: ':configDir/live/:hostname/chain.pem',
|
|
||||||
workDir: obj.workPath,
|
|
||||||
logsDir: obj.logsPath,
|
|
||||||
webrootPath: obj.webrootPath,
|
|
||||||
debug: false
|
|
||||||
})
|
|
||||||
, approveDomains: approveDomains
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('CreateLetsEncrypt-2');
|
// Hook up GreenLock to the redirection server
|
||||||
function approveDomains(opts, certs, func) {
|
if (obj.parent.redirserver.port == 80) { obj.parent.redirserver.app.use('/', obj.le.middleware()); obj.redirWebServerHooked = true; }
|
||||||
console.log('approveDomains', opts, certs);
|
|
||||||
|
|
||||||
// This is where you check your database and associated
|
obj.getCertificate = function (certs, func) {
|
||||||
// email addresses with domains and agreements and such
|
if (certs.CommonName == 'un-configured') { console.log("ERROR: Use --cert to setup the default server name before using Let's Encrypt."); func(certs); return; }
|
||||||
|
if (obj.parent.config.letsencrypt == null) { func(certs); return; }
|
||||||
|
if (obj.parent.config.letsencrypt.email == null) { console.log("ERROR: Let's Encrypt email address not specified."); func(certs); return; }
|
||||||
|
if ((obj.parent.redirserver == null) || (obj.parent.redirserver.port !== 80)) { console.log("ERROR: Redirection web server must be active on port 80 for Let's Encrypt to work."); func(certs); return; }
|
||||||
|
if (obj.redirWebServerHooked !== true) { console.log("ERROR: Redirection web server not setup for Let's Encrypt to work."); func(certs); return; }
|
||||||
|
if ((obj.parent.config.letsencrypt.rsakeysize != null) && (obj.parent.config.letsencrypt.rsakeysize !== 2048) && (obj.parent.config.letsencrypt.rsakeysize !== 3072)) { console.log("ERROR: Invalid Let's Encrypt certificate key size, must be 2048 or 3072."); func(certs); return; }
|
||||||
|
|
||||||
|
// Get the list of domains
|
||||||
|
obj.leDomains = [certs.CommonName];
|
||||||
|
if (obj.parent.config.letsencrypt.names != null) {
|
||||||
|
if (typeof obj.parent.config.letsencrypt.names == 'string') { obj.parent.config.letsencrypt.names = obj.parent.config.letsencrypt.names.split(','); }
|
||||||
|
obj.parent.config.letsencrypt.names.map(function (s) { return s.trim() }); // Trim each name
|
||||||
|
if ((typeof obj.parent.config.letsencrypt.names != 'object') || (obj.parent.config.letsencrypt.names.length == null)) { console.log("ERROR: Let's Encrypt names must be an array in config.json."); func(certs); return; }
|
||||||
|
obj.leDomains = obj.parent.config.letsencrypt.names;
|
||||||
|
obj.leDomains.sort(); // Sort the array so it's always going to be in the same order.
|
||||||
|
}
|
||||||
|
|
||||||
// The domains being approved for the first time are listed in opts.domains
|
obj.le.check({ domains: obj.leDomains }).then(function (results) {
|
||||||
// Certs being renewed are listed in certs.altnames
|
if (results) {
|
||||||
if (certs) {
|
obj.leResults = results;
|
||||||
opts.domains = ['example.com', 'yourdomain.com']
|
|
||||||
|
// If we already have real certificates, use them.
|
||||||
|
if (results.altnames.indexOf(certs.CommonName) >= 0) { certs.web.cert = results.cert; certs.web.key = results.privkey; certs.web.ca = [results.chain]; }
|
||||||
|
for (var i in obj.parent.config.domains) { if ((obj.parent.config.domains[i].dns != null) && (results.altnames.indexOf(obj.parent.config.domains[i].dns) >= 0)) { certs.dns[i].cert = results.cert; certs.dns[i].key = results.privkey; certs.dns[i].ca = [results.chain]; } }
|
||||||
|
func(certs);
|
||||||
|
|
||||||
|
// Check if the Let's Encrypt certificate needs to be renewed.
|
||||||
|
setTimeout(obj.checkRenewCertificate, 300000); // Check in 5 minutes.
|
||||||
|
setInterval(obj.checkRenewCertificate, 86400000); // Check again in 24 hours and every 24 hours.
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
opts.email = 'john.doe@example.com';
|
// Otherwise return default certificates and try to get a real one
|
||||||
opts.agreeTos = true;
|
func(certs);
|
||||||
|
}
|
||||||
|
console.log("Attempting to get Let's Encrypt certificate, may take a few minutes...");
|
||||||
|
|
||||||
|
// Figure out the RSA key size
|
||||||
|
var rsaKeySize = (obj.parent.config.letsencrypt.rsakeysize === 2048) ? 2048 : 3072;
|
||||||
|
|
||||||
|
// TODO: Only register on one of the peers if multi-peers are active.
|
||||||
|
// Register Certificate manually
|
||||||
|
obj.le.register({
|
||||||
|
domains: obj.leDomains,
|
||||||
|
email: obj.parent.config.letsencrypt.email,
|
||||||
|
agreeTos: true,
|
||||||
|
rsaKeySize: rsaKeySize,
|
||||||
|
challengeType: 'http-01'
|
||||||
|
}).then(function (xresults) {
|
||||||
|
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
|
||||||
|
}, function (err) {
|
||||||
|
console.error("ERROR: Let's encrypt error: ", err);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: you can also change other options such as `challengeType` and `challenge`
|
// Check if we need to renew the certificate, call this every day.
|
||||||
// opts.challengeType = 'http-01';
|
obj.checkRenewCertificate = function () {
|
||||||
// opts.challenge = require('le-challenge-fs').create({});
|
if (obj.leResults == null) { return; }
|
||||||
|
// TODO: Only renew on one of the peers if multi-peers are active.
|
||||||
func(null, { options: opts, certs: certs });
|
// Check if we need to renew the certificate
|
||||||
|
obj.le.renew({ duplicate: false }, obj.leResults).then(function (xresults) {
|
||||||
|
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
|
||||||
|
}, function (err) { }); // If we can't renew, ignore.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles acme-challenge and redirects to https
|
} catch (e) { console.error(e); return null; } // Unable to start Let's Encrypt
|
||||||
require('http').createServer(obj.lex.middleware(require('redirect-https')())).listen(81, function () { console.log("Listening for ACME http-01 challenges on", this.address()); });
|
|
||||||
|
|
||||||
var app = require('express')();
|
|
||||||
app.use('/', function (req, res) { res.end('Hello, World!'); });
|
|
||||||
|
|
||||||
// Handles your app
|
|
||||||
require('https').createServer(obj.lex.httpsOptions, obj.lex.middleware(app)).listen(443, function () { console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address()); });
|
|
||||||
|
|
||||||
console.log('CreateLetsEncrypt-3');
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@ function CreateMeshCentralServer() {
|
||||||
obj.amtEventHandler;
|
obj.amtEventHandler;
|
||||||
obj.amtScanner;
|
obj.amtScanner;
|
||||||
obj.meshScanner;
|
obj.meshScanner;
|
||||||
|
obj.letsencrypt;
|
||||||
obj.eventsDispatch = {};
|
obj.eventsDispatch = {};
|
||||||
obj.fs = require('fs');
|
obj.fs = require('fs');
|
||||||
obj.path = require('path');
|
obj.path = require('path');
|
||||||
|
@ -163,8 +164,11 @@ function CreateMeshCentralServer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } else if (data.indexOf('Starting self upgrade...') >= 0) { xprocess.xrestart = 3; } console.log(data); });
|
xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Updating server certificates...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } else if (data.indexOf('Starting self upgrade...') >= 0) { xprocess.xrestart = 3; } console.log(data); });
|
||||||
xprocess.stderr.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync(obj.path.join(obj.datapath, 'mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n'); });
|
xprocess.stderr.on('data', function (data) {
|
||||||
|
if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock
|
||||||
|
if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync(obj.path.join(obj.datapath, 'mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n');
|
||||||
|
});
|
||||||
xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } });
|
xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +190,9 @@ function CreateMeshCentralServer() {
|
||||||
// Initiate server self-update
|
// Initiate server self-update
|
||||||
obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); }
|
obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); }
|
||||||
|
|
||||||
|
// Initiate server self-update
|
||||||
|
obj.performServerCertUpdate = function () { console.log('Updating server certificates...'); process.exit(200); }
|
||||||
|
|
||||||
obj.StartEx = function () {
|
obj.StartEx = function () {
|
||||||
// Look to see if data and/or file path is specified
|
// Look to see if data and/or file path is specified
|
||||||
if (obj.args.datapath) { obj.datapath = obj.args.datapath; }
|
if (obj.args.datapath) { obj.datapath = obj.args.datapath; }
|
||||||
|
@ -310,9 +317,38 @@ function CreateMeshCentralServer() {
|
||||||
obj.updateMeshCore();
|
obj.updateMeshCore();
|
||||||
obj.updateMeshCmd();
|
obj.updateMeshCmd();
|
||||||
|
|
||||||
|
// Setup and start the redirection server if needed
|
||||||
|
if ((obj.args.redirport != null) && (typeof obj.args.redirport == 'number') && (obj.args.redirport != 0)) {
|
||||||
|
obj.redirserver = require('./redirserver.js').CreateRedirServer(obj, obj.db, obj.args, obj.StartEx2);
|
||||||
|
} else {
|
||||||
|
obj.StartEx2(); // If not needed, move on.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done starting the redirection server, go on to load the server certificates
|
||||||
|
obj.StartEx2 = function () {
|
||||||
// Load server certificates
|
// Load server certificates
|
||||||
obj.certificateOperations = require('./certoperations.js').CertificateOperations()
|
obj.certificateOperations = require('./certoperations.js').CertificateOperations()
|
||||||
obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, obj.config, function (certs) {
|
obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, obj.config, function (certs) {
|
||||||
|
if (obj.config.letsencrypt == null) {
|
||||||
|
obj.StartEx3(certs); // Just use the configured certificates
|
||||||
|
} else {
|
||||||
|
var le = require('./letsencrypt.js');
|
||||||
|
obj.letsencrypt = le.CreateLetsEncrypt(obj);
|
||||||
|
if (obj.letsencrypt != null) {
|
||||||
|
obj.letsencrypt.getCertificate(certs, obj.StartEx3); // Use Let's Encrypt certificate
|
||||||
|
} else {
|
||||||
|
console.log('ERROR: Unable to setup GreenLock module.');
|
||||||
|
obj.StartEx3(certs); // Let's Encrypt did not load, just use the configured certificates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the server with the given certificates
|
||||||
|
obj.StartEx3 = function (certs) {
|
||||||
obj.certificates = certs;
|
obj.certificates = certs;
|
||||||
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
||||||
|
|
||||||
|
@ -350,11 +386,7 @@ function CreateMeshCentralServer() {
|
||||||
// If the secret is not specified, generate a random number.
|
// If the secret is not specified, generate a random number.
|
||||||
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, buf.toString('hex').toUpperCase(), obj.certificates);
|
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, buf.toString('hex').toUpperCase(), obj.certificates);
|
||||||
}
|
}
|
||||||
|
if (obj.redirserver != null) { obj.redirserver.hookMainWebServer(obj.certificates); }
|
||||||
// Setup and start the redirection server if needed
|
|
||||||
if ((obj.args.redirport != null) && (typeof obj.args.redirport == 'number') && (obj.args.redirport != 0)) {
|
|
||||||
obj.redirserver = require('./redirserver.js').CreateRedirServer(obj, obj.db, obj.args, obj.certificates);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the Intel AMT event handler
|
// Setup the Intel AMT event handler
|
||||||
obj.amtEventHandler = require('./amtevents.js').CreateAmtEventsHandler(obj);
|
obj.amtEventHandler = require('./amtevents.js').CreateAmtEventsHandler(obj);
|
||||||
|
@ -403,9 +435,6 @@ function CreateMeshCentralServer() {
|
||||||
obj.debug(1, 'Server started');
|
obj.debug(1, 'Server started');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform maintenance operations (called every hour)
|
// Perform maintenance operations (called every hour)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.1.2-h",
|
"version": "0.1.2-s",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
@ -48,7 +48,11 @@
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"node-sspi": "^0.2.2",
|
"node-sspi": "^0.2.2",
|
||||||
"node-windows": "^0.1.14",
|
"node-windows": "^0.1.14",
|
||||||
"mongojs": "^2.4.0"
|
"mongojs": "^2.4.0",
|
||||||
|
"greenlock": "^2.1.18",
|
||||||
|
"le-store-certbot": "^2.0.5",
|
||||||
|
"le-challenge-fs": "^2.0.8",
|
||||||
|
"le-acme-core": "^2.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"readme": "readme.txt"
|
"readme": "readme.txt"
|
||||||
|
|
|
@ -1693,6 +1693,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function deskAdjust() {
|
function deskAdjust() {
|
||||||
|
console.log('deskAdjust');
|
||||||
var x = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('Desk').clientHeight + Q('deskarea4').clientHeight + 2)) / 2;
|
var x = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('Desk').clientHeight + Q('deskarea4').clientHeight + 2)) / 2;
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
document.documentElement.style.overflow = 'hidden';
|
document.documentElement.style.overflow = 'hidden';
|
||||||
|
|
|
@ -29,6 +29,8 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.rotation = 0;
|
obj.rotation = 0;
|
||||||
obj.protocol = 2; // KVM
|
obj.protocol = 2; // KVM
|
||||||
obj.debugmode = 0;
|
obj.debugmode = 0;
|
||||||
|
obj.firstUpKeys = [];
|
||||||
|
obj.stopInput = false;
|
||||||
|
|
||||||
obj.sessionid = 0;
|
obj.sessionid = 0;
|
||||||
obj.username;
|
obj.username;
|
||||||
|
@ -43,7 +45,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.width = 960;
|
obj.width = 960;
|
||||||
obj.height = 960;
|
obj.height = 960;
|
||||||
|
|
||||||
obj.onScreenResize = null;
|
obj.onScreenSizeChange = null;
|
||||||
obj.onMessage = null;
|
obj.onMessage = null;
|
||||||
obj.onConnectCountChanged = null;
|
obj.onConnectCountChanged = null;
|
||||||
obj.onDebugMessage = null;
|
obj.onDebugMessage = null;
|
||||||
|
@ -59,7 +61,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.UnGrabKeyInput();
|
obj.UnGrabKeyInput();
|
||||||
obj.UnGrabMouseInput();
|
obj.UnGrabMouseInput();
|
||||||
obj.touchenabled = 0;
|
obj.touchenabled = 0;
|
||||||
if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||||||
obj.Canvas.clearRect(0, 0, obj.CanvasId.width, obj.CanvasId.height);
|
obj.Canvas.clearRect(0, 0, obj.CanvasId.width, obj.CanvasId.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +166,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); }
|
while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); }
|
||||||
obj.SendCompressionLevel(1);
|
obj.SendCompressionLevel(1);
|
||||||
obj.SendUnPause();
|
obj.SendUnPause();
|
||||||
|
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId); }
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.ProcessData = function (str) {
|
obj.ProcessData = function (str) {
|
||||||
|
@ -201,6 +204,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.SendKeyMsgKC(obj.KeyAction.UP, 18); // Alt
|
obj.SendKeyMsgKC(obj.KeyAction.UP, 18); // Alt
|
||||||
obj.SendKeyMsgKC(obj.KeyAction.UP, 91); // Left-Windows
|
obj.SendKeyMsgKC(obj.KeyAction.UP, 91); // Left-Windows
|
||||||
obj.SendKeyMsgKC(obj.KeyAction.UP, 92); // Right-Windows
|
obj.SendKeyMsgKC(obj.KeyAction.UP, 92); // Right-Windows
|
||||||
|
obj.SendKeyMsgKC(obj.KeyAction.UP, 16); // Shift
|
||||||
obj.Send(String.fromCharCode(0x00, 0x0E, 0x00, 0x04));
|
obj.Send(String.fromCharCode(0x00, 0x0E, 0x00, 0x04));
|
||||||
break;
|
break;
|
||||||
case 11: // GetDisplays
|
case 11: // GetDisplays
|
||||||
|
@ -334,7 +338,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.GetDisplayNumbers = function () { obj.Send(String.fromCharCode(0x00, 0x0B, 0x00, 0x04)); } // Get Terminal display
|
obj.GetDisplayNumbers = function () { obj.Send(String.fromCharCode(0x00, 0x0B, 0x00, 0x04)); } // Get Terminal display
|
||||||
obj.SetDisplay = function (number) { console.log('SetDisplay', number); obj.Send(String.fromCharCode(0x00, 0x0C, 0x00, 0x06, number >> 8, number & 0xFF)); } // Set Terminal display
|
obj.SetDisplay = function (number) { obj.Send(String.fromCharCode(0x00, 0x0C, 0x00, 0x06, number >> 8, number & 0xFF)); } // Set Terminal display
|
||||||
obj.intToStr = function (x) { return String.fromCharCode((x >> 24) & 0xFF, (x >> 16) & 0xFF, (x >> 8) & 0xFF, x & 0xFF); }
|
obj.intToStr = function (x) { return String.fromCharCode((x >> 24) & 0xFF, (x >> 16) & 0xFF, (x >> 8) & 0xFF, x & 0xFF); }
|
||||||
obj.shortToStr = function (x) { return String.fromCharCode((x >> 8) & 0xFF, x & 0xFF); }
|
obj.shortToStr = function (x) { return String.fromCharCode((x >> 8) & 0xFF, x & 0xFF); }
|
||||||
|
|
||||||
|
@ -345,7 +349,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.Canvas.canvas.width = obj.ScreenWidth;
|
obj.Canvas.canvas.width = obj.ScreenWidth;
|
||||||
obj.Canvas.canvas.height = obj.ScreenHeight;
|
obj.Canvas.canvas.height = obj.ScreenHeight;
|
||||||
obj.Canvas.fillRect(0, 0, obj.ScreenWidth, obj.ScreenHeight);
|
obj.Canvas.fillRect(0, 0, obj.ScreenWidth, obj.ScreenHeight);
|
||||||
if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||||||
}
|
}
|
||||||
obj.FirstDraw = false;
|
obj.FirstDraw = false;
|
||||||
//obj.Debug("onResize: " + obj.ScreenWidth + " x " + obj.ScreenHeight);
|
//obj.Debug("onResize: " + obj.ScreenWidth + " x " + obj.ScreenHeight);
|
||||||
|
@ -363,15 +367,21 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
obj.xxKeyPress = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
obj.xxKeyPress = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
|
||||||
// Key handlers
|
// Key handlers
|
||||||
obj.handleKeys = function (e) { return obj.xxKeyPress(e); }
|
obj.handleKeys = function (e) { if (obj.stopInput == true || desktop.State != 3) return false; return obj.xxKeyPress(e); }
|
||||||
obj.handleKeyUp = function (e) { return obj.xxKeyUp(e); }
|
obj.handleKeyUp = function (e) {
|
||||||
obj.handleKeyDown = function (e) { return obj.xxKeyDown(e); }
|
if (obj.stopInput == true || desktop.State != 3) return false;
|
||||||
|
if (obj.firstUpKeys.length < 5) {
|
||||||
|
obj.firstUpKeys.push(e.keyCode);
|
||||||
|
if ((obj.firstUpKeys.length == 5)) { var j = obj.firstUpKeys.join(','); if ((j == '16,17,91,91,16') || (j == '16,17,18,91,92')) { obj.stopInput = true; } }
|
||||||
|
} return obj.xxKeyUp(e);
|
||||||
|
}
|
||||||
|
obj.handleKeyDown = function (e) { if (obj.stopInput == true || desktop.State != 3) return false; return obj.xxKeyDown(e); }
|
||||||
|
|
||||||
// Mouse handlers
|
// Mouse handlers
|
||||||
obj.mousedown = function (e) { return obj.xxMouseDown(e); }
|
obj.mousedown = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseDown(e); }
|
||||||
obj.mouseup = function (e) { return obj.xxMouseUp(e); }
|
obj.mouseup = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseUp(e); }
|
||||||
obj.mousemove = function (e) { return obj.xxMouseMove(e); }
|
obj.mousemove = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseMove(e); }
|
||||||
obj.mousewheel = function (e) { return obj.xxMouseWheel(e); }
|
obj.mousewheel = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseWheel(e); }
|
||||||
|
|
||||||
obj.xxMsTouchEvent = function (evt) {
|
obj.xxMsTouchEvent = function (evt) {
|
||||||
if (evt.originalEvent.pointerType == 4) return; // If this is a mouse pointer, ignore this event. Touch & pen are ok.
|
if (evt.originalEvent.pointerType == 4) return; // If this is a mouse pointer, ignore this event. Touch & pen are ok.
|
||||||
|
@ -573,7 +583,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
|
|
||||||
obj.ScreenWidth = obj.Canvas.canvas.width;
|
obj.ScreenWidth = obj.Canvas.canvas.width;
|
||||||
obj.ScreenHeight = obj.Canvas.canvas.height;
|
obj.ScreenHeight = obj.Canvas.canvas.height;
|
||||||
if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,25 @@
|
||||||
// https://github.com/expressjs/express/blob/master/examples/auth/index.js
|
// https://github.com/expressjs/express/blob/master/examples/auth/index.js
|
||||||
|
|
||||||
// Construct a HTTP redirection web server object
|
// Construct a HTTP redirection web server object
|
||||||
module.exports.CreateRedirServer = function (parent, db, args, certificates) {
|
module.exports.CreateRedirServer = function (parent, db, args, func) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.db = db;
|
obj.db = db;
|
||||||
obj.args = args;
|
obj.args = args;
|
||||||
obj.certificates = certificates;
|
obj.certificates = null;
|
||||||
obj.express = require('express');
|
obj.express = require('express');
|
||||||
obj.net = require('net');
|
obj.net = require('net');
|
||||||
obj.app = obj.express();
|
obj.app = obj.express();
|
||||||
obj.tcpServer;
|
obj.tcpServer;
|
||||||
|
obj.port = null;
|
||||||
|
|
||||||
// Perform an HTTP to HTTPS redirection
|
// Perform an HTTP to HTTPS redirection
|
||||||
function performRedirection(req, res) {
|
function performRedirection(req, res) {
|
||||||
var host = certificates.CommonName;
|
var host = req.headers.host;
|
||||||
if ((certificates.CommonName == 'sample.org') || (certificates.CommonName == 'un-configured')) { host = req.headers.host; }
|
if (obj.certificates != null) {
|
||||||
|
host = obj.certificates.CommonName;
|
||||||
|
if ((obj.certificates.CommonName == 'sample.org') || (obj.certificates.CommonName == 'un-configured')) { host = req.headers.host; }
|
||||||
|
}
|
||||||
if (req.headers && req.headers.host && (req.headers.host.split(':')[0].toLowerCase() == 'localhost')) { res.redirect('https://localhost:' + args.port + req.url); } else { res.redirect('https://' + host + ':' + args.port + req.url); }
|
if (req.headers && req.headers.host && (req.headers.host.split(':')[0].toLowerCase() == 'localhost')) { res.redirect('https://localhost:' + args.port + req.url); } else { res.redirect('https://' + host + ':' + args.port + req.url); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,17 +58,25 @@ module.exports.CreateRedirServer = function (parent, db, args, certificates) {
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup all HTTP redirection handlers
|
// Once the main web server is started, call this to hookup additional handlers
|
||||||
//obj.app.set('etag', false);
|
obj.hookMainWebServer = function (certs) {
|
||||||
|
obj.certificates = certs;
|
||||||
for (var i in parent.config.domains) {
|
for (var i in parent.config.domains) {
|
||||||
|
if (parent.config.domains[i].dns != null) { continue; }
|
||||||
var url = parent.config.domains[i].url;
|
var url = parent.config.domains[i].url;
|
||||||
obj.app.get(url, performRedirection);
|
|
||||||
obj.app.post(url + 'amtevents.ashx', obj.parent.webserver.handleAmtEventRequest);
|
obj.app.post(url + 'amtevents.ashx', obj.parent.webserver.handleAmtEventRequest);
|
||||||
obj.app.get(url + 'meshsettings', obj.parent.webserver.handleMeshSettingsRequest);
|
obj.app.get(url + 'meshsettings', obj.parent.webserver.handleMeshSettingsRequest);
|
||||||
obj.app.get(url + 'meshagents', obj.parent.webserver.handleMeshAgentRequest);
|
obj.app.get(url + 'meshagents', obj.parent.webserver.handleMeshAgentRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Indicates the clickonce folder is public
|
// Setup all HTTP redirection handlers
|
||||||
obj.app.use(url + 'clickonce', obj.express.static(obj.parent.path.join(__dirname, 'public/clickonce')));
|
//obj.app.set('etag', false);
|
||||||
|
for (var i in parent.config.domains) {
|
||||||
|
if (parent.config.domains[i].dns != null) { continue; }
|
||||||
|
var url = parent.config.domains[i].url;
|
||||||
|
obj.app.get(url, performRedirection);
|
||||||
|
obj.app.use(url + 'clickonce', obj.express.static(obj.parent.path.join(__dirname, 'public/clickonce'))); // Indicates the clickonce folder is public
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a free port starting with the specified one and going up.
|
// Find a free port starting with the specified one and going up.
|
||||||
|
@ -79,8 +91,13 @@ module.exports.CreateRedirServer = function (parent, db, args, certificates) {
|
||||||
// Start the ExpressJS web server, if the port is busy try the next one.
|
// Start the ExpressJS web server, if the port is busy try the next one.
|
||||||
function StartRedirServer(port) {
|
function StartRedirServer(port) {
|
||||||
if (port == 0 || port == 65535) return;
|
if (port == 0 || port == 65535) return;
|
||||||
obj.args.redirport = port;
|
obj.tcpServer = obj.app.listen(port, function () {
|
||||||
obj.tcpServer = obj.app.listen(port, function () { console.log('MeshCentral HTTP redirection web server running on port ' + port + '.'); }).on('error', function (err) { if ((err.code == 'EACCES') && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); } });
|
obj.port = port;
|
||||||
|
console.log('MeshCentral HTTP redirection web server running on port ' + port + '.');
|
||||||
|
func(obj.port);
|
||||||
|
}).on('error', function (err) {
|
||||||
|
if ((err.code == 'EACCES') && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); func(obj.port); }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckListenPort(args.redirport, StartRedirServer);
|
CheckListenPort(args.redirport, StartRedirServer);
|
||||||
|
|
|
@ -1242,7 +1242,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function ondockeypress(e) {
|
function ondockeypress(e) {
|
||||||
if (!xxdialogMode && xxcurrentView == 11 && desktop && desktop.State == 3) return desktop.m.handleKeys(e);
|
if (!xxdialogMode && xxcurrentView == 11 && desktop) return desktop.m.handleKeys(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeys(e);
|
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeys(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 15) return agentConsoleHandleKeys(e);
|
if (!xxdialogMode && xxcurrentView == 15) return agentConsoleHandleKeys(e);
|
||||||
if (xxdialogMode || xxcurrentView != 1) return;
|
if (xxdialogMode || xxcurrentView != 1) return;
|
||||||
|
@ -1278,7 +1278,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function ondockeydown(e) {
|
function ondockeydown(e) {
|
||||||
if (!xxdialogMode && xxcurrentView == 11 && desktop && desktop.State == 3) return desktop.m.handleKeyDown(e);
|
if (!xxdialogMode && xxcurrentView == 11 && desktop) return desktop.m.handleKeyDown(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyDown(e);
|
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyDown(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
|
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
|
||||||
if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||||||
|
@ -1295,7 +1295,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function ondockeyup(e) {
|
function ondockeyup(e) {
|
||||||
if (!xxdialogMode && xxcurrentView == 11 && desktop && desktop.State == 3) return desktop.m.handleKeyUp(e);
|
if (!xxdialogMode && xxcurrentView == 11 && desktop) return desktop.m.handleKeyUp(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
|
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
|
||||||
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
|
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
|
||||||
if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
|
if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
|
||||||
|
@ -2939,6 +2939,7 @@
|
||||||
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
|
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
|
||||||
desktop.m.ScalingLevel = desktopsettings.scaling;
|
desktop.m.ScalingLevel = desktopsettings.scaling;
|
||||||
desktop.m.onDisplayinfo = deskDisplayInfo;
|
desktop.m.onDisplayinfo = deskDisplayInfo;
|
||||||
|
desktop.m.onScreenSizeChange = deskAdjust;
|
||||||
desktop.Start(desktopNode._id);
|
desktop.Start(desktopNode._id);
|
||||||
desktop.contype = 1;
|
desktop.contype = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
var dnscount = 0;
|
var dnscount = 0;
|
||||||
obj.tlsSniCredentials = {};
|
obj.tlsSniCredentials = {};
|
||||||
for (var i in obj.certificates.dns) { if (obj.parent.config.domains[i].dns != null) { obj.dnsDomains[obj.parent.config.domains[i].dns.toLowerCase()] = obj.parent.config.domains[i]; obj.tlsSniCredentials[obj.parent.config.domains[i].dns] = obj.tls.createSecureContext(obj.certificates.dns[i]).context; dnscount++; } }
|
for (var i in obj.certificates.dns) { if (obj.parent.config.domains[i].dns != null) { obj.dnsDomains[obj.parent.config.domains[i].dns.toLowerCase()] = obj.parent.config.domains[i]; obj.tlsSniCredentials[obj.parent.config.domains[i].dns] = obj.tls.createSecureContext(obj.certificates.dns[i]).context; dnscount++; } }
|
||||||
if (dnscount > 0) { obj.tlsSniCredentials[''] = obj.tls.createSecureContext({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.ca }).context; } else { obj.tlsSniCredentials = null; }
|
if (dnscount > 0) { obj.tlsSniCredentials[''] = obj.tls.createSecureContext({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca }).context; } else { obj.tlsSniCredentials = null; }
|
||||||
}
|
}
|
||||||
function TlsSniCallback(name, cb) { var c = obj.tlsSniCredentials[name]; if (c != null) { cb(null, c); } else { cb(null, obj.tlsSniCredentials['']); } }
|
function TlsSniCallback(name, cb) { var c = obj.tlsSniCredentials[name]; if (c != null) { cb(null, c); } else { cb(null, obj.tlsSniCredentials['']); } }
|
||||||
|
|
||||||
|
@ -143,10 +143,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// Setup the HTTP server with TLS
|
// Setup the HTTP server with TLS
|
||||||
if (obj.tlsSniCredentials != null) {
|
if (obj.tlsSniCredentials != null) {
|
||||||
// We have multiple web server certificate used depending on the domain name
|
// We have multiple web server certificate used depending on the domain name
|
||||||
obj.tlsServer = require('https').createServer({ SNICallback: TlsSniCallback, cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.ca, rejectUnauthorized: true }, obj.app);
|
obj.tlsServer = require('https').createServer({ SNICallback: TlsSniCallback, cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true }, obj.app);
|
||||||
} else {
|
} else {
|
||||||
// We have a single web server certificate
|
// We have a single web server certificate
|
||||||
obj.tlsServer = require('https').createServer({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.ca, rejectUnauthorized: true }, obj.app);
|
obj.tlsServer = require('https').createServer({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true }, obj.app);
|
||||||
}
|
}
|
||||||
obj.expressWs = require('express-ws')(obj.app, obj.tlsServer);
|
obj.expressWs = require('express-ws')(obj.app, obj.tlsServer);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue