Major changes to the way NPM is used to install modules, should fix meshcentral updateing incorrectly and other module issues.
Ylian Saint-Hilaire committed
Oct 20, 2023 at 23:36 UTC
cdde9b5d676c70f27408ecd1e401db19359d01f3
1 file changed
+52
-45
meshcentral.js
+52
-45
@@ -3830,8 +3830,8 @@ function getConfig(createSampleConfig) {
3830
}
3831
3832
// Check if a list of modules are present and install any missing ones
3833
-function InstallModules(modules, func) {
3834
- const missingModules = [];
3833
+function InstallModules(modules, args, func) {
3834
+ var missingModules = [];
3835
if (modules.length > 0) {
3836
const dependencies = require('./package.json').dependencies;
3837
for (var i in modules) {
@@ -3852,32 +3852,39 @@ function InstallModules(modules, func) {
3852
require(moduleName);
3853
}
3854
} catch (ex) {
3855
- if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(moduleNameAndVersion); }
3855
+ missingModules.push(moduleNameAndVersion);
3856
}
3857
}
3858
- if (missingModules.length > 0) { InstallModule(missingModules.shift(), InstallModules, modules, func); } else { func(); }
3858
+
3859
+ if (missingModules.length > 0) { if (args.debug) { console.log('Missing Modules: ' + missingModules.join(', ')); } InstallModuleEx(modules, args, func); } else { func(); }
3860
}
3861
}
3862
3862
-// Check if a module is present and install it if missing
3863
-function InstallModule(modulename, func, tag1, tag2) {
3864
- console.log('Installing ' + modulename + '...');
3863
+// Install all missing modules at once. We will be running "npm install" once, with a full list of all modules we need, no matter if they area already installed or not,
3864
+// this is to make sure NPM gives us exactly what we need. Also, we install the meshcentral with current version, so that NPM does not update it - which it will do if obmitted.
3865
+function InstallModuleEx(modulenames, args, func) {
3866
+ var names = modulenames.join(' ');
3867
+ console.log('Installing modules...');
3868
const child_process = require('child_process');
3869
var parentpath = __dirname;
3870
+ function getCurrentVersion() { try { return JSON.parse(require('fs').readFileSync(require('path').join(__dirname, 'package.json'), 'utf8')).version; } catch (ex) { } return null; } // Fetch server version
3871
+ const meshCentralVersion = getCurrentVersion();
3872
+ if (meshCentralVersion != null) { names = 'meshcentral@' + getCurrentVersion() + ' ' + names; }
3873
3874
// Get the working directory
3875
if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); }
3876
3871
- child_process.exec(npmpath + ` install --no-audit --no-package-lock --no-optional --save-exact ${modulename}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
3877
+ if (args.debug) { console.log('NPM Command Line: ' + npmpath + ` install --no-audit --no-package-lock --omit=optional --no-save --no-fund ${names}`); }
3878
+
3879
+ child_process.exec(npmpath + ` install --no-audit --no-package-lock --no-optional --omit=optional --no-save ${names}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
3880
if ((error != null) && (error != '')) {
3881
var mcpath = __dirname;
3882
if (mcpath.endsWith('\\node_modules\\meshcentral') || mcpath.endsWith('/node_modules/meshcentral')) { mcpath = require('path').join(mcpath, '..', '..'); }
3875
- console.log('ERROR: Unable to install required module "' + modulename + '". MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. To manualy install this module try:\r\n\r\n cd "' + mcpath + '"\r\n npm install ' + modulename + '\r\n node node_modules' + ((require('os').platform() == 'win32') ? '\\' : '/') + 'meshcentral');
3883
+ console.log('ERROR: Unable to install required modules. MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. To manualy install this module try:\r\n\r\n cd "' + mcpath + '"\r\n npm install ' + names + '\r\n node node_modules' + ((require('os').platform() == 'win32') ? '\\' : '/') + 'meshcentral');
3884
process.exit();
3885
return;
3886
}
3879
- previouslyInstalledModules[modulename] = true;
3880
- func(tag1, tag2);
3887
+ func();
3888
return;
3889
});
3890
}
@@ -3933,7 +3940,7 @@ function mainStart() {
3940
if (__dirname.endsWith('\\node_modules\\meshcentral') || __dirname.endsWith('/node_modules/meshcentral')) { process.chdir(require('path').join(__dirname, '..', '..')); }
3941
3942
// Check for any missing modules.
3936
- InstallModules(['minimist'], function () {
3943
+ InstallModules(['minimist'], {}, function () {
3944
// Parse inbound arguments
3945
const args = require('minimist')(process.argv.slice(2));
3946
@@ -4009,36 +4016,36 @@ function mainStart() {
4016
4017
// Build the list of required modules
4018
var modules = ['archiver@5.3.2','body-parser@1.20.2','cbor@5.2.0','compression@1.7.4','cookie-session@2.0.0','express@4.18.2','express-handlebars@5.3.5','express-ws@4.0.0','ipcheck@0.1.0','minimist@1.2.8','multiparty@4.2.3','@yetzt/nedb','node-forge@1.3.1','ua-parser-js@1.0.36','ws@8.14.2','yauzl@2.10.0'];
4012
- if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.14'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
4013
- if (ldap == true) { modules.push('ldapauth-fork'); }
4014
- if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2'); } }
4019
+ if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.14'); modules.push('loadavg-windows@1.1.1'); if (sspi == true) { modules.push('node-sspi@0.2.10'); } } // Add Windows modules
4020
+ if (ldap == true) { modules.push('ldapauth-fork@5.0.5'); }
4021
+ if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2@1.14.0'); } }
4022
if (passport != null) { modules.push(...passport); }
4016
- if (captcha == true) { modules.push('svg-captcha'); }
4023
+ if (captcha == true) { modules.push('svg-captcha@1.4.0'); }
4024
4018
- if (sessionRecording == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
4025
+ if (sessionRecording == true) { modules.push('image-size@1.0.2'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
4026
if (config.letsencrypt != null) { modules.push('acme-client@4.2.5'); } // Add acme-client module. We need to force v4.2.4 or higher since olver versions using SHA-1 which is no longer supported by Let's Encrypt.
4027
if (config.settings.mqtt != null) { modules.push('aedes@0.39.0'); } // Add MQTT Modules
4021
- if (config.settings.mysql != null) { modules.push('mysql2'); } // Add MySQL.
4022
- //if (config.settings.mysql != null) { modules.push('@mysql/xdevapi'); } // Add MySQL, official driver (https://dev.mysql.com/doc/dev/connector-nodejs/8.0/)
4023
- if (config.settings.mongodb != null) { modules.push('mongodb@4.13.0'); modules.push('saslprep'); } // Add MongoDB, official driver.
4028
+ if (config.settings.mysql != null) { modules.push('mysql2@3.6.2'); } // Add MySQL.
4029
+ //if (config.settings.mysql != null) { modules.push('@mysql/xdevapi@8.0.33'); } // Add MySQL, official driver (https://dev.mysql.com/doc/dev/connector-nodejs/8.0/)
4030
+ if (config.settings.mongodb != null) { modules.push('mongodb@4.13.0'); modules.push('saslprep@1.0.3'); } // Add MongoDB, official driver.
4031
if (config.settings.postgres != null) { modules.push('pg@8.7.1'); modules.push('pgtools@0.3.2'); } // Add Postgres, Postgres driver.
4025
- if (config.settings.mariadb != null) { modules.push('mariadb'); } // Add MariaDB, official driver.
4026
- if (config.settings.acebase != null) { modules.push('acebase'); } // Add AceBase, official driver.
4027
- if (config.settings.sqlite3 != null) { modules.push('sqlite3'); } // Add sqlite3, official driver.
4028
- if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
4029
- if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
4030
- if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
4031
- else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
4032
- if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer'); } // Add SMTP support
4032
+ if (config.settings.mariadb != null) { modules.push('mariadb@3.2.2'); } // Add MariaDB, official driver.
4033
+ if (config.settings.acebase != null) { modules.push('acebase@1.29.5'); } // Add AceBase, official driver.
4034
+ if (config.settings.sqlite3 != null) { modules.push('sqlite3@5.1.6'); } // Add sqlite3, official driver.
4035
+ if (config.settings.vault != null) { modules.push('node-vault@0.10.2'); } // Add official HashiCorp's Vault module.
4036
+ if (config.settings.plugins != null) { modules.push('semver@7.5.4'); } // Required for version compat testing and update checks
4037
+ if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent@7.0.2'); } // Required for HTTP/HTTPS proxy support
4038
+ else if (config.settings.xmongodb != null) { modules.push('mongojs@3.1.0'); } // Add MongoJS, old driver.
4039
+ if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer@6.9.6'); } // Add SMTP support
4040
if (sendgrid || (config.sendgrid != null)) { modules.push('@sendgrid/mail'); } // Add SendGrid support
4041
if (args.translate) { modules.push('jsdom'); modules.push('esprima'); modules.push('minify-js'); modules.push('html-minifier'); } // Translation support
4035
- if (typeof config.settings.crowdsec == 'object') { modules.push('@crowdsec/express-bouncer'); } // Add CrowdSec bounser module (https://www.npmjs.com/package/@crowdsec/express-bouncer)
4042
+ if (typeof config.settings.crowdsec == 'object') { modules.push('@crowdsec/express-bouncer@0.1.0'); } // Add CrowdSec bounser module (https://www.npmjs.com/package/@crowdsec/express-bouncer)
4043
4044
if (typeof config.settings.autobackup == 'object') {
4045
// Setup encrypted zip support if needed
4039
- if (config.settings.autobackup.zippassword) { modules.push('archiver-zip-encrypted'); }
4046
+ if (config.settings.autobackup.zippassword) { modules.push('archiver-zip-encrypted@1.0.11'); }
4047
// Enable Google Drive Support
4041
- if (typeof config.settings.autobackup.googledrive == 'object') { modules.push('googleapis'); }
4048
+ if (typeof config.settings.autobackup.googledrive == 'object') { modules.push('googleapis@128.0.0'); }
4049
// Enable WebDAV Support
4050
if (typeof config.settings.autobackup.webdav == 'object') {
4051
if ((typeof config.settings.autobackup.webdav.url != 'string') || (typeof config.settings.autobackup.webdav.username != 'string') || (typeof config.settings.autobackup.webdav.password != 'string')) { addServerWarning("Missing WebDAV parameters.", 2, null, !args.launch); } else { modules.push('webdav@4.11.3'); }
@@ -4051,46 +4058,46 @@ function mainStart() {
4058
// Setup 2nd factor authentication
4059
if (config.settings.no2factorauth !== true) {
4060
// Setup YubiKey OTP if configured
4054
- if (yubikey == true) { modules.push('yubikeyotp'); } // Add YubiKey OTP support
4061
+ if (yubikey == true) { modules.push('yubikeyotp@0.2.0'); } // Add YubiKey OTP support
4062
if (allsspi == false) { modules.push('otplib@10.2.3'); } // Google Authenticator support (v10 supports older NodeJS versions).
4063
}
4064
4065
// Desktop multiplexor support
4059
- if (config.settings.desktopmultiplex === true) { modules.push('image-size'); }
4066
+ if (config.settings.desktopmultiplex === true) { modules.push('image-size@1.0.2'); }
4067
4068
// SMS support
4069
if (config.sms != null) {
4063
- if (config.sms.provider == 'twilio') { modules.push('twilio'); }
4064
- if (config.sms.provider == 'plivo') { modules.push('plivo'); }
4065
- if (config.sms.provider == 'telnyx') { modules.push('telnyx'); }
4070
+ if (config.sms.provider == 'twilio') { modules.push('twilio@4.19.0'); }
4071
+ if (config.sms.provider == 'plivo') { modules.push('plivo@4.58.0'); }
4072
+ if (config.sms.provider == 'telnyx') { modules.push('telnyx@1.25.5'); }
4073
}
4074
4075
// Messaging support
4076
if (config.messaging != null) {
4070
- if (config.messaging.telegram != null) { modules.push('telegram'); modules.push('input'); }
4077
+ if (config.messaging.telegram != null) { modules.push('telegram@2.19.8'); modules.push('input@1.0.1'); }
4078
if (config.messaging.discord != null) { if (nodeVersion >= 17) { modules.push('discord.js@14.6.0'); } else { delete config.messaging.discord; addServerWarning('This NodeJS version does not support Discord.js.', 26); } }
4072
- if (config.messaging.xmpp != null) { modules.push('@xmpp/client'); }
4073
- if (config.messaging.pushover != null) { modules.push('node-pushover'); }
4074
- if (config.messaging.zulip != null) { modules.push('zulip'); }
4079
+ if (config.messaging.xmpp != null) { modules.push('@xmpp/client@0.13.1'); }
4080
+ if (config.messaging.pushover != null) { modules.push('node-pushover@1.0.0'); }
4081
+ if (config.messaging.zulip != null) { modules.push('zulip@0.1.0'); }
4082
}
4083
4084
// Setup web based push notifications
4078
- if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) { modules.push('web-push'); }
4085
+ if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) { modules.push('web-push@3.6.6'); }
4086
4087
// Firebase Support
4088
// Avoid 0.1.8 due to bugs: https://github.com/guness/node-xcs/issues/43
4089
if (config.firebase != null) { modules.push('node-xcs@0.1.7'); }
4090
4091
// Syslog support
4085
- if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); }
4086
- if (config.settings.syslogtcp) { modules.push('syslog'); }
4092
+ if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog@1.2.0'); }
4093
+ if (config.settings.syslogtcp) { modules.push('syslog@0.1.1-1'); }
4094
4095
// Setup heapdump support if needed, useful for memory leak debugging
4096
// https://www.arbazsiddiqui.me/a-practical-guide-to-memory-leaks-in-nodejs/
4090
- if (config.settings.heapdump === true) { modules.push('heapdump'); }
4097
+ if (config.settings.heapdump === true) { modules.push('heapdump@0.3.15'); }
4098
4099
// Install any missing modules and launch the server
4093
- InstallModules(modules, function () {
4100
+ InstallModules(modules, args, function () {
4101
if (require('os').platform() == 'win32') { try { require('node-windows'); } catch (ex) { console.log("Module node-windows can't be loaded. Restart MeshCentral."); process.exit(); return; } }
4102
meshserver = CreateMeshCentralServer(config, args);
4103
meshserver.Start();