Improve the way dynamic dependencies work

Properly verify the version without using hacks. Allows mc to ensure exact versions are installed. Also added otplib as a normal dependency.

TotallyNotElite committed Jan 25, 2020 at 16:58 UTC 7a775be4c0a090bd9f410dcc3c2a32d036c09c98
2 files changed +16 -9
meshcentral.js
+15 -8
@@ -2168,20 +2168,27 @@ function getConfig(createSampleConfig) {
2168 function InstallModules(modules, func) {
2169 var missingModules = [];
2170 if (modules.length > 0) {
2171 + var dependencies = require("./package.json").dependencies;
2172 for (var i in modules) {
2173 // Modules may contain a version tag (foobar@1.0.0), remove it so the module can be found using require
2173 - var moduleName = modules[i].split("@", 1)[0];
2174 + var moduleInfo = modules[i].split("@", 2);
2175 + var moduleName = moduleInfo[0];
2176 + var moduleVersion = moduleInfo[1];
2177 try {
2175 - if (moduleName == 'greenlock') {
2176 - // Check if we have GreenLock v3
2177 - delete require.cache[require.resolve('greenlock')]; // Clear the require cache
2178 - if (typeof require('greenlock').challengeType == 'string') { missingModules.push(modules[i]); }
2179 - } else {
2178 + // Does the module need a specific version?
2179 + if (moduleVersion) {
2180 + if (require(`${moduleName}/package.json`).version != moduleVersion)
2181 + throw new Error();
2182 + }
2183 + else {
2184 // For all other modules, do the check here.
2185 + // Is the module in package.json? Install exact version.
2186 + if (typeof dependencies[moduleName] != undefined)
2187 + moduleVersion = dependencies[moduleName];
2188 require(moduleName);
2189 }
2190 } catch (e) {
2184 - if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(modules[i]); }
2191 + if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(`${moduleName}${moduleVersion ? `@${moduleVersion}` : ""}`); }
2192 }
2193 }
2194 if (missingModules.length > 0) { InstallModule(missingModules.shift(), InstallModules, modules, func); } else { func(); }
@@ -2197,7 +2204,7 @@ function InstallModule(modulename, func, tag1, tag2) {
2204 // Get the working directory
2205 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, '../..'); }
2206
2200 - child_process.exec(`npm install --no-optional ${modulename}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
2207 + child_process.exec(`npm install --no-save --no-optional ${modulename}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
2208 if ((error != null) && (error != '')) {
2209 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. Try "npm install ' + modulename + '" to manualy install this module.\r\n');
2210 process.exit();
package.json
+1 -1
@@ -38,11 +38,11 @@
38 "express-handlebars": "^3.1.0",
39 "express-ws": "^4.0.0",
40 "ipcheck": "^0.1.0",
41 - "meshcentral": "*",
41 "minimist": "^1.2.0",
42 "multiparty": "^4.2.1",
43 "nedb": "^1.8.0",
44 "node-forge": "^0.8.4",
45 + "otplib": "^12.0.1",
46 "ws": "^6.2.1",
47 "xmldom": "^0.1.27",
48 "yauzl": "^2.10.0"