mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Plugin system improvements.
This commit is contained in:
parent
54bc30e092
commit
75d49db30b
@ -170,6 +170,7 @@
|
|||||||
<Content Include="CreateSourcePackage.bat" />
|
<Content Include="CreateSourcePackage.bat" />
|
||||||
<Content Include="LICENSE" />
|
<Content Include="LICENSE" />
|
||||||
<Content Include="package.json" />
|
<Content Include="package.json" />
|
||||||
|
<Content Include="plugin_development.md" />
|
||||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" />
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" />
|
||||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" />
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" />
|
||||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" />
|
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" />
|
||||||
|
@ -1102,8 +1102,7 @@ function createMeshCore(agent) {
|
|||||||
if (fs.existsSync("/usr/bin/python") && fs.existsSync("/bin/bash")) {
|
if (fs.existsSync("/usr/bin/python") && fs.existsSync("/bin/bash")) {
|
||||||
this.httprequest.process = childProcess.execFile("/usr/bin/python", [ "python", "-c", "import pty; pty.spawn([\"/bin/bash\"])" ]);
|
this.httprequest.process = childProcess.execFile("/usr/bin/python", [ "python", "-c", "import pty; pty.spawn([\"/bin/bash\"])" ]);
|
||||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("export TERM='xterm'\nalias ls='ls --color=auto'\nclear\n"); }
|
if (process.platform == 'linux') { this.httprequest.process.stdin.write("export TERM='xterm'\nalias ls='ls --color=auto'\nclear\n"); }
|
||||||
}
|
} else if (fs.existsSync("/bin/bash")) {
|
||||||
else if (fs.existsSync("/bin/bash")) {
|
|
||||||
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
||||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
||||||
} else {
|
} else {
|
||||||
|
3
agents/meshcore.min.js
vendored
3
agents/meshcore.min.js
vendored
@ -1102,8 +1102,7 @@ function createMeshCore(agent) {
|
|||||||
if (fs.existsSync("/usr/bin/python") && fs.existsSync("/bin/bash")) {
|
if (fs.existsSync("/usr/bin/python") && fs.existsSync("/bin/bash")) {
|
||||||
this.httprequest.process = childProcess.execFile("/usr/bin/python", [ "python", "-c", "import pty; pty.spawn([\"/bin/bash\"])" ]);
|
this.httprequest.process = childProcess.execFile("/usr/bin/python", [ "python", "-c", "import pty; pty.spawn([\"/bin/bash\"])" ]);
|
||||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("export TERM='xterm'\nalias ls='ls --color=auto'\nclear\n"); }
|
if (process.platform == 'linux') { this.httprequest.process.stdin.write("export TERM='xterm'\nalias ls='ls --color=auto'\nclear\n"); }
|
||||||
}
|
} else if (fs.existsSync("/bin/bash")) {
|
||||||
else if (fs.existsSync("/bin/bash")) {
|
|
||||||
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
||||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
||||||
} else {
|
} else {
|
||||||
|
64
db.js
64
db.js
@ -442,9 +442,9 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup plugin info collection
|
// Setup plugin info collection
|
||||||
obj.pluginsfile = db.collection('plugins');
|
if (parent.config.settings != null) { obj.pluginsfile = db.collection('plugins'); }
|
||||||
|
|
||||||
setupFunctions(func); // Completed setup of MongoDB
|
setupFunctions(func); // Completed setup of MongoDB
|
||||||
});
|
});
|
||||||
@ -548,7 +548,7 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup plugin info collection
|
// Setup plugin info collection
|
||||||
obj.pluginsfile = db.collection('plugins');
|
if (parent.config.settings != null) { obj.pluginsfile = db.collection('plugins'); }
|
||||||
|
|
||||||
setupFunctions(func); // Completed setup of MongoJS
|
setupFunctions(func); // Completed setup of MongoJS
|
||||||
} else {
|
} else {
|
||||||
@ -611,8 +611,10 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
obj.serverstatsfile.ensureIndex({ fieldName: 'expire', expireAfterSeconds: 0 }); // Auto-expire events
|
obj.serverstatsfile.ensureIndex({ fieldName: 'expire', expireAfterSeconds: 0 }); // Auto-expire events
|
||||||
|
|
||||||
// Setup plugin info collection
|
// Setup plugin info collection
|
||||||
obj.pluginsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-plugins.db'), autoload: true });
|
if (parent.config.settings != null) {
|
||||||
obj.pluginsfile.persistence.setAutocompactionInterval(36000);
|
obj.pluginsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-plugins.db'), autoload: true });
|
||||||
|
obj.pluginsfile.persistence.setAutocompactionInterval(36000);
|
||||||
|
}
|
||||||
|
|
||||||
setupFunctions(func); // Completed setup of NeDB
|
setupFunctions(func); // Completed setup of NeDB
|
||||||
}
|
}
|
||||||
@ -764,22 +766,16 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
func(r);
|
func(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a plugin
|
// Plugin operations
|
||||||
obj.addPlugin = function (plugin, func) { plugin.type = "plugin"; obj.pluginsfile.insertOne(plugin, func); };
|
if (parent.config.settings.plugins != null) {
|
||||||
|
obj.addPlugin = function (plugin, func) { plugin.type = "plugin"; obj.pluginsfile.insertOne(plugin, func); }; // Add a plugin
|
||||||
// Get all plugins
|
obj.getPlugins = function (func) { obj.pluginsfile.find({ "type": "plugin" }).project({ "type": 0 }).sort({ name: 1 }).toArray(func); }; // Get all plugins
|
||||||
obj.getPlugins = function (func) { obj.pluginsfile.find({"type": "plugin"}).project({"type": 0}).sort({ name: 1 }).toArray(func); };
|
obj.getPlugin = function (id, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.find({ _id: id }).sort({ name: 1 }).toArray(func); }; // Get plugin
|
||||||
|
obj.deletePlugin = function (id, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.deleteOne({ _id: id }, func); }; // Delete plugin
|
||||||
// Get plugin
|
obj.setPluginStatus = function (id, status, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: { status: status } }, func); };
|
||||||
obj.getPlugin = function (id, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.find({ _id: id }).sort({ name: 1 }).toArray(func); };
|
obj.updatePlugin = function (id, args, func) { delete args._id; id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: args }, func); };
|
||||||
|
}
|
||||||
// Delete plugin
|
|
||||||
obj.deletePlugin = function (id, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.deleteOne({ _id: id }, func); };
|
|
||||||
|
|
||||||
obj.setPluginStatus = function(id, status, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: {status: status } }, func); };
|
|
||||||
|
|
||||||
obj.updatePlugin = function(id, args, func) { delete args._id; id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: args }, func); };
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Database actions on the main collection (NeDB and MongoJS)
|
// Database actions on the main collection (NeDB and MongoJS)
|
||||||
@ -911,22 +907,16 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
func(r);
|
func(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a plugin
|
// Plugin operations
|
||||||
obj.addPlugin = function (plugin, func) { plugin.type = "plugin"; obj.pluginsfile.insert(plugin, func); };
|
if (parent.config.settings.plugins != null) {
|
||||||
|
obj.addPlugin = function (plugin, func) { plugin.type = "plugin"; obj.pluginsfile.insert(plugin, func); }; // Add a plugin
|
||||||
// Get all plugins
|
obj.getPlugins = function (func) { obj.pluginsfile.find({ "type": "plugin" }, { "type": 0 }).sort({ name: 1 }).exec(func); }; // Get all plugins
|
||||||
obj.getPlugins = function (func) { obj.pluginsfile.find({"type": "plugin"}, {"type": 0}).sort({ name: 1 }).exec(func); };
|
obj.getPlugin = function (id, func) { obj.pluginsfile.find({ _id: id }).sort({ name: 1 }).exec(func); }; // Get plugin
|
||||||
|
obj.deletePlugin = function (id, func) { obj.pluginsfile.remove({ _id: id }, func); }; // Delete plugin
|
||||||
// Get plugin
|
obj.setPluginStatus = function (id, status, func) { obj.pluginsfile.update({ _id: id }, { $set: { status: status } }, func); };
|
||||||
obj.getPlugin = function (id, func) { obj.pluginsfile.find({ _id: id }).sort({ name: 1 }).exec(func); };
|
obj.updatePlugin = function (id, args, func) { delete args._id; obj.pluginsfile.update({ _id: id }, { $set: args }, func); };
|
||||||
|
}
|
||||||
// Delete plugin
|
|
||||||
obj.deletePlugin = function (id, func) { obj.pluginsfile.remove({ _id: id }, func); };
|
|
||||||
|
|
||||||
obj.setPluginStatus = function(id, status, func) { obj.pluginsfile.update({ _id: id }, { $set: {status: status } }, func); };
|
|
||||||
|
|
||||||
obj.updatePlugin = function(id, args, func) { delete args._id; obj.pluginsfile.update({ _id: id }, { $set: args }, func); };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,7 +840,13 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
|
|
||||||
// Start plugin manager if configuration allows this.
|
// Start plugin manager if configuration allows this.
|
||||||
if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null)) {
|
if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null)) {
|
||||||
obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
|
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
|
if (nodeVersion < 7) {
|
||||||
|
console.log("WARNING: Plugin support requires Node 7 or higher.");
|
||||||
|
delete obj.config.settings.plugins;
|
||||||
|
} else {
|
||||||
|
obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the default meshcore and meshcmd
|
// Load the default meshcore and meshcmd
|
||||||
@ -2073,6 +2079,7 @@ function mainStart() {
|
|||||||
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
|
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
|
||||||
if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
|
if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
|
||||||
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
|
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
|
||||||
|
if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
|
||||||
else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
|
else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
|
||||||
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
|
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
|
||||||
|
|
||||||
|
@ -3138,6 +3138,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'distributeCore': {
|
case 'distributeCore': {
|
||||||
|
// This is only available when plugins are enabled since it could cause stress on the server
|
||||||
|
if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin with plugins enabled
|
||||||
for (var i in command.nodes) {
|
for (var i in command.nodes) {
|
||||||
parent.sendMeshAgentCore(user, domain, command.nodes[i]._id, 'default');
|
parent.sendMeshAgentCore(user, domain, command.nodes[i]._id, 'default');
|
||||||
}
|
}
|
||||||
@ -3170,7 +3172,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
if (typeof err == 'object') err = err.message;
|
if (typeof err == 'object') err = err.message;
|
||||||
try { ws.send(JSON.stringify({ action: 'pluginError', msg: err })); } catch (er) { }
|
try { ws.send(JSON.stringify({ action: 'pluginError', msg: err })); } catch (er) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch(e) { console.log('Cannot add plugin: ' + e); }
|
} catch(e) { console.log('Cannot add plugin: ' + e); }
|
||||||
|
375
pluginHandler.js
375
pluginHandler.js
@ -25,27 +25,27 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
obj.plugins = {};
|
obj.plugins = {};
|
||||||
obj.exports = {};
|
obj.exports = {};
|
||||||
obj.loadList = obj.parent.config.settings.plugins.list; // For local development / manual install, not from DB
|
obj.loadList = obj.parent.config.settings.plugins.list; // For local development / manual install, not from DB
|
||||||
|
|
||||||
if (typeof obj.loadList != 'object') {
|
if (typeof obj.loadList != 'object') {
|
||||||
obj.loadList = {};
|
obj.loadList = {};
|
||||||
parent.db.getPlugins(function(err, plugins){
|
parent.db.getPlugins(function (err, plugins) {
|
||||||
plugins.forEach(function(plugin){
|
plugins.forEach(function (plugin) {
|
||||||
if (plugin.status != 1) return;
|
if (plugin.status != 1) return;
|
||||||
if (obj.fs.existsSync(obj.pluginPath + '/' + plugin.shortName)) {
|
if (obj.fs.existsSync(obj.pluginPath + '/' + plugin.shortName)) {
|
||||||
try {
|
try {
|
||||||
obj.plugins[plugin.shortName] = require(obj.pluginPath + '/' + plugin.shortName + '/' + plugin.shortName + '.js')[plugin.shortName](obj);
|
obj.plugins[plugin.shortName] = require(obj.pluginPath + '/' + plugin.shortName + '/' + plugin.shortName + '.js')[plugin.shortName](obj);
|
||||||
obj.exports[plugin.shortName] = obj.plugins[plugin.shortName].exports;
|
obj.exports[plugin.shortName] = obj.plugins[plugin.shortName].exports;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error loading plugin: " + plugin.shortName + " (" + e + "). It has been disabled.", e.stack);
|
console.log("Error loading plugin: " + plugin.shortName + " (" + e + "). It has been disabled.", e.stack);
|
||||||
}
|
}
|
||||||
try { // try loading local info about plugin to database (if it changed locally)
|
try { // try loading local info about plugin to database (if it changed locally)
|
||||||
var plugin_config = obj.fs.readFileSync(obj.pluginPath + '/' + plugin.shortName + '/config.json');
|
var plugin_config = obj.fs.readFileSync(obj.pluginPath + '/' + plugin.shortName + '/config.json');
|
||||||
plugin_config = JSON.parse(plugin_config);
|
plugin_config = JSON.parse(plugin_config);
|
||||||
parent.db.updatePlugin(plugin._id, plugin_config);
|
parent.db.updatePlugin(plugin._id, plugin_config);
|
||||||
} catch (e) { console.log('Plugin config file for '+ plugin.name +' could not be parsed.'); }
|
} catch (e) { console.log("Plugin config file for " + plugin.name + " could not be parsed."); }
|
||||||
}
|
}
|
||||||
obj.parent.updateMeshCore(); // db calls are delayed, lets inject here once we're ready
|
obj.parent.updateMeshCore(); // db calls are delayed, lets inject here once we're ready
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
obj.loadList.forEach(function (plugin, index) {
|
obj.loadList.forEach(function (plugin, index) {
|
||||||
@ -59,15 +59,15 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.prepExports = function () {
|
obj.prepExports = function () {
|
||||||
var str = 'function() {\r\n';
|
var str = 'function() {\r\n';
|
||||||
str += ' var obj = {};\r\n';
|
str += ' var obj = {};\r\n';
|
||||||
|
|
||||||
for (const p of Object.keys(obj.plugins)) {
|
for (var p of Object.keys(obj.plugins)) {
|
||||||
str += ' obj.' + p + ' = {};\r\n';
|
str += ' obj.' + p + ' = {};\r\n';
|
||||||
if (Array.isArray(obj.exports[p])) {
|
if (Array.isArray(obj.exports[p])) {
|
||||||
for (const l of Object.values(obj.exports[p])) {
|
for (var l of Object.values(obj.exports[p])) {
|
||||||
str += ' obj.' + p + '.' + l + ' = ' + obj.plugins[p][l].toString() + '\r\n';
|
str += ' obj.' + p + '.' + l + ' = ' + obj.plugins[p][l].toString() + '\r\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
meshserver.send({ action: 'addplugin', url: Q('pluginurlinput').value});
|
meshserver.send({ action: 'addplugin', url: Q('pluginurlinput').value});
|
||||||
};
|
};
|
||||||
obj.addPluginDlg = function() {
|
obj.addPluginDlg = function() {
|
||||||
setDialogMode(2, "Plugin Config URL", 3, obj.addPluginEx, '<input type=text id=pluginurlinput style=width:100% />');
|
setDialogMode(2, "Plugin Download URL", 3, obj.addPluginEx, '<p><b>WARNING:</b> Downloading plugins may compromise server security. Only download from trusted sources.</p><input type=text id=pluginurlinput style=width:100% placeholder="https://" />');
|
||||||
focusTextBox('pluginurlinput');
|
focusTextBox('pluginurlinput');
|
||||||
};
|
};
|
||||||
obj.refreshPluginHandler = function() {
|
obj.refreshPluginHandler = function() {
|
||||||
@ -108,20 +108,20 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
return obj; };`;
|
return obj; };`;
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.refreshJS = function(req, res) {
|
obj.refreshJS = function (req, res) {
|
||||||
// to minimize server reboots when installing new plugins, we call the new data and overwrite the old pluginHandler on the front end
|
// to minimize server reboots when installing new plugins, we call the new data and overwrite the old pluginHandler on the front end
|
||||||
res.set('Content-Type', 'text/javascript');
|
res.set('Content-Type', 'text/javascript');
|
||||||
res.send('pluginHandlerBuilder = '+obj.prepExports() + ' pluginHandler = new pluginHandlerBuilder();');
|
res.send('pluginHandlerBuilder = ' + obj.prepExports() + ' pluginHandler = new pluginHandlerBuilder();');
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.callHook = function (hookName, ...args) {
|
obj.callHook = function (hookName, ...args) {
|
||||||
for (var p in obj.plugins) {
|
for (var p in obj.plugins) {
|
||||||
if (typeof obj.plugins[p][hookName] == 'function') {
|
if (typeof obj.plugins[p][hookName] == 'function') {
|
||||||
try {
|
try {
|
||||||
obj.plugins[p][hookName](args);
|
obj.plugins[p][hookName](args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Error ocurred while running plugin hook' + p + ':' + hookName + ' (' + e + ')');
|
console.log("Error ocurred while running plugin hook" + p + ':' + hookName + ' (' + e + ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,20 +187,20 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
panel[p].header = obj.plugins[p].on_device_header();
|
panel[p].header = obj.plugins[p].on_device_header();
|
||||||
panel[p].content = obj.plugins[p].on_device_page();
|
panel[p].content = obj.plugins[p].on_device_page();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Error ocurred while getting plugin views ' + p + ':' + ' (' + e + ')');
|
console.log("Error ocurred while getting plugin views " + p + ':' + ' (' + e + ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return panel;
|
return panel;
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.isValidConfig = function(conf, url) { // check for the required attributes
|
obj.isValidConfig = function (conf, url) { // check for the required attributes
|
||||||
var isValid = true;
|
var isValid = true;
|
||||||
if (!(
|
if (!(
|
||||||
typeof conf.name == 'string'
|
typeof conf.name == 'string'
|
||||||
&& typeof conf.shortName == 'string'
|
&& typeof conf.shortName == 'string'
|
||||||
&& typeof conf.version == 'string'
|
&& typeof conf.version == 'string'
|
||||||
// && typeof conf.author == 'string'
|
// && typeof conf.author == 'string'
|
||||||
&& typeof conf.description == 'string'
|
&& typeof conf.description == 'string'
|
||||||
&& typeof conf.hasAdminPanel == 'boolean'
|
&& typeof conf.hasAdminPanel == 'boolean'
|
||||||
&& typeof conf.homepage == 'string'
|
&& typeof conf.homepage == 'string'
|
||||||
@ -210,7 +210,7 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
&& typeof conf.repository.type == 'string'
|
&& typeof conf.repository.type == 'string'
|
||||||
&& typeof conf.repository.url == 'string'
|
&& typeof conf.repository.url == 'string'
|
||||||
&& typeof conf.meshCentralCompat == 'string'
|
&& typeof conf.meshCentralCompat == 'string'
|
||||||
// && conf.configUrl == url // make sure we're loading a plugin from its desired config
|
// && conf.configUrl == url // make sure we're loading a plugin from its desired config
|
||||||
)) isValid = false;
|
)) isValid = false;
|
||||||
// more checks here?
|
// more checks here?
|
||||||
if (conf.repository.type == 'git') {
|
if (conf.repository.type == 'git') {
|
||||||
@ -218,119 +218,120 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
}
|
}
|
||||||
return isValid;
|
return isValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.getPluginConfig = function(configUrl) {
|
// https://raw.githubusercontent.com/ryanblenis/MeshCentral-Sample/master/config.json
|
||||||
return new Promise(function(resolve, reject) {
|
obj.getPluginConfig = function (configUrl) {
|
||||||
if (configUrl.indexOf('https://') >= 0) {
|
return new Promise(function (resolve, reject) {
|
||||||
var http = require('https');
|
var http = (configUrl.indexOf('https://') >= 0) ? require('https') : require('http');
|
||||||
} else {
|
if (configUrl.indexOf('://') === -1) reject("Unable to fetch the config: Bad URL (" + configUrl + ")");
|
||||||
var http = require('http');
|
var options = require('url').parse(configUrl);
|
||||||
|
if (typeof parent.config.settings.plugins.proxy == 'string') { // Proxy support
|
||||||
|
const HttpsProxyAgent = require('https-proxy-agent');
|
||||||
|
options.agent = new HttpsProxyAgent(require('url').parse(parent.config.settings.plugins.proxy));
|
||||||
}
|
}
|
||||||
if (configUrl.indexOf('://') === -1) reject('Unable to fetch the config: Bad URL (' + configUrl + ')');
|
http.get(options, function (res) {
|
||||||
http.get(configUrl, function(res) {
|
var configStr = '';
|
||||||
var configStr = '';
|
res.on('data', function (chunk) {
|
||||||
res.on('data', function(chunk){
|
configStr += chunk;
|
||||||
configStr += chunk;
|
});
|
||||||
});
|
res.on('end', function () {
|
||||||
res.on('end', function(){
|
if (configStr[0] == '{') { // Let's be sure we're JSON
|
||||||
if (configStr[0] == '{') { // let's be sure we're JSON
|
try {
|
||||||
try {
|
var pluginConfig = JSON.parse(configStr);
|
||||||
var pluginConfig = JSON.parse(configStr);
|
if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0];
|
||||||
if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0];
|
if (obj.isValidConfig(pluginConfig, configUrl)) {
|
||||||
if (obj.isValidConfig(pluginConfig, configUrl)) {
|
resolve(pluginConfig);
|
||||||
resolve(pluginConfig);
|
} else {
|
||||||
} else {
|
reject("This does not appear to be a valid plugin configuration.");
|
||||||
reject("This does not appear to be a valid plugin configuration.");
|
}
|
||||||
}
|
} catch (e) { reject("Error getting plugin config. Check that you have valid JSON."); }
|
||||||
|
} else {
|
||||||
} catch (e) { reject('Error getting plugin config. Check that you have valid JSON.'); }
|
reject("Error getting plugin config. Check that you have valid JSON.");
|
||||||
} else {
|
}
|
||||||
reject('Error getting plugin config. Check that you have valid JSON.');
|
});
|
||||||
}
|
|
||||||
});
|
}).on('error', function (e) {
|
||||||
|
|
||||||
}).on('error', function(e) {
|
|
||||||
reject("Error getting plugin config: " + e.message);
|
reject("Error getting plugin config: " + e.message);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.getPluginLatest = function() {
|
obj.getPluginLatest = function () {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
parent.db.getPlugins(function(err, plugins) {
|
parent.db.getPlugins(function (err, plugins) {
|
||||||
var proms = [];
|
var proms = [];
|
||||||
plugins.forEach(function(curconf) {
|
plugins.forEach(function (curconf) {
|
||||||
proms.push(obj.getPluginConfig(curconf.configUrl).catch(e => { return null; } ));
|
proms.push(obj.getPluginConfig(curconf.configUrl).catch(e => { return null; }));
|
||||||
});
|
});
|
||||||
var latestRet = [];
|
var latestRet = [];
|
||||||
Promise.all(proms).then(function(newconfs) {
|
Promise.all(proms).then(function (newconfs) {
|
||||||
var nconfs = [];
|
var nconfs = [];
|
||||||
// filter out config download issues
|
// Filter out config download issues
|
||||||
newconfs.forEach(function(nc) {
|
newconfs.forEach(function (nc) { if (nc !== null) nconfs.push(nc); });
|
||||||
if (nc !== null) nconfs.push(nc);
|
if (nconfs.length == 0) { resolve([]); } else {
|
||||||
});
|
nconfs.forEach(function (newconf) {
|
||||||
nconfs.forEach(function(newconf) {
|
var curconf = null;
|
||||||
var curconf = null;
|
plugins.forEach(function (conf) {
|
||||||
plugins.forEach(function(conf) {
|
if (conf.configUrl == newconf.configUrl) curconf = conf;
|
||||||
if (conf.configUrl == newconf.configUrl) curconf = conf;
|
});
|
||||||
|
if (curconf == null) reject("Some plugin configs could not be parsed");
|
||||||
|
var s = require('semver');
|
||||||
|
// MeshCentral doesn't adhere to semantic versioning (due to the -<alpha_char> at the end of the version)
|
||||||
|
// Convert the letter to ASCII for a "true" version number comparison
|
||||||
|
var mcCurVer = parent.currentVer.replace(/-(.)$/, (m, p1) => { return p1.charCodeAt(0); });
|
||||||
|
var piCompatVer = newconf.meshCentralCompat.replace(/-(.)\b/g, (m, p1) => { return p1.charCodeAt(0); });
|
||||||
|
latestRet.push({
|
||||||
|
'id': curconf._id,
|
||||||
|
'installedVersion': curconf.version,
|
||||||
|
'version': newconf.version,
|
||||||
|
'hasUpdate': s.gt(newconf.version, curconf.version),
|
||||||
|
'meshCentralCompat': s.satisfies(mcCurVer, piCompatVer),
|
||||||
|
'changelogUrl': curconf.changelogUrl,
|
||||||
|
'status': curconf.status
|
||||||
|
});
|
||||||
|
resolve(latestRet);
|
||||||
});
|
});
|
||||||
if (curconf == null) reject('Some plugin configs could not be parsed');
|
}
|
||||||
var s = require('semver');
|
}).catch((e) => { console.log("Error reaching plugins, update call aborted.", e) });
|
||||||
// MeshCentral doesn't adhere to semantic versioning (due to the -<alpha_char> at the end of the version)
|
|
||||||
// Convert the letter to ASCII for a "true" version number comparison
|
|
||||||
var mcCurVer = parent.currentVer.replace(/-(.)$/, (m, p1) => { return p1.charCodeAt(0); });
|
|
||||||
var piCompatVer = newconf.meshCentralCompat.replace(/-(.)\b/g, (m, p1) => { return p1.charCodeAt(0); });
|
|
||||||
latestRet.push({
|
|
||||||
"id": curconf._id,
|
|
||||||
"installedVersion": curconf.version,
|
|
||||||
"version": newconf.version,
|
|
||||||
"hasUpdate": s.gt(newconf.version, curconf.version),
|
|
||||||
"meshCentralCompat": s.satisfies(mcCurVer, piCompatVer),
|
|
||||||
"changelogUrl": curconf.changelogUrl,
|
|
||||||
"status": curconf.status
|
|
||||||
});
|
|
||||||
resolve(latestRet);
|
|
||||||
});
|
|
||||||
}).catch((e) => { console.log('Error reaching plugins, update call aborted. ', e)});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.addPlugin = function(pluginConfig) {
|
obj.addPlugin = function (pluginConfig) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
parent.db.addPlugin({
|
parent.db.addPlugin({
|
||||||
"name": pluginConfig.name,
|
'name': pluginConfig.name,
|
||||||
"shortName": pluginConfig.shortName,
|
'shortName': pluginConfig.shortName,
|
||||||
"version": pluginConfig.version,
|
'version': pluginConfig.version,
|
||||||
"description": pluginConfig.description,
|
'description': pluginConfig.description,
|
||||||
"hasAdminPanel": pluginConfig.hasAdminPanel,
|
'hasAdminPanel': pluginConfig.hasAdminPanel,
|
||||||
"homepage": pluginConfig.homepage,
|
'homepage': pluginConfig.homepage,
|
||||||
"changelogUrl": pluginConfig.changelogUrl,
|
'changelogUrl': pluginConfig.changelogUrl,
|
||||||
"configUrl": pluginConfig.configUrl,
|
'configUrl': pluginConfig.configUrl,
|
||||||
"downloadUrl": pluginConfig.downloadUrl,
|
'downloadUrl': pluginConfig.downloadUrl,
|
||||||
"repository": {
|
'repository': {
|
||||||
"type": pluginConfig.repository.type,
|
'type': pluginConfig.repository.type,
|
||||||
"url": pluginConfig.repository.url
|
'url': pluginConfig.repository.url
|
||||||
},
|
},
|
||||||
"meshCentralCompat": pluginConfig.meshCentralCompat,
|
'meshCentralCompat': pluginConfig.meshCentralCompat,
|
||||||
"versionHistoryUrl": pluginConfig.versionHistoryUrl,
|
'versionHistoryUrl': pluginConfig.versionHistoryUrl,
|
||||||
"status": 0 // 0: disabled, 1: enabled
|
'status': 0 // 0: disabled, 1: enabled
|
||||||
}, function() {
|
}, function () {
|
||||||
parent.db.getPlugins(function(err, docs){
|
parent.db.getPlugins(function (err, docs) {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
else resolve(docs);
|
else resolve(docs);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.installPlugin = function(id, version_only, force_url, func) {
|
obj.installPlugin = function (id, version_only, force_url, func) {
|
||||||
parent.db.getPlugin(id, function(err, docs){
|
parent.db.getPlugin(id, function (err, docs) {
|
||||||
// the "id" would probably suffice, but is probably an sanitary issue, generate a random instead
|
// the "id" would probably suffice, but is probably an sanitary issue, generate a random instead
|
||||||
var randId = Math.random().toString(32).replace('0.', '');
|
var randId = Math.random().toString(32).replace('0.', '');
|
||||||
var fileName = obj.parent.path.join(require('os').tmpdir(), 'Plugin_'+randId+'.zip');
|
var fileName = obj.parent.path.join(require('os').tmpdir(), 'Plugin_' + randId + '.zip');
|
||||||
var plugin = docs[0];
|
var plugin = docs[0];
|
||||||
if (plugin.repository.type == 'git') {
|
if (plugin.repository.type == 'git') {
|
||||||
const file = obj.fs.createWriteStream(fileName);
|
const file = obj.fs.createWriteStream(fileName);
|
||||||
var dl_url = plugin.downloadUrl;
|
var dl_url = plugin.downloadUrl;
|
||||||
if (version_only != null && version_only != false) dl_url = version_only.url;
|
if (version_only != null && version_only != false) dl_url = version_only.url;
|
||||||
@ -339,7 +340,7 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
var q = url.parse(dl_url, true);
|
var q = url.parse(dl_url, true);
|
||||||
var http = (q.protocol == "http") ? require('http') : require('https');
|
var http = (q.protocol == "http") ? require('http') : require('https');
|
||||||
var opts = {
|
var opts = {
|
||||||
path: q.pathname,
|
path: q.pathname,
|
||||||
host: q.hostname,
|
host: q.hostname,
|
||||||
port: q.port,
|
port: q.port,
|
||||||
headers: {
|
headers: {
|
||||||
@ -348,12 +349,16 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
followRedirects: true,
|
followRedirects: true,
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
};
|
};
|
||||||
var request = http.get(opts, function(response) {
|
if (typeof parent.config.settings.plugins.proxy == 'string') { // Proxy support
|
||||||
|
const HttpsProxyAgent = require('https-proxy-agent');
|
||||||
|
opts.agent = new HttpsProxyAgent(require('url').parse(parent.config.settings.plugins.proxy));
|
||||||
|
}
|
||||||
|
var request = http.get(opts, function (response) {
|
||||||
// handle redirections with grace
|
// handle redirections with grace
|
||||||
if (response.headers.location) return obj.installPlugin(id, version_only, response.headers.location, func);
|
if (response.headers.location) return obj.installPlugin(id, version_only, response.headers.location, func);
|
||||||
response.pipe(file);
|
response.pipe(file);
|
||||||
file.on('finish', function() {
|
file.on('finish', function () {
|
||||||
file.close(function(){
|
file.close(function () {
|
||||||
var yauzl = require("yauzl");
|
var yauzl = require("yauzl");
|
||||||
if (!obj.fs.existsSync(obj.pluginPath)) {
|
if (!obj.fs.existsSync(obj.pluginPath)) {
|
||||||
obj.fs.mkdirSync(obj.pluginPath);
|
obj.fs.mkdirSync(obj.pluginPath);
|
||||||
@ -364,12 +369,12 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
yauzl.open(fileName, { lazyEntries: true }, function (err, zipfile) {
|
yauzl.open(fileName, { lazyEntries: true }, function (err, zipfile) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
zipfile.readEntry();
|
zipfile.readEntry();
|
||||||
zipfile.on("entry", function (entry) {
|
zipfile.on('entry', function (entry) {
|
||||||
let pluginPath = obj.parent.path.join(obj.pluginPath, plugin.shortName);
|
let pluginPath = obj.parent.path.join(obj.pluginPath, plugin.shortName);
|
||||||
let pathReg = new RegExp(/(.*?\/)/);
|
let pathReg = new RegExp(/(.*?\/)/);
|
||||||
if (process.platform == 'win32') pathReg = new RegExp(/(.*?\\/);
|
//if (process.platform == 'win32') { pathReg = new RegExp(/(.*?\\/); }
|
||||||
let filePath = obj.parent.path.join(pluginPath, entry.fileName.replace(pathReg, '')); // remove top level dir
|
let filePath = obj.parent.path.join(pluginPath, entry.fileName.replace(pathReg, '')); // remove top level dir
|
||||||
|
|
||||||
if (/\/$/.test(entry.fileName)) { // dir
|
if (/\/$/.test(entry.fileName)) { // dir
|
||||||
if (!obj.fs.existsSync(filePath))
|
if (!obj.fs.existsSync(filePath))
|
||||||
obj.fs.mkdirSync(filePath);
|
obj.fs.mkdirSync(filePath);
|
||||||
@ -377,50 +382,48 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
} else { // file
|
} else { // file
|
||||||
zipfile.openReadStream(entry, function (err, readStream) {
|
zipfile.openReadStream(entry, function (err, readStream) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
readStream.on("end", function () { zipfile.readEntry(); });
|
readStream.on('end', function () { zipfile.readEntry(); });
|
||||||
readStream.pipe(obj.fs.createWriteStream(filePath));
|
readStream.pipe(obj.fs.createWriteStream(filePath));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
zipfile.on("end", function () { setTimeout(function () {
|
zipfile.on('end', function () {
|
||||||
obj.fs.unlinkSync(fileName);
|
setTimeout(function () {
|
||||||
if (version_only == null || version_only === false) {
|
obj.fs.unlinkSync(fileName);
|
||||||
parent.db.setPluginStatus(id, 1, func);
|
if (version_only == null || version_only === false) {
|
||||||
} else {
|
parent.db.setPluginStatus(id, 1, func);
|
||||||
parent.db.updatePlugin(id, { status: 1, version: version_only.name }, func);
|
} else {
|
||||||
}
|
parent.db.updatePlugin(id, { status: 1, version: version_only.name }, func);
|
||||||
obj.plugins[plugin.shortName] = require(obj.pluginPath + '/' + plugin.shortName + '/' + plugin.shortName + '.js')[plugin.shortName](obj);
|
}
|
||||||
obj.exports[plugin.shortName] = obj.plugins[plugin.shortName].exports;
|
obj.plugins[plugin.shortName] = require(obj.pluginPath + '/' + plugin.shortName + '/' + plugin.shortName + '.js')[plugin.shortName](obj);
|
||||||
if (typeof obj.plugins[plugin.shortName].server_startup == 'function') obj.plugins[plugin.shortName].server_startup();
|
obj.exports[plugin.shortName] = obj.plugins[plugin.shortName].exports;
|
||||||
var plugin_config = obj.fs.readFileSync(obj.pluginPath + '/' + plugin.shortName + '/config.json');
|
if (typeof obj.plugins[plugin.shortName].server_startup == 'function') obj.plugins[plugin.shortName].server_startup();
|
||||||
plugin_config = JSON.parse(plugin_config);
|
var plugin_config = obj.fs.readFileSync(obj.pluginPath + '/' + plugin.shortName + '/config.json');
|
||||||
parent.db.updatePlugin(plugin._id, plugin_config);
|
plugin_config = JSON.parse(plugin_config);
|
||||||
parent.updateMeshCore();
|
parent.db.updatePlugin(plugin._id, plugin_config);
|
||||||
}); });
|
parent.updateMeshCore();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (plugin.repository.type == 'npm') {
|
} else if (plugin.repository.type == 'npm') {
|
||||||
// @TODO npm support? (need a test plugin)
|
// @TODO npm support? (need a test plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.getPluginVersions = function(id) {
|
obj.getPluginVersions = function (id) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
parent.db.getPlugin(id, function(err, docs) {
|
parent.db.getPlugin(id, function (err, docs) {
|
||||||
var plugin = docs[0];
|
var plugin = docs[0];
|
||||||
if (plugin.versionHistoryUrl == null) reject('No version history available for this plugin.');
|
if (plugin.versionHistoryUrl == null) reject("No version history available for this plugin.");
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var q = url.parse(plugin.versionHistoryUrl, true);
|
var q = url.parse(plugin.versionHistoryUrl, true);
|
||||||
var http = (q.protocol == "http") ? require('http') : require('https');
|
var http = (q.protocol == 'http') ? require('http') : require('https');
|
||||||
var opts = {
|
var opts = {
|
||||||
path: q.pathname,
|
path: q.pathname,
|
||||||
host: q.hostname,
|
host: q.hostname,
|
||||||
port: q.port,
|
port: q.port,
|
||||||
headers: {
|
headers: {
|
||||||
@ -428,47 +431,51 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
'Accept': 'application/vnd.github.v3+json'
|
'Accept': 'application/vnd.github.v3+json'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
http.get(opts, function(res) {
|
if (typeof parent.config.settings.plugins.proxy == 'string') { // Proxy support
|
||||||
|
const HttpsProxyAgent = require('https-proxy-agent');
|
||||||
|
options.agent = new HttpsProxyAgent(require('url').parse(parent.config.settings.plugins.proxy));
|
||||||
|
}
|
||||||
|
http.get(opts, function (res) {
|
||||||
var versStr = '';
|
var versStr = '';
|
||||||
res.on('data', function(chunk){
|
res.on('data', function (chunk) {
|
||||||
versStr += chunk;
|
versStr += chunk;
|
||||||
});
|
});
|
||||||
res.on('end', function(){
|
res.on('end', function () {
|
||||||
if (versStr[0] == '{' || versStr[0] == '[') { // let's be sure we're JSON
|
if (versStr[0] == '{' || versStr[0] == '[') { // let's be sure we're JSON
|
||||||
try {
|
try {
|
||||||
var vers = JSON.parse(versStr);
|
var vers = JSON.parse(versStr);
|
||||||
var vList = [];
|
var vList = [];
|
||||||
var s = require('semver');
|
var s = require('semver');
|
||||||
vers.forEach((v) => {
|
vers.forEach((v) => {
|
||||||
if (s.lt(v.name, plugin.version)) vList.push(v);
|
if (s.lt(v.name, plugin.version)) vList.push(v);
|
||||||
});
|
});
|
||||||
if (vers.length == 0) reject('No previous versions available.');
|
if (vers.length == 0) reject("No previous versions available.");
|
||||||
resolve({ 'id': plugin._id, 'name': plugin.name, versionList: vList });
|
resolve({ 'id': plugin._id, 'name': plugin.name, versionList: vList });
|
||||||
} catch (e) { reject('Version history problem.'); }
|
} catch (e) { reject("Version history problem."); }
|
||||||
} else {
|
} else {
|
||||||
reject('Version history appears to be malformed.'+versStr);
|
reject("Version history appears to be malformed." + versStr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).on('error', function(e) {
|
}).on('error', function (e) {
|
||||||
reject("Error getting plugin versions: " + e.message);
|
reject("Error getting plugin versions: " + e.message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.disablePlugin = function(id, func) {
|
obj.disablePlugin = function (id, func) {
|
||||||
parent.db.getPlugin(id, function(err, docs){
|
parent.db.getPlugin(id, function (err, docs) {
|
||||||
var plugin = docs[0];
|
var plugin = docs[0];
|
||||||
parent.db.setPluginStatus(id, 0, func);
|
parent.db.setPluginStatus(id, 0, func);
|
||||||
delete obj.plugins[plugin.shortName];
|
delete obj.plugins[plugin.shortName];
|
||||||
delete obj.exports[plugin.shortName];
|
delete obj.exports[plugin.shortName];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.removePlugin = function(id, func) {
|
obj.removePlugin = function (id, func) {
|
||||||
parent.db.getPlugin(id, function(err, docs){
|
parent.db.getPlugin(id, function (err, docs) {
|
||||||
var plugin = docs[0];
|
var plugin = docs[0];
|
||||||
var rimraf = require("rimraf");
|
var rimraf = require('rimraf');
|
||||||
let pluginPath = obj.parent.path.join(obj.pluginPath, plugin.shortName);
|
let pluginPath = obj.parent.path.join(obj.pluginPath, plugin.shortName);
|
||||||
rimraf.sync(pluginPath);
|
rimraf.sync(pluginPath);
|
||||||
parent.db.deletePlugin(id, func);
|
parent.db.deletePlugin(id, func);
|
||||||
@ -476,25 +483,23 @@ module.exports.pluginHandler = function (parent) {
|
|||||||
obj.parent.updateMeshCore();
|
obj.parent.updateMeshCore();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.handleAdminReq = function (req, res, user, serv) {
|
obj.handleAdminReq = function (req, res, user, serv) {
|
||||||
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
|
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
|
||||||
serv.app.set('views', path);
|
serv.app.set('views', path);
|
||||||
if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') {
|
if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') {
|
||||||
obj.plugins[req.query.pin].handleAdminReq(req, res, user);
|
obj.plugins[req.query.pin].handleAdminReq(req, res, user);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
res.sendStatus(401);
|
res.sendStatus(401);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.handleAdminPostReq = function(req, res, user, serv) {
|
obj.handleAdminPostReq = function (req, res, user, serv) {
|
||||||
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
|
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
|
||||||
serv.app.set('views', path);
|
serv.app.set('views', path);
|
||||||
if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') {
|
if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') {
|
||||||
obj.plugins[req.query.pin].handleAdminPostReq(req, res, user);
|
obj.plugins[req.query.pin].handleAdminPostReq(req, res, user);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
res.sendStatus(401);
|
res.sendStatus(401);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 44 KiB |
BIN
public/images/plugin.png
Normal file
BIN
public/images/plugin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
public/images/plugin24.png
Normal file
BIN
public/images/plugin24.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 656 B |
@ -1295,17 +1295,6 @@ a {
|
|||||||
left: 6px;
|
left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lb7 {
|
|
||||||
background: url(../images/leftbar-64.png) -382px -2px;
|
|
||||||
height: 62px;
|
|
||||||
width: 62px;
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 6px;
|
|
||||||
left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.m0 {
|
.m0 {
|
||||||
background: url(../images/images16.png) -32px 0px;
|
background: url(../images/images16.png) -32px 0px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
@ -1694,6 +1683,10 @@ a {
|
|||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gradTable1 { background-image: linear-gradient(to right, #fff 0%, #d3d9d6 100%); }
|
||||||
|
.gradTable2 { background-color: #d3d9d6; }
|
||||||
|
.gradTable3 { background-image: linear-gradient(to right, #d3d9d6 0%, #fff 100%); }
|
||||||
|
|
||||||
.h1 {
|
.h1 {
|
||||||
background-position: 0% 0%;
|
background-position: 0% 0%;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
@ -2580,45 +2573,47 @@ a {
|
|||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl {
|
.p42tblRow {
|
||||||
|
height: 36px;
|
||||||
|
max-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p42tbl {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: separate;
|
||||||
|
border-spacing:0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl th, #p7tbl td {
|
#p42tbl th, #p7tbl td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 12px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl tr:nth-child(n+2):nth-child(odd) {
|
#p42tbl .chName {
|
||||||
background-color: #cfeeff;
|
|
||||||
}
|
|
||||||
|
|
||||||
#p7tbl .chName {
|
|
||||||
width: 20%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chDescription {
|
#p42tbl .chDescription {
|
||||||
width: 38%;
|
width: 38%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chSite {
|
#p42tbl .chSite {
|
||||||
width: 7%;
|
width: 7%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chVersion {
|
#p42tbl .chVersion {
|
||||||
width: 5%;
|
width: 5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chUpgradeAvail {
|
#p42tbl .chUpgradeAvail {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chStatus {
|
#p42tbl .chStatus {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#p7tbl .chAction {
|
#p42tbl .chAction {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2636,12 +2631,14 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pluginRestartNotice {
|
#pluginRestartNotice {
|
||||||
|
/*
|
||||||
width: 40em;
|
width: 40em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
margin: 50px auto;
|
margin: 50px auto;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.pluginContent {
|
.pluginContent {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -57,9 +57,11 @@
|
|||||||
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
|
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
|
||||||
<div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
|
<div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
<div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||||||
<div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
|
<div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<!-- main page -->
|
<!-- main page -->
|
||||||
<div id=container>
|
<div id=container>
|
||||||
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
||||||
@ -91,9 +93,6 @@
|
|||||||
<div id=LeftMenuMyServer tabindex=0 class="lbbutton" style="display:none" title="My Server" onclick=go(6,event) onkeypress="if (event.key=='Enter') { go(6); }">
|
<div id=LeftMenuMyServer tabindex=0 class="lbbutton" style="display:none" title="My Server" onclick=go(6,event) onkeypress="if (event.key=='Enter') { go(6); }">
|
||||||
<div class="lb6"></div>
|
<div class="lb6"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id=LeftMenuMyPlugins tabindex=0 class="lbbutton" style="display:none" title="My Plugins" onclick=go(7,event) onkeypress="if (event.key=='Enter') { go(7); }">
|
|
||||||
<div class="lb7"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id=topbar class=noselect>
|
<div id=topbar class=noselect>
|
||||||
<div>
|
<div>
|
||||||
@ -115,7 +114,7 @@
|
|||||||
<td tabindex=0 id=MainMenuMyFiles class="topbar_td style3x" onclick=go(5,event) onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
|
<td tabindex=0 id=MainMenuMyFiles class="topbar_td style3x" onclick=go(5,event) onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
|
||||||
<td tabindex=0 id=MainMenuMyUsers class="topbar_td style3x" onclick=go(4,event) onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
|
<td tabindex=0 id=MainMenuMyUsers class="topbar_td style3x" onclick=go(4,event) onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
|
||||||
<td tabindex=0 id=MainMenuMyServer class="topbar_td style3x" onclick=go(6,event) onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
|
<td tabindex=0 id=MainMenuMyServer class="topbar_td style3x" onclick=go(6,event) onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
|
||||||
<td tabindex=0 id=MainMenuMyPlugins class="topbar_td style3x" onclick=go(7,event) onkeypress="if (event.key == 'Enter') go(7)">My Plugins</td>
|
<!-- <td tabindex=0 id=MainMenuMyPlugins class="topbar_td style3x" onclick=go(7,event) onkeypress="if (event.key == 'Enter') go(7)">My Plugins</td> -->
|
||||||
<td class="topbar_td_end style3"> </td>
|
<td class="topbar_td_end style3"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -159,15 +158,20 @@
|
|||||||
<td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40,event) onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
|
<td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40,event) onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
|
||||||
<td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115,event) onkeypress="if (event.key == 'Enter') go(115)">Console</td>
|
<td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115,event) onkeypress="if (event.key == 'Enter') go(115)">Console</td>
|
||||||
<td tabindex=0 id=ServerTrace class="topbar_td style3x" onclick=go(41,event) onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
<td tabindex=0 id=ServerTrace class="topbar_td style3x" onclick=go(41,event) onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
||||||
|
<td tabindex=0 id=ServerPlugins class="topbar_td style3x" onclick=go(42,event) onkeypress="if (event.key == 'Enter') go(42)">Plugins</td>
|
||||||
<td class="topbar_td_end style3"> </td>
|
<td class="topbar_td_end style3"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<div id=PluginSubMenuSpan>
|
<div id=PluginSubMenuSpan>
|
||||||
<table id=PluginSubMenu cellpadding=0 cellspacing=0 class=style1>
|
<table id=PluginSubMenu cellpadding=0 cellspacing=0 class=style1>
|
||||||
<tr><td onclick="goPlugin(-1)" onkeypress="if (event.key == 'Enter') goPlugin(-1)" class="topbar_td style3x">Home</td></tr>
|
<tr>
|
||||||
|
<td onclick="goPlugin(-1)" onkeypress="if (event.key == 'Enter') goPlugin(-1)" class="topbar_td style3x">Home</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<div id=UserDummyMenuSpan>
|
<div id=UserDummyMenuSpan>
|
||||||
<table id=UserDummyMenu cellpadding=0 cellspacing=0 class=style1>
|
<table id=UserDummyMenu cellpadding=0 cellspacing=0 class=style1>
|
||||||
<tr><td class=style3 style=""> </td></tr>
|
<tr><td class=style3 style=""> </td></tr>
|
||||||
@ -417,16 +421,6 @@
|
|||||||
<div id="serverStatsTable"></div>
|
<div id="serverStatsTable"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id=p7 style="display:none">
|
|
||||||
<h1>My Plugins</h1>
|
|
||||||
<div id="addPlugin" title="Add New Plugin" onclick="return pluginHandler.addPluginDlg();"></div>
|
|
||||||
<table id="p7tbl">
|
|
||||||
<tr><th class="chName">Name</th><th class="chDescription">Description</th><th class="chSite">Link</th><th class="chVersion">Version</th><th class="chUpgradeAvail">Latest Available</th><th class="chStatus">Status</th><th class="chAction">Action</th></tr>
|
|
||||||
</table>
|
|
||||||
<div id="pluginRestartNotice" style="display:none;"><div>Notice:</div> MeshCentral plugins have been altered. Agent cores require may require an update before full features are available.<br />
|
|
||||||
Click <a href="#" onclick="distributeCore(); return false;">here</a> to update all Mesh Agent cores.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id=p10 style="display:none">
|
<div id=p10 style="display:none">
|
||||||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||||||
<tr>
|
<tr>
|
||||||
@ -871,6 +865,28 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id=p41events style=""></div>
|
<div id=p41events style=""></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id=p42 style="display:none">
|
||||||
|
<h1>My Server Plugins</h1>
|
||||||
|
<div class="areaHead">
|
||||||
|
<div class="toright2">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input value="Download Plugin" type="button" onclick="return pluginHandler.addPluginDlg();" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pluginRestartNotice" class="areaHead" style="background-color:gold;display:none">
|
||||||
|
<div class="toright2">
|
||||||
|
<input value="Refresh Agent Cores" type="button" onclick="distributeCore();return false" />
|
||||||
|
</div>
|
||||||
|
<div style="padding:2px">
|
||||||
|
<div style="padding:2px"><b>Notice:</b> Plugins have been altered, this may require agent core update.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table id="p42tbl">
|
||||||
|
<tr class="DevSt"><th style="width:26px"></th><th style="width:10px"></th><th class="chName">Name</th><th class="chDescription">Description</th><th class="chSite" style="text-align:center">Link</th><th class="chVersion" style="text-align:center">Version</th><th class="chUpgradeAvail" style="text-align:center">Latest</th><th class="chStatus" style="text-align:center">Status</th><th class="chAction" style="text-align:center">Action</th><th style="width:10px"></th></tr>
|
||||||
|
</table>
|
||||||
|
<div id="pluginNoneNotice" style="width:100%;text-align:center;padding-top:10px;display:none"><i>No plugins on server.</i></div>
|
||||||
|
</div>
|
||||||
<div id=p19 style="display:none">
|
<div id=p19 style="display:none">
|
||||||
<h1>Plugins - <span id=p19deviceName></span></h1>
|
<h1>Plugins - <span id=p19deviceName></span></h1>
|
||||||
<style>
|
<style>
|
||||||
@ -1361,8 +1377,6 @@
|
|||||||
QV('p2ServerActionsVersion', siteRights & 16);
|
QV('p2ServerActionsVersion', siteRights & 16);
|
||||||
QV('MainMenuMyFiles', siteRights & 8);
|
QV('MainMenuMyFiles', siteRights & 8);
|
||||||
QV('LeftMenuMyFiles', siteRights & 8);
|
QV('LeftMenuMyFiles', siteRights & 8);
|
||||||
QV('MainMenuMyPlugins', ((pluginHandler != null) && (siteRights & 0xFFFFFFFF)));
|
|
||||||
QV('LeftMenuMyPlugins', ((pluginHandler != null) && (siteRights & 0xFFFFFFFF)));
|
|
||||||
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
|
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
|
||||||
if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
|
if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
|
||||||
|
|
||||||
@ -2385,15 +2399,13 @@
|
|||||||
}
|
}
|
||||||
case 'downgradePluginVersions': {
|
case 'downgradePluginVersions': {
|
||||||
var vSelect = '<select id="lastPluginVersion">';
|
var vSelect = '<select id="lastPluginVersion">';
|
||||||
message.info.versionList.forEach(function(v){
|
message.info.versionList.forEach(function(v) { vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>'; });
|
||||||
vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>';
|
|
||||||
});
|
|
||||||
vSelect += '</select>';
|
vSelect += '</select>';
|
||||||
setDialogMode(2, 'Plugin Action', 3, pluginActionEx, 'Select the version to downgrade the plugin: ' + message.info.name + '<hr />' + vSelect + '<hr />Please be aware that downgrading is not recommended. Please only do so in the event that a recent upgrade has broken something.<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
|
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format('Select the version to downgrade the plugin: {0}', message.info.name) + '<hr />' + vSelect + '<hr />' + "Please be aware that downgrading is not recommended. Please only do so in the event that a recent upgrade has broken something." + + '<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'pluginError': {
|
case 'pluginError': {
|
||||||
setDialogMode(2, 'Oops!', 1, null, message.msg);
|
setDialogMode(2, "Plugin Error", 1, null, message.msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'plugin': {
|
case 'plugin': {
|
||||||
@ -3543,12 +3555,12 @@
|
|||||||
contextmenudiv.style.left = event.pageX + 'px';
|
contextmenudiv.style.left = event.pageX + 'px';
|
||||||
contextmenudiv.style.top = event.pageY + 'px';
|
contextmenudiv.style.top = event.pageY + 'px';
|
||||||
contextmenudiv.style.display = 'block';
|
contextmenudiv.style.display = 'block';
|
||||||
} else if (elem && elem != null && elem.classList.contains('pluginTab')) {
|
/*} else if (elem && elem != null && elem.classList.contains('pluginTab')) {
|
||||||
contextelement = elem;
|
contextelement = elem;
|
||||||
var contextmenudiv = document.getElementById('pluginTabContextMenu');
|
var contextmenudiv = document.getElementById('pluginTabContextMenu');
|
||||||
contextmenudiv.style.left = event.pageX + 'px';
|
contextmenudiv.style.left = event.pageX + 'px';
|
||||||
contextmenudiv.style.top = event.pageY + 'px';
|
contextmenudiv.style.top = event.pageY + 'px';
|
||||||
contextmenudiv.style.display = 'block';
|
contextmenudiv.style.display = 'block';*/
|
||||||
} else {
|
} else {
|
||||||
while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
|
while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
|
||||||
if (!elem || elem == null) return true;
|
if (!elem || elem == null) return true;
|
||||||
@ -3620,21 +3632,23 @@
|
|||||||
connectTerminal(null, 1, { powershell: (action == 2) });
|
connectTerminal(null, 1, { powershell: (action == 2) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
function pluginTabClose() {
|
function pluginTabClose() {
|
||||||
var pluginTab = contextelement;
|
var pluginTab = contextelement;
|
||||||
var pname = pluginTab.getAttribute('x-data-plugin-sname');
|
var pname = pluginTab.getAttribute('x-data-plugin-sname');
|
||||||
var pdiv = Q('plugin-'+pname);
|
var pdiv = Q('plugin-'+pname);
|
||||||
pdiv.parentNode.removeChild(pdiv);
|
pdiv.parentNode.removeChild(pdiv);
|
||||||
pluginTab.parentNode.removeChild(pluginTab);
|
pluginTab.parentNode.removeChild(pluginTab);
|
||||||
QV('p7', true);
|
QV('p42', true);
|
||||||
goPlugin(-1);
|
goPlugin(-1);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
function hideContextMenu() {
|
function hideContextMenu() {
|
||||||
QV('contextMenu', false);
|
QV('contextMenu', false);
|
||||||
QV('meshContextMenu', false);
|
QV('meshContextMenu', false);
|
||||||
QV('termShellContextMenu', false);
|
QV('termShellContextMenu', false);
|
||||||
QV('pluginTabContextMenu', false);
|
//QV('pluginTabContextMenu', false);
|
||||||
contextelement = null;
|
contextelement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9364,14 +9378,11 @@
|
|||||||
if (xxcurrentView == x) return;
|
if (xxcurrentView == x) return;
|
||||||
|
|
||||||
// Edit this line when adding a new screen
|
// Edit this line when adding a new screen
|
||||||
for (var i = 0; i < 42; i++) { QV('p' + i, i == x); }
|
for (var i = 0; i < 43; i++) { QV('p' + i, i == x); }
|
||||||
xxcurrentView = x;
|
xxcurrentView = x;
|
||||||
|
|
||||||
// Remove top bar selection
|
// Remove top bar selection
|
||||||
var mainBarItems = ['MainMenuMyDevices', 'MainMenuMyAccount', 'MainMenuMyEvents', 'MainMenuMyFiles', 'MainMenuMyUsers', 'MainMenuMyServer'];
|
var mainBarItems = ['MainMenuMyDevices', 'MainMenuMyAccount', 'MainMenuMyEvents', 'MainMenuMyFiles', 'MainMenuMyUsers', 'MainMenuMyServer'];
|
||||||
if (pluginHandler != null) {
|
|
||||||
mainBarItems.push('MainMenuMyPlugins');
|
|
||||||
}
|
|
||||||
for (var i in mainBarItems) {
|
for (var i in mainBarItems) {
|
||||||
QC(mainBarItems[i]).remove('fullselect');
|
QC(mainBarItems[i]).remove('fullselect');
|
||||||
QC(mainBarItems[i]).remove('semiselect');
|
QC(mainBarItems[i]).remove('semiselect');
|
||||||
@ -9379,9 +9390,6 @@
|
|||||||
|
|
||||||
// Remove left bar selection
|
// Remove left bar selection
|
||||||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
||||||
if (pluginHandler != null) {
|
|
||||||
leftBarItems.push('LeftMenuMyPlugins');
|
|
||||||
}
|
|
||||||
for (var i in leftBarItems) {
|
for (var i in leftBarItems) {
|
||||||
QC(leftBarItems[i]).remove('lbbuttonsel');
|
QC(leftBarItems[i]).remove('lbbuttonsel');
|
||||||
QC(leftBarItems[i]).remove('lbbuttonsel2');
|
QC(leftBarItems[i]).remove('lbbuttonsel2');
|
||||||
@ -9389,7 +9397,7 @@
|
|||||||
|
|
||||||
// Define class for Menu(s) as fully or semi active.
|
// Define class for Menu(s) as fully or semi active.
|
||||||
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
||||||
var leftMenuActiveClass = (x < 9 ? 'lbbuttonsel2' : 'lbbuttonsel');
|
var leftMenuActiveClass = (((x < 9) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) ? 'lbbuttonsel2' : 'lbbuttonsel');
|
||||||
|
|
||||||
// My Devices
|
// My Devices
|
||||||
if (x == 1 || (x >= 10 && x < 20)) QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
if (x == 1 || (x >= 10 && x < 20)) QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
||||||
@ -9413,25 +9421,21 @@
|
|||||||
|
|
||||||
// My Server
|
// My Server
|
||||||
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
||||||
if ((x == 6) || (x == 115) || (x == 40)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
if ((x == 6) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||||||
|
|
||||||
// My Plugins
|
|
||||||
if (x == 7) QC('MainMenuMyPlugins').add(mainMenuActiveClass);
|
|
||||||
if (x == 7) QC('LeftMenuMyPlugins').add(leftMenuActiveClass);
|
|
||||||
|
|
||||||
// column_l max-height
|
// column_l max-height
|
||||||
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||||||
|
|
||||||
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
||||||
QV('topbar', x != 0);
|
QV('topbar', x != 0);
|
||||||
if ((x == 0) && (webPageFullScreen)) { QC('body').add("arg_hide"); }
|
if ((x == 0) && (webPageFullScreen)) { QC('body').add('arg_hide'); }
|
||||||
|
|
||||||
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
||||||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41);
|
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41 || x == 42);
|
||||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 115: 'ServerConsole' };
|
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 42: 'ServerPlugins', 115: 'ServerConsole' };
|
||||||
for (var i in panels) {
|
for (var i in panels) {
|
||||||
QC(panels[i]).remove('style3x');
|
QC(panels[i]).remove('style3x');
|
||||||
QC(panels[i]).remove('style3sel');
|
QC(panels[i]).remove('style3sel');
|
||||||
@ -9455,8 +9459,9 @@
|
|||||||
// Fetch the server timeline stats if needed
|
// Fetch the server timeline stats if needed
|
||||||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||||||
|
|
||||||
if (x == 7) { refreshPluginLatest(); QV('PluginSubMenuSpan', true); goPlugin(-1); } else { noGoPlugin(); }
|
// MyServer Plugins
|
||||||
|
if (x == 42) { refreshPluginLatest(); } // goPlugin(-1); QV('PluginSubMenuSpan', true); goPlugin(-1); } //else { noGoPlugin(); }
|
||||||
|
|
||||||
// Update the web page title
|
// Update the web page title
|
||||||
if ((currentNode) && (x >= 10) && (x < 20)) {
|
if ((currentNode) && (x >= 10) && (x < 20)) {
|
||||||
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
||||||
@ -9464,30 +9469,30 @@
|
|||||||
document.title = decodeURIComponent('{{{extitle}}}');
|
document.title = decodeURIComponent('{{{extitle}}}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plugin
|
||||||
function updatePluginList(versInfo) {
|
function updatePluginList(versInfo) {
|
||||||
if (Array.isArray(versInfo)) {
|
if (Array.isArray(versInfo)) { versInfo.forEach(function(v) { updatePluginList(v); }); }
|
||||||
versInfo.forEach(function(v) { updatePluginList(v); });
|
QV('pluginNoneNotice', installedPluginList.length == 0);
|
||||||
}
|
|
||||||
if (installedPluginList.length) {
|
if (installedPluginList.length) {
|
||||||
if (versInfo != null) {
|
if (versInfo != null) {
|
||||||
if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
|
if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
|
||||||
installedPluginList['version_info'][versInfo.id] = versInfo;
|
installedPluginList['version_info'][versInfo.id] = versInfo;
|
||||||
}
|
}
|
||||||
var tr = Q('p7tbl').querySelectorAll(".p7tblRow");
|
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||||
if (tr.length) {
|
if (tr.length) {
|
||||||
for (const i in Object.values(tr)) {
|
for (var i in Object.values(tr)) {
|
||||||
tr[i].parentNode.removeChild(tr[i]);
|
tr[i].parentNode.removeChild(tr[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var statusMap = {
|
var statusMap = {
|
||||||
0: {
|
0: {
|
||||||
"text": 'Disabled',
|
'text': 'Disabled',
|
||||||
"color": '858483'
|
'color': '858483'
|
||||||
},
|
},
|
||||||
1: {
|
1: {
|
||||||
"text": 'Installed',
|
'text': 'Installed',
|
||||||
"color": '00ff00'
|
'color': '00aa00'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var statusAvailability = {
|
var statusAvailability = {
|
||||||
@ -9502,8 +9507,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var vers_not_compat = ` [ <span onclick="return setDialogMode(2, 'Compatibility Issue', 1, null, 'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.');" title="Version incompatible, please upgrade your MeshCentral installation first" style="cursor: pointer; color:red;"> ! </span> ]`;
|
var vers_not_compat = ` [ <span onclick="return setDialogMode(2, 'Compatibility Issue', 1, null, 'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.');" title="Version incompatible, please upgrade your MeshCentral installation first" style="cursor: pointer; color:red;"> ! </span> ]`;
|
||||||
|
|
||||||
var tbl = Q('p7tbl');
|
var tbl = Q('p42tbl');
|
||||||
installedPluginList.forEach(function(p){
|
installedPluginList.forEach(function(p){
|
||||||
var cant_action = [];
|
var cant_action = [];
|
||||||
if (p.hasAdminPanel == true && p.status) {
|
if (p.hasAdminPanel == true && p.status) {
|
||||||
@ -9514,21 +9519,16 @@
|
|||||||
p.statusText = statusMap[p.status].text;
|
p.statusText = statusMap[p.status].text;
|
||||||
p.statusColor = statusMap[p.status].color;
|
p.statusColor = statusMap[p.status].color;
|
||||||
|
|
||||||
if (p.versionHistoryUrl == null) {
|
if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
|
||||||
cant_action.push('downgrade');
|
if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
|
||||||
}
|
p.upgradeAvail = "Checking...";
|
||||||
|
|
||||||
if (!p.status) { // It isn't technically installed, so no version number
|
|
||||||
p.version = ' - ';
|
|
||||||
}
|
|
||||||
p.upgradeAvail = 'Checking...';
|
|
||||||
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
|
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
|
||||||
var vin = installedPluginList['version_info'][p._id];
|
var vin = installedPluginList['version_info'][p._id];
|
||||||
if (vin.hasUpdate) {
|
if (vin.hasUpdate) {
|
||||||
p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||||
} else {
|
} else {
|
||||||
cant_action.push('upgrade');
|
cant_action.push('upgrade');
|
||||||
if (p.status) p.upgradeAvail = 'Up to date';
|
if (p.status) p.upgradeAvail = "Up to date";
|
||||||
else p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
else p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||||
}
|
}
|
||||||
if (!vin.meshCentralCompat) {
|
if (!vin.meshCentralCompat) {
|
||||||
@ -9538,73 +9538,75 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.actions = '<select onchange="return pluginAction(this, \'' + p._id + '\');"><option value=""> --</option>';
|
p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
|
||||||
for (const [k, v] of Object.entries(statusAvailability[p.status])) {
|
var entries = Object.entries(statusAvailability[p.status]);
|
||||||
|
for (var k in entries) {
|
||||||
if (cant_action.indexOf(k) === -1) {
|
if (cant_action.indexOf(k) === -1) {
|
||||||
p.actions += '<option value="' + k + '">' + v + '</option>';
|
p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.actions += '</select>';
|
p.actions += '</select>';
|
||||||
|
|
||||||
let tpl = `<td>${p.nameHtml}</td><td>${p.description}</td><td><a href="${p.homepage}" target="_blank">Homepage</a></td><td>${p.version}</td><td class="pluginUpgradeAvailable">${p.upgradeAvail}</td><td style="color: #${p.statusColor}">${p.statusText}</td><td class="pluginAction">${p.actions}</td>`;
|
let tpl = `<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>${p.nameHtml}</td><td class=gradTable2>${p.description}</td><td class=gradTable2 style=text-align:center><a href="${p.homepage}" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>${p.version}</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">${p.upgradeAvail}</td><td class=gradTable2 style="text-align:center;color:#${p.statusColor}">${p.statusText}</td><td class="pluginAction gradTable2" style=text-align:center>${p.actions}</td><td class=gradTable3> </td>`;
|
||||||
let tr = tbl.insertRow(-1);
|
let tr = tbl.insertRow(-1);
|
||||||
tr.innerHTML = tpl;
|
tr.innerHTML = tpl;
|
||||||
tr.classList.add('p7tblRow');
|
tr.classList.add('p42tblRow');
|
||||||
tr.setAttribute('data-id', p._id);
|
tr.setAttribute('data-id', p._id);
|
||||||
tr.setAttribute('id', 'pluginRow-'+p._id);
|
tr.setAttribute('id', 'pluginRow-' + p._id);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var tr = Q('p7tbl').querySelectorAll(".p7tblRow");
|
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||||
for (const i in Object.values(tr)) {
|
for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
|
||||||
tr[i].parentNode.removeChild(tr[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (versInfo == null) refreshPluginLatest();
|
if (versInfo == null) refreshPluginLatest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshPluginLatest() {
|
function refreshPluginLatest() {
|
||||||
meshserver.send({ action: 'pluginLatestCheck' });
|
meshserver.send({ action: 'pluginLatestCheck' });
|
||||||
}
|
}
|
||||||
|
|
||||||
function distributeCore() {
|
function distributeCore() {
|
||||||
meshserver.send({ action: 'distributeCore', nodes: nodes }); // all nodes the user has access to
|
meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
|
||||||
QV('pluginRestartNotice', false);
|
QV('pluginRestartNotice', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pluginActionEx() {
|
function pluginActionEx() {
|
||||||
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
|
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
|
||||||
|
|
||||||
switch(act) {
|
switch(act) {
|
||||||
case 'upgrade':
|
case 'upgrade':
|
||||||
case 'install':
|
case 'install':
|
||||||
meshserver.send({ "action": "installplugin", "id": id, "version_only": false });
|
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
|
||||||
break;
|
break;
|
||||||
case 'downgrade':
|
case 'downgrade':
|
||||||
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
|
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
|
||||||
if (opt.value == pVersUrl) pVers = opt.text;
|
if (opt.value == pVersUrl) pVers = opt.text;
|
||||||
});
|
});
|
||||||
meshserver.send({ "action": "installplugin", "id": id, "version_only": { "name": pVers, "url": pVersUrl }});
|
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
meshserver.send({ "action": "removeplugin", "id": id });
|
meshserver.send({ 'action': 'removeplugin', 'id': id });
|
||||||
break;
|
break;
|
||||||
case 'disable':
|
case 'disable':
|
||||||
meshserver.send({ "action": "disableplugin", "id": id });
|
meshserver.send({ 'action': 'disableplugin', 'id': id });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
QS('pluginRestartNotice').display = '';
|
QV('pluginRestartNotice', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pluginAction(elem, id) {
|
function pluginAction(elem, id) {
|
||||||
if (elem.value == 'downgrade') {
|
if (elem.value == 'downgrade') {
|
||||||
meshserver.send({ "action": "getpluginversions", "id": id });
|
meshserver.send({ 'action': 'getpluginversions', 'id': id });
|
||||||
} else {
|
} else {
|
||||||
setDialogMode(2, 'Plugin Action', 3, pluginActionEx, 'Are you sure you want to ' + elem.value + ' the plugin: ' + elem.parentNode.parentNode.firstChild.innerText+'<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + elem.parentNode.parentNode.getAttribute('data-id') + '" /><input id="lastPluginVersion" type="hidden" value="" />');
|
var plugin = null;
|
||||||
|
for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
|
||||||
|
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format("Are you sure you want to {0} the plugin: {1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
|
||||||
}
|
}
|
||||||
elem.value = '';
|
elem.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function goPlugin(pname, title) {
|
function goPlugin(pname, title) {
|
||||||
|
/*
|
||||||
let holder = Q('PluginSubMenu').querySelectorAll('tr')[0];
|
let holder = Q('PluginSubMenu').querySelectorAll('tr')[0];
|
||||||
let loadedPluginsTDs = holder.querySelectorAll('td');
|
let loadedPluginsTDs = holder.querySelectorAll('td');
|
||||||
var found = false;
|
var found = false;
|
||||||
@ -9612,25 +9614,25 @@
|
|||||||
p.classList.remove('style3sel');
|
p.classList.remove('style3sel');
|
||||||
p.classList.add('style3x');
|
p.classList.add('style3x');
|
||||||
var tname = p.getAttribute('x-data-plugin-sname');
|
var tname = p.getAttribute('x-data-plugin-sname');
|
||||||
if (tname != null) { Q('plugin-'+tname).style.display = 'none'; }
|
if (tname != null) { Q('plugin-' + tname).style.display = 'none'; }
|
||||||
if (tname == pname) {
|
if (tname == pname) {
|
||||||
// show existing tab / content
|
// show existing tab / content
|
||||||
p.classList.remove('style3x');
|
p.classList.remove('style3x');
|
||||||
p.classList.add('style3sel');
|
p.classList.add('style3sel');
|
||||||
QS('p7').display = 'none';
|
QS('p42').display = 'none';
|
||||||
Q('plugin-'+tname).style.display = '';
|
Q('plugin-'+tname).style.display = '';
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (pname == -1) { // go gome
|
if (pname == -1) { // Go home
|
||||||
QV('p7', true);
|
QV('p42', true);
|
||||||
let homeTab = loadedPluginsTDs[0];
|
let homeTab = loadedPluginsTDs[0];
|
||||||
homeTab.classList.add('style3sel');
|
homeTab.classList.add('style3sel');
|
||||||
homeTab.classList.remove('style3x');
|
homeTab.classList.remove('style3x');
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
if (found) return;
|
if (found) return;
|
||||||
|
|
||||||
Q('PluginSubMenu').style.display = 'block';
|
Q('PluginSubMenu').style.display = 'block';
|
||||||
let sif = document.createElement('td');
|
let sif = document.createElement('td');
|
||||||
sif.setAttribute('x-data-plugin-sname', pname);
|
sif.setAttribute('x-data-plugin-sname', pname);
|
||||||
@ -9641,7 +9643,7 @@
|
|||||||
sif.setAttribute('onkeypress', 'if (event.key == "Enter") goPlugin("' + pname + '", "' + title + '")');
|
sif.setAttribute('onkeypress', 'if (event.key == "Enter") goPlugin("' + pname + '", "' + title + '")');
|
||||||
sif.innerHTML = title;
|
sif.innerHTML = title;
|
||||||
holder.append(sif);
|
holder.append(sif);
|
||||||
|
|
||||||
let dif = document.createElement('div');
|
let dif = document.createElement('div');
|
||||||
dif.setAttribute('id', 'plugin-'+pname);
|
dif.setAttribute('id', 'plugin-'+pname);
|
||||||
dif.classList.add('pluginContent');
|
dif.classList.add('pluginContent');
|
||||||
@ -9654,19 +9656,21 @@
|
|||||||
dif.append(pif);
|
dif.append(pif);
|
||||||
let x = Q('column_l_bottomgap');
|
let x = Q('column_l_bottomgap');
|
||||||
x.parentNode.insertBefore(dif, x.previousSibling);
|
x.parentNode.insertBefore(dif, x.previousSibling);
|
||||||
QS('p7').display = 'none';
|
QS('p42').display = 'none';
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function noGoPlugin(el) {
|
function noGoPlugin(el) {
|
||||||
|
/*
|
||||||
QV('PluginSubMenuSpan', false);
|
QV('PluginSubMenuSpan', false);
|
||||||
let loadedPluginsTDs = Q('PluginSubMenu').querySelectorAll('td');
|
let loadedPluginsTDs = Q('PluginSubMenu').querySelectorAll('td');
|
||||||
loadedPluginsTDs.forEach((p) => {
|
loadedPluginsTDs.forEach((p) => {
|
||||||
var tname = p.getAttribute('x-data-plugin-sname');
|
var tname = p.getAttribute('x-data-plugin-sname');
|
||||||
if (tname != null) Q('plugin-'+tname).style.display = 'none';
|
if (tname != null) Q('plugin-'+tname).style.display = 'none';
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic methods
|
// Generic methods
|
||||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||||
function putstore(name, val) {
|
function putstore(name, val) {
|
||||||
@ -9727,7 +9731,7 @@
|
|||||||
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
||||||
function format(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; }); };
|
function format(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; }); };
|
||||||
function nobreak(x) { return x.split(' ').join(' '); }
|
function nobreak(x) { return x.split(' ').join(' '); }
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -55,6 +55,11 @@
|
|||||||
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
|
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
|
||||||
<div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
|
<div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
|
<div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||||||
|
<div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
<!-- main page -->
|
<!-- main page -->
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
||||||
@ -107,6 +112,7 @@
|
|||||||
<td tabindex="0" id="MainMenuMyFiles" class="topbar_td style3x" onclick="go(5,event)" onkeypress="if (event.key == 'Enter') go(5)">Mes Dossiers</td>
|
<td tabindex="0" id="MainMenuMyFiles" class="topbar_td style3x" onclick="go(5,event)" onkeypress="if (event.key == 'Enter') go(5)">Mes Dossiers</td>
|
||||||
<td tabindex="0" id="MainMenuMyUsers" class="topbar_td style3x" onclick="go(4,event)" onkeypress="if (event.key == 'Enter') go(4)">Mes Utilisateurs</td>
|
<td tabindex="0" id="MainMenuMyUsers" class="topbar_td style3x" onclick="go(4,event)" onkeypress="if (event.key == 'Enter') go(4)">Mes Utilisateurs</td>
|
||||||
<td tabindex="0" id="MainMenuMyServer" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">Mon Serveur</td>
|
<td tabindex="0" id="MainMenuMyServer" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">Mon Serveur</td>
|
||||||
|
<!-- <td tabindex=0 id=MainMenuMyPlugins class="topbar_td style3x" onclick=go(7,event) onkeypress="if (event.key == 'Enter') go(7)">My Plugins</td> -->
|
||||||
<td class="topbar_td_end style3"> </td>
|
<td class="topbar_td_end style3"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
@ -150,10 +156,20 @@
|
|||||||
<td tabindex="0" id="ServerStats" class="topbar_td style3x" onclick="go(40,event)" onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
|
<td tabindex="0" id="ServerStats" class="topbar_td style3x" onclick="go(40,event)" onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
|
||||||
<td tabindex="0" id="ServerConsole" class="topbar_td style3x" onclick="go(115,event)" onkeypress="if (event.key == 'Enter') go(115)">Console</td>
|
<td tabindex="0" id="ServerConsole" class="topbar_td style3x" onclick="go(115,event)" onkeypress="if (event.key == 'Enter') go(115)">Console</td>
|
||||||
<td tabindex="0" id="ServerTrace" class="topbar_td style3x" onclick="go(41,event)" onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
<td tabindex="0" id="ServerTrace" class="topbar_td style3x" onclick="go(41,event)" onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
||||||
|
<td tabindex="0" id="ServerPlugins" class="topbar_td style3x" onclick="go(42,event)" onkeypress="if (event.key == 'Enter') go(42)">Plugins</td>
|
||||||
<td class="topbar_td_end style3"> </td>
|
<td class="topbar_td_end style3"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
|
<div id=PluginSubMenuSpan>
|
||||||
|
<table id=PluginSubMenu cellpadding=0 cellspacing=0 class=style1>
|
||||||
|
<tr>
|
||||||
|
<td onclick="goPlugin(-1)" onkeypress="if (event.key == 'Enter') goPlugin(-1)" class="topbar_td style3x">Home</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
<div id="UserDummyMenuSpan">
|
<div id="UserDummyMenuSpan">
|
||||||
<table id="UserDummyMenu" cellpadding="0" cellspacing="0" class="style1">
|
<table id="UserDummyMenu" cellpadding="0" cellspacing="0" class="style1">
|
||||||
<tbody><tr><td class="style3" style=""> </td></tr>
|
<tbody><tr><td class="style3" style=""> </td></tr>
|
||||||
@ -847,6 +863,28 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="p41events" style=""></div>
|
<div id="p41events" style=""></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="p42" style="display:none">
|
||||||
|
<h1>My Server Plugins</h1>
|
||||||
|
<div class="areaHead">
|
||||||
|
<div class="toright2">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input value="Download Plugin" type="button" onclick="return pluginHandler.addPluginDlg();">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pluginRestartNotice" class="areaHead" style="background-color:gold;display:none">
|
||||||
|
<div class="toright2">
|
||||||
|
<input value="Refresh Agent Cores" type="button" onclick="distributeCore();return false">
|
||||||
|
</div>
|
||||||
|
<div style="padding:2px">
|
||||||
|
<div style="padding:2px"><b>Notice:</b> Plugins have been altered, this may require agent core update.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table id="p42tbl">
|
||||||
|
<tbody><tr class="DevSt"><th style="width:26px"></th><th style="width:10px"></th><th class="chName">Nom</th><th class="chDescription">Description</th><th class="chSite" style="text-align:center">Link</th><th class="chVersion" style="text-align:center">Version</th><th class="chUpgradeAvail" style="text-align:center">Latest</th><th class="chStatus" style="text-align:center">Statut</th><th class="chAction" style="text-align:center">Action</th><th style="width:10px"></th></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<div id="pluginNoneNotice" style="width:100%;text-align:center;padding-top:10px;display:none"><i>No plugins on server.</i></div>
|
||||||
|
</div>
|
||||||
<div id="p19" style="display:none">
|
<div id="p19" style="display:none">
|
||||||
<h1>Plugins - <span id="p19deviceName"></span></h1>
|
<h1>Plugins - <span id="p19deviceName"></span></h1>
|
||||||
<style>
|
<style>
|
||||||
@ -1040,6 +1078,7 @@
|
|||||||
var pluginHandlerBuilder = {{{pluginHandler}}};
|
var pluginHandlerBuilder = {{{pluginHandler}}};
|
||||||
var pluginHandler = null;
|
var pluginHandler = null;
|
||||||
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
||||||
|
var installedPluginList = null;
|
||||||
|
|
||||||
// Console Message Display Timers
|
// Console Message Display Timers
|
||||||
var p11DeskConsoleMsgTimer = null;
|
var p11DeskConsoleMsgTimer = null;
|
||||||
@ -1293,6 +1332,7 @@
|
|||||||
// Fetch list of meshes, nodes, files
|
// Fetch list of meshes, nodes, files
|
||||||
meshserver.send({ action: 'meshes' });
|
meshserver.send({ action: 'meshes' });
|
||||||
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
||||||
|
if (pluginHandler != null) { meshserver.send({ action: 'plugins' }); }
|
||||||
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
||||||
if ('{{viewmode}}' == '') { go(1); }
|
if ('{{viewmode}}' == '') { go(1); }
|
||||||
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
||||||
@ -2282,6 +2322,16 @@
|
|||||||
//console.log(message.msg);
|
//console.log(message.msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'updatePluginList': {
|
||||||
|
installedPluginList = message.event.list;
|
||||||
|
updatePluginList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'pluginStateChange': {
|
||||||
|
if (pluginHandler == null) break;
|
||||||
|
pluginHandler.refreshPluginHandler();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
//console.log('Unknown message.event.action', message.event.action);
|
//console.log('Unknown message.event.action', message.event.action);
|
||||||
break;
|
break;
|
||||||
@ -2335,6 +2385,27 @@
|
|||||||
QH('p0span', message.msg);
|
QH('p0span', message.msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'updatePluginList': {
|
||||||
|
installedPluginList = message.list;
|
||||||
|
updatePluginList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'pluginVersionsAvailable': {
|
||||||
|
if (pluginHandler == null) break;
|
||||||
|
updatePluginList(message.list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'downgradePluginVersions': {
|
||||||
|
var vSelect = '<select id="lastPluginVersion">';
|
||||||
|
message.info.versionList.forEach(function(v) { vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>'; });
|
||||||
|
vSelect += '</select>';
|
||||||
|
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format('Select the version to downgrade the plugin: {0}', message.info.name) + '<hr />' + vSelect + '<hr />' + "Please be aware that downgrading is not recommended. Please only do so in the event that a recent upgrade has broken something." + + '<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'pluginError': {
|
||||||
|
setDialogMode(2, "Plugin Error", 1, null, message.msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'plugin': {
|
case 'plugin': {
|
||||||
if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
|
if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
|
||||||
try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
|
try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
|
||||||
@ -3482,6 +3553,12 @@
|
|||||||
contextmenudiv.style.left = event.pageX + 'px';
|
contextmenudiv.style.left = event.pageX + 'px';
|
||||||
contextmenudiv.style.top = event.pageY + 'px';
|
contextmenudiv.style.top = event.pageY + 'px';
|
||||||
contextmenudiv.style.display = 'block';
|
contextmenudiv.style.display = 'block';
|
||||||
|
/*} else if (elem && elem != null && elem.classList.contains('pluginTab')) {
|
||||||
|
contextelement = elem;
|
||||||
|
var contextmenudiv = document.getElementById('pluginTabContextMenu');
|
||||||
|
contextmenudiv.style.left = event.pageX + 'px';
|
||||||
|
contextmenudiv.style.top = event.pageY + 'px';
|
||||||
|
contextmenudiv.style.display = 'block';*/
|
||||||
} else {
|
} else {
|
||||||
while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
|
while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
|
||||||
if (!elem || elem == null) return true;
|
if (!elem || elem == null) return true;
|
||||||
@ -3553,10 +3630,23 @@
|
|||||||
connectTerminal(null, 1, { powershell: (action == 2) });
|
connectTerminal(null, 1, { powershell: (action == 2) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function pluginTabClose() {
|
||||||
|
var pluginTab = contextelement;
|
||||||
|
var pname = pluginTab.getAttribute('x-data-plugin-sname');
|
||||||
|
var pdiv = Q('plugin-'+pname);
|
||||||
|
pdiv.parentNode.removeChild(pdiv);
|
||||||
|
pluginTab.parentNode.removeChild(pluginTab);
|
||||||
|
QV('p42', true);
|
||||||
|
goPlugin(-1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
function hideContextMenu() {
|
function hideContextMenu() {
|
||||||
QV('contextMenu', false);
|
QV('contextMenu', false);
|
||||||
QV('meshContextMenu', false);
|
QV('meshContextMenu', false);
|
||||||
QV('termShellContextMenu', false);
|
QV('termShellContextMenu', false);
|
||||||
|
//QV('pluginTabContextMenu', false);
|
||||||
contextelement = null;
|
contextelement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4478,7 +4568,7 @@
|
|||||||
p13clearConsoleMsg();
|
p13clearConsoleMsg();
|
||||||
|
|
||||||
// Device refresh plugin handler
|
// Device refresh plugin handler
|
||||||
if (pluginHandler != null) { pluginHandler.onDeviceRefeshEnd(nodeid, panel, refresh, event); }
|
if (pluginHandler != null) { pluginHandler.callHook('onDeviceRefreshEnd', nodeid, panel, refresh, event); }
|
||||||
}
|
}
|
||||||
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
|
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
|
||||||
if (!panel) panel = 10;
|
if (!panel) panel = 10;
|
||||||
@ -5139,6 +5229,7 @@
|
|||||||
desktop.Stop();
|
desktop.Stop();
|
||||||
webRtcDesktopReset();
|
webRtcDesktopReset();
|
||||||
desktopNode = desktop = null;
|
desktopNode = desktop = null;
|
||||||
|
if (pluginHandler != null) { pluginHandler.callHook('onDesktopDisconnect'); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9285,7 +9376,7 @@
|
|||||||
if (xxcurrentView == x) return;
|
if (xxcurrentView == x) return;
|
||||||
|
|
||||||
// Edit this line when adding a new screen
|
// Edit this line when adding a new screen
|
||||||
for (var i = 0; i < 42; i++) { QV('p' + i, i == x); }
|
for (var i = 0; i < 43; i++) { QV('p' + i, i == x); }
|
||||||
xxcurrentView = x;
|
xxcurrentView = x;
|
||||||
|
|
||||||
// Remove top bar selection
|
// Remove top bar selection
|
||||||
@ -9304,7 +9395,7 @@
|
|||||||
|
|
||||||
// Define class for Menu(s) as fully or semi active.
|
// Define class for Menu(s) as fully or semi active.
|
||||||
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
||||||
var leftMenuActiveClass = (x < 9 ? 'lbbuttonsel2' : 'lbbuttonsel');
|
var leftMenuActiveClass = (((x < 9) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) ? 'lbbuttonsel2' : 'lbbuttonsel');
|
||||||
|
|
||||||
// My Devices
|
// My Devices
|
||||||
if (x == 1 || (x >= 10 && x < 20)) QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
if (x == 1 || (x >= 10 && x < 20)) QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
||||||
@ -9328,21 +9419,21 @@
|
|||||||
|
|
||||||
// My Server
|
// My Server
|
||||||
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
||||||
if ((x == 6) || (x == 115) || (x == 40)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
if ((x == 6) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||||||
|
|
||||||
// column_l max-height
|
// column_l max-height
|
||||||
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||||||
|
|
||||||
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
||||||
QV('topbar', x != 0);
|
QV('topbar', x != 0);
|
||||||
if ((x == 0) && (webPageFullScreen)) { QC('body').add("arg_hide"); }
|
if ((x == 0) && (webPageFullScreen)) { QC('body').add('arg_hide'); }
|
||||||
|
|
||||||
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
||||||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41);
|
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41 || x == 42);
|
||||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 115: 'ServerConsole' };
|
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 42: 'ServerPlugins', 115: 'ServerConsole' };
|
||||||
for (var i in panels) {
|
for (var i in panels) {
|
||||||
QC(panels[i]).remove('style3x');
|
QC(panels[i]).remove('style3x');
|
||||||
QC(panels[i]).remove('style3sel');
|
QC(panels[i]).remove('style3sel');
|
||||||
@ -9366,6 +9457,9 @@
|
|||||||
// Fetch the server timeline stats if needed
|
// Fetch the server timeline stats if needed
|
||||||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||||||
|
|
||||||
|
// MyServer Plugins
|
||||||
|
if (x == 42) { refreshPluginLatest(); } // goPlugin(-1); QV('PluginSubMenuSpan', true); goPlugin(-1); } //else { noGoPlugin(); }
|
||||||
|
|
||||||
// Update the web page title
|
// Update the web page title
|
||||||
if ((currentNode) && (x >= 10) && (x < 20)) {
|
if ((currentNode) && (x >= 10) && (x < 20)) {
|
||||||
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
||||||
@ -9374,6 +9468,207 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plugin
|
||||||
|
function updatePluginList(versInfo) {
|
||||||
|
if (Array.isArray(versInfo)) { versInfo.forEach(function(v) { updatePluginList(v); }); }
|
||||||
|
QV('pluginNoneNotice', installedPluginList.length == 0);
|
||||||
|
if (installedPluginList.length) {
|
||||||
|
if (versInfo != null) {
|
||||||
|
if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
|
||||||
|
installedPluginList['version_info'][versInfo.id] = versInfo;
|
||||||
|
}
|
||||||
|
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||||
|
if (tr.length) {
|
||||||
|
for (var i in Object.values(tr)) {
|
||||||
|
tr[i].parentNode.removeChild(tr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var statusMap = {
|
||||||
|
0: {
|
||||||
|
'text': 'Disabled',
|
||||||
|
'color': '858483'
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
'text': 'Installed',
|
||||||
|
'color': '00aa00'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var statusAvailability = {
|
||||||
|
0: {
|
||||||
|
'install': 'Install',
|
||||||
|
'delete': 'Delete'
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
'disable': 'Disable',
|
||||||
|
'upgrade': 'Upgrade',
|
||||||
|
// 'downgrade': 'Downgrade' // disabling until plugins have prior versions available for better testing
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var vers_not_compat = ` [ <span onclick="return setDialogMode(2, 'Compatibility Issue', 1, null, 'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.');" title="Version incompatible, please upgrade your MeshCentral installation first" style="cursor: pointer; color:red;"> ! </span> ]`;
|
||||||
|
|
||||||
|
var tbl = Q('p42tbl');
|
||||||
|
installedPluginList.forEach(function(p){
|
||||||
|
var cant_action = [];
|
||||||
|
if (p.hasAdminPanel == true && p.status) {
|
||||||
|
p.nameHtml = `<a onclick="return goPlugin('${p.shortName}', '${p.name}');">${p.name}</a>`;
|
||||||
|
} else {
|
||||||
|
p.nameHtml = p.name;
|
||||||
|
}
|
||||||
|
p.statusText = statusMap[p.status].text;
|
||||||
|
p.statusColor = statusMap[p.status].color;
|
||||||
|
|
||||||
|
if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
|
||||||
|
if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
|
||||||
|
p.upgradeAvail = "Checking...";
|
||||||
|
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
|
||||||
|
var vin = installedPluginList['version_info'][p._id];
|
||||||
|
if (vin.hasUpdate) {
|
||||||
|
p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||||
|
} else {
|
||||||
|
cant_action.push('upgrade');
|
||||||
|
if (p.status) p.upgradeAvail = "Up to date";
|
||||||
|
else p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||||
|
}
|
||||||
|
if (!vin.meshCentralCompat) {
|
||||||
|
p.upgradeAvail += vers_not_compat;
|
||||||
|
cant_action.push('install');
|
||||||
|
cant_action.push('upgrade');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
|
||||||
|
var entries = Object.entries(statusAvailability[p.status]);
|
||||||
|
for (var k in entries) {
|
||||||
|
if (cant_action.indexOf(k) === -1) {
|
||||||
|
p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.actions += '</select>';
|
||||||
|
|
||||||
|
let tpl = `<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>${p.nameHtml}</td><td class=gradTable2>${p.description}</td><td class=gradTable2 style=text-align:center><a href="${p.homepage}" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>${p.version}</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">${p.upgradeAvail}</td><td class=gradTable2 style="text-align:center;color:#${p.statusColor}">${p.statusText}</td><td class="pluginAction gradTable2" style=text-align:center>${p.actions}</td><td class=gradTable3> </td>`;
|
||||||
|
let tr = tbl.insertRow(-1);
|
||||||
|
tr.innerHTML = tpl;
|
||||||
|
tr.classList.add('p42tblRow');
|
||||||
|
tr.setAttribute('data-id', p._id);
|
||||||
|
tr.setAttribute('id', 'pluginRow-' + p._id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||||
|
for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
|
||||||
|
}
|
||||||
|
if (versInfo == null) refreshPluginLatest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshPluginLatest() {
|
||||||
|
meshserver.send({ action: 'pluginLatestCheck' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function distributeCore() {
|
||||||
|
meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
|
||||||
|
QV('pluginRestartNotice', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pluginActionEx() {
|
||||||
|
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
|
||||||
|
|
||||||
|
switch(act) {
|
||||||
|
case 'upgrade':
|
||||||
|
case 'install':
|
||||||
|
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
|
||||||
|
break;
|
||||||
|
case 'downgrade':
|
||||||
|
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
|
||||||
|
if (opt.value == pVersUrl) pVers = opt.text;
|
||||||
|
});
|
||||||
|
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
meshserver.send({ 'action': 'removeplugin', 'id': id });
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
meshserver.send({ 'action': 'disableplugin', 'id': id });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QV('pluginRestartNotice', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pluginAction(elem, id) {
|
||||||
|
if (elem.value == 'downgrade') {
|
||||||
|
meshserver.send({ 'action': 'getpluginversions', 'id': id });
|
||||||
|
} else {
|
||||||
|
var plugin = null;
|
||||||
|
for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
|
||||||
|
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format("Are you sure you want to {0} the plugin: {1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
|
||||||
|
}
|
||||||
|
elem.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function goPlugin(pname, title) {
|
||||||
|
/*
|
||||||
|
let holder = Q('PluginSubMenu').querySelectorAll('tr')[0];
|
||||||
|
let loadedPluginsTDs = holder.querySelectorAll('td');
|
||||||
|
var found = false;
|
||||||
|
loadedPluginsTDs.forEach((p) => {
|
||||||
|
p.classList.remove('style3sel');
|
||||||
|
p.classList.add('style3x');
|
||||||
|
var tname = p.getAttribute('x-data-plugin-sname');
|
||||||
|
if (tname != null) { Q('plugin-' + tname).style.display = 'none'; }
|
||||||
|
if (tname == pname) {
|
||||||
|
// show existing tab / content
|
||||||
|
p.classList.remove('style3x');
|
||||||
|
p.classList.add('style3sel');
|
||||||
|
QS('p42').display = 'none';
|
||||||
|
Q('plugin-'+tname).style.display = '';
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (pname == -1) { // Go home
|
||||||
|
QV('p42', true);
|
||||||
|
let homeTab = loadedPluginsTDs[0];
|
||||||
|
homeTab.classList.add('style3sel');
|
||||||
|
homeTab.classList.remove('style3x');
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (found) return;
|
||||||
|
|
||||||
|
Q('PluginSubMenu').style.display = 'block';
|
||||||
|
let sif = document.createElement('td');
|
||||||
|
sif.setAttribute('x-data-plugin-sname', pname);
|
||||||
|
sif.classList.add('topbar_td');
|
||||||
|
sif.classList.add('style3sel');
|
||||||
|
sif.classList.add('pluginTab');
|
||||||
|
sif.setAttribute('onclick', 'goPlugin("' + pname + '", "' + title + '")');
|
||||||
|
sif.setAttribute('onkeypress', 'if (event.key == "Enter") goPlugin("' + pname + '", "' + title + '")');
|
||||||
|
sif.innerHTML = title;
|
||||||
|
holder.append(sif);
|
||||||
|
|
||||||
|
let dif = document.createElement('div');
|
||||||
|
dif.setAttribute('id', 'plugin-'+pname);
|
||||||
|
dif.classList.add('pluginContent');
|
||||||
|
let pif = document.createElement('iframe');
|
||||||
|
pif.src = '/pluginadmin.ashx?pin='+pname;
|
||||||
|
pif.setAttribute('frameBorder', '0');
|
||||||
|
pif.style.width = '100%';
|
||||||
|
pif.style.height = '100%';
|
||||||
|
pif.setAttribute('frameBorder', '0');
|
||||||
|
dif.append(pif);
|
||||||
|
let x = Q('column_l_bottomgap');
|
||||||
|
x.parentNode.insertBefore(dif, x.previousSibling);
|
||||||
|
QS('p42').display = 'none';
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function noGoPlugin(el) {
|
||||||
|
/*
|
||||||
|
QV('PluginSubMenuSpan', false);
|
||||||
|
let loadedPluginsTDs = Q('PluginSubMenu').querySelectorAll('td');
|
||||||
|
loadedPluginsTDs.forEach((p) => {
|
||||||
|
var tname = p.getAttribute('x-data-plugin-sname');
|
||||||
|
if (tname != null) Q('plugin-'+tname).style.display = 'none';
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// Generic methods
|
// Generic methods
|
||||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||||
function putstore(name, val) {
|
function putstore(name, val) {
|
||||||
@ -9434,7 +9729,7 @@
|
|||||||
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
||||||
function format(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; }); };
|
function format(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; }); };
|
||||||
function nobreak(x) { return x.split(' ').join(' '); }
|
function nobreak(x) { return x.split(' ').join(' '); }
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
61
webserver.js
61
webserver.js
@ -3214,35 +3214,38 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.handlePluginAdminReq = function(req, res) {
|
if (parent.pluginHandler != null) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
// Handle a plugin admin request
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
obj.handlePluginAdminReq = function (req, res) {
|
||||||
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
const domain = checkUserIpAddress(req, res);
|
||||||
var user = obj.users[req.session.userid];
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
if (user == null) { res.sendStatus(401); return; }
|
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
||||||
|
var user = obj.users[req.session.userid];
|
||||||
parent.pluginHandler.handleAdminReq(req, res, user, obj);
|
if (user == null) { res.sendStatus(401); return; }
|
||||||
}
|
|
||||||
|
parent.pluginHandler.handleAdminReq(req, res, user, obj);
|
||||||
obj.handlePluginAdminPostReq = function(req, res) {
|
}
|
||||||
const domain = checkUserIpAddress(req, res);
|
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
obj.handlePluginAdminPostReq = function (req, res) {
|
||||||
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
const domain = checkUserIpAddress(req, res);
|
||||||
var user = obj.users[req.session.userid];
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
if (user == null) { res.sendStatus(401); return; }
|
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
||||||
|
var user = obj.users[req.session.userid];
|
||||||
parent.pluginHandler.handleAdminPostReq(req, res, user, obj);
|
if (user == null) { res.sendStatus(401); return; }
|
||||||
}
|
|
||||||
|
parent.pluginHandler.handleAdminPostReq(req, res, user, obj);
|
||||||
obj.handlePluginJS = function(req, res) {
|
}
|
||||||
const domain = checkUserIpAddress(req, res);
|
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
obj.handlePluginJS = function (req, res) {
|
||||||
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
const domain = checkUserIpAddress(req, res);
|
||||||
var user = obj.users[req.session.userid];
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
if (user == null) { res.sendStatus(401); return; }
|
if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
||||||
|
var user = obj.users[req.session.userid];
|
||||||
parent.pluginHandler.refreshJS(req, res);
|
if (user == null) { res.sendStatus(401); return; }
|
||||||
|
|
||||||
|
parent.pluginHandler.refreshJS(req, res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the HTTPS server, this should be called after the user/mesh tables are loaded
|
// Starts the HTTPS server, this should be called after the user/mesh tables are loaded
|
||||||
|
Loading…
Reference in New Issue
Block a user