From 64bef74317a1cb90971065a55db6cc59856c0056 Mon Sep 17 00:00:00 2001 From: Stuart Wyatt Date: Thu, 11 Jan 2024 17:49:12 -0800 Subject: [PATCH] Align and specify NPM module versions (#5685) The Dockerfile specifies NPM modules to be installed. However, some do not specify a version, so the latest is installed. Later in meshcentral.js mainStart() specific versions are required. If they don't match the latest version, all modules will be reinstalled to get the specific versions. #5684 Soft version conflict on NPM modules causes NPM modules to be installed on startup in Docker #5545 Docker on Debian 11 fails on version 1.1.15 and 1.1.16 giving NPM errors #5681 InstallModules() installs all modules, not just missing modules (regression) --- docker/Dockerfile | 5 +++-- mcrec.js | 2 +- meshcentral.js | 7 ++++--- translate/translate.js | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index aa1721c6..fc3a9864 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -86,8 +86,9 @@ COPY ./docker/config.json.template /opt/meshcentral/config.json.template # install dependencies from package.json and nedb RUN cd meshcentral && npm install && npm install nedb -RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.13.0; fi -RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2 saslprep semver nodemailer image-size wildleek@2.0.0 otplib@10.2.3 yubikeyotp; fi +# NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN meshcentral.js mainStart() +RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.13.0 saslprep@1.0.3; fi +RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2@1.15.0 semver@7.5.4 nodemailer@6.9.8 image-size@1.0.2 wildleek@2.0.0 otplib@10.2.3 yubikeyotp@0.2.0; fi EXPOSE 80 443 4433 diff --git a/mcrec.js b/mcrec.js index 43a78433..4e10d8d4 100644 --- a/mcrec.js +++ b/mcrec.js @@ -304,7 +304,7 @@ function InstallModule(modulename, func, tag1, tag2) { 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, '../..'); } // Looks like we need to keep a global reference to the child process object for this to work correctly. - InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) { + InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 300000, cwd: parentpath }, function (error, stdout, stderr) { InstallModuleChildProcess = null; if ((error != null) && (error != '')) { log('ERROR: Unable to install required module "' + modulename + '". May not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n'); diff --git a/meshcentral.js b/meshcentral.js index 018e60eb..c183cf72 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -3877,7 +3877,7 @@ function InstallModuleEx(modulenames, args, func) { if (args.debug) { console.log('NPM Command Line: ' + npmpath + ` install --no-audit --no-package-lock --omit=optional --no-save --no-fund ${names}`); } - 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) { + child_process.exec(npmpath + ` install --no-audit --no-package-lock --no-optional --omit=optional --no-save ${names}`, { maxBuffer: 512000, timeout: 300000, cwd: parentpath }, function (error, stdout, stderr) { if ((error != null) && (error != '')) { var mcpath = __dirname; if (mcpath.endsWith('\\node_modules\\meshcentral') || mcpath.endsWith('/node_modules/meshcentral')) { mcpath = require('path').join(mcpath, '..', '..'); } @@ -4016,10 +4016,11 @@ function mainStart() { } // Build the list of required modules + // NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN Dockerfile 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.37','ws@8.14.2','yauzl@2.10.0']; 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 if (ldap == true) { modules.push('ldapauth-fork@5.0.5'); } - if (ssh == true) { modules.push('ssh2@1.14.0'); } + if (ssh == true) { modules.push('ssh2@1.15.0'); } if (passport != null) { modules.push(...passport); } if (captcha == true) { modules.push('svg-captcha@1.4.0'); } @@ -4037,7 +4038,7 @@ function mainStart() { if (config.settings.plugins != null) { modules.push('semver@7.5.4'); } // Required for version compat testing and update checks if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent@7.0.2'); } // Required for HTTP/HTTPS proxy support else if (config.settings.xmongodb != null) { modules.push('mongojs@3.1.0'); } // Add MongoJS, old driver. - if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer@6.9.6'); } // Add SMTP support + if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer@6.9.8'); } // Add SMTP support if (sendgrid || (config.sendgrid != null)) { modules.push('@sendgrid/mail'); } // Add SendGrid support if ((args.translate || args.dev) && (Number(process.version.match(/^v(\d+\.\d+)/)[1]) >= 16)) { modules.push('jsdom@22.1.0'); modules.push('esprima@4.0.1'); modules.push('minify-js@0.0.4'); modules.push('html-minifier@4.0.0'); } // Translation support 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) diff --git a/translate/translate.js b/translate/translate.js index b22ebc2f..a250492a 100644 --- a/translate/translate.js +++ b/translate/translate.js @@ -1108,7 +1108,7 @@ function InstallModuleEx(modulenames, func) { 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, '../..'); } // Looks like we need to keep a global reference to the child process object for this to work correctly. - InstallModuleChildProcess = child_process.exec(`npm install --no-audit --no-package-lock --no-optional --omit=optional --no-save ${names}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) { + InstallModuleChildProcess = child_process.exec(`npm install --no-audit --no-package-lock --no-optional --omit=optional --no-save ${names}`, { maxBuffer: 512000, timeout: 300000, cwd: parentpath }, function (error, stdout, stderr) { InstallModuleChildProcess = null; if ((error != null) && (error != '')) { log('ERROR: Unable to install required modules. May not have access to npm, or npm may not have suffisent rights to load the new modules. Try "npm install ' + names + '" to manualy install the modules.\r\n');