diff --git a/meshuser.js b/meshuser.js index 86fb79ec..05f0e9b6 100644 --- a/meshuser.js +++ b/meshuser.js @@ -3147,6 +3147,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use parent.parent.pluginHandler.disablePlugin(command.id, function(){ parent.db.getPlugins(function(err, docs) { try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { } + // @TODO delete plugin object from handler }); }); break; diff --git a/pluginHandler.js b/pluginHandler.js index 12fe18b8..92cb9b10 100644 --- a/pluginHandler.js +++ b/pluginHandler.js @@ -54,21 +54,15 @@ module.exports.pluginHandler = function (parent) { }); } - obj.prepExportsForPlugin = function(plugin) { - var str = ''; - str += ' obj.' + plugin + ' = {};\r\n'; - for (const l of Object.values(obj.exports[plugin])) { - str += ' obj.' + plugin + '.' + l + ' = ' + obj.plugins[plugin][l].toString() + '\r\n'; - } - return str; - }; - obj.prepExports = function () { var str = 'function() {\r\n'; str += ' var obj = {};\r\n'; for (const p of Object.keys(obj.plugins)) { - str += obj.prepExportsForPlugin(p); + str += ' obj.' + p + ' = {};\r\n'; + for (const l of Object.values(obj.exports[p])) { + str += ' obj.' + p + '.' + l + ' = ' + obj.plugins[p][l].toString() + '\r\n'; + } } str += `obj.onDeviceRefeshEnd = function(nodeid, panel, refresh, event) { @@ -371,5 +365,26 @@ module.exports.pluginHandler = function (parent) { }); }; + obj.handleAdminReq = function (req, res, serv) { + var path = obj.path.join(obj.pluginPath, req.query.pin, 'views'); + serv.app.set('views', path); + if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') { + obj.plugins[req.query.pin].handleAdminReq(req, res); + } + else { + res.sendStatus(401); + } + } + + obj.handleAdminPostReq = function(req, res, serv) { + var path = obj.path.join(obj.pluginPath, req.query.pin, 'views'); + serv.app.set('views', path); + if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') { + obj.plugins[req.query.pin].handleAdminPostReq(req, res); + } + else { + res.sendStatus(401); + } + } return obj; }; \ No newline at end of file diff --git a/public/styles/style.css b/public/styles/style.css index b588133b..11d42602 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -2627,4 +2627,45 @@ a { text-align: center; padding: 14px; margin: 50px auto; +} + +.pluginOverlayBg { + width: 95%; /* Full width (cover the whole page) */ + height: 95%; /* Full height (cover the whole page) */ + margin: 10px; + background-color: rgba(0,0,0,0.8); /* Black background with opacity */ + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */ + position: absolute; + cursor: pointer; /* Add a pointer on hover */ + filter:blur(4px); + -o-filter:blur(4px); + -ms-filter:blur(4px); + -moz-filter:blur(4px); + -webkit-filter:blur(4px); +} + +.pluginOverlay { + width: 95%; /* Full width (cover the whole page) */ + height: 95%; /* Full height (cover the whole page) */ + margin: 10px; + background-color: #FFFFFF; /* Black background with opacity */ + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */ + position: absolute; + cursor: pointer; /* Add a pointer on hover */ +} + +.pluginTitleBar { + padding: 4px; + height: 25px; + border-bottom: double; + font-size: 20px; +} + +.pluginCloseBtn { + border: none; + outline: none; + cursor: pointer; + float: right; + position: relative; + padding: 0; } \ No newline at end of file diff --git a/views/default.handlebars b/views/default.handlebars index b9ffa8f7..5817821d 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -9408,7 +9408,7 @@ // Fetch the server timeline stats if needed if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); } - if (x == 7) refreshPluginLatest(); + if (x == 7) refreshPluginLatest(); else noGoPlugin(); // Update the web page title if ((currentNode) && (x >= 10) && (x < 20)) { @@ -9456,7 +9456,7 @@ installedPluginList.forEach(function(p){ var cant_action = []; if (p.hasAdminPanel == true) { - p.name = `${p.name}`; + p.nameHtml = `${p.name}`; } p.statusText = statusMap[p.status].text; p.statusColor = statusMap[p.status].color; @@ -9490,7 +9490,7 @@ } p.actions += ''; - let tpl = `${p.name}${p.description}Homepage${p.version}${p.upgradeAvail}${p.statusText}${p.actions}`; + let tpl = `${p.nameHtml}${p.description}Homepage${p.version}${p.upgradeAvail}${p.statusText}${p.actions}`; let tr = tbl.insertRow(-1); tr.innerHTML = tpl; tr.classList.add('p7tblRow'); @@ -9532,6 +9532,38 @@ elem.value = ''; } + function goPlugin(pname, title) { + let xwin = `
${title}
` + let dif = document.createElement('div'); + dif.classList.add('pluginOverlay'); + dif.innerHTML = xwin; + 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('p7'); + x.parentNode.insertBefore(dif, x.nextSibling); + Q('p7').classList.add('pluginOverlayBg'); + } + + function noGoPlugin(el) { + if (el == null) { + var boxes = document.querySelectorAll('.pluginOverlay'); + for (const b in Object.values(boxes)) { + boxes[b].parentNode.removeChild(boxes[b]); + } + Q('p7').classList.remove('pluginOverlayBg'); + return; + } + var box = document.querySelector('.pluginOverlay').closest(".pluginOverlay"); + box.parentNode.removeChild(box); + Q('p7').classList.remove('pluginOverlayBg'); + } + // 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 putstore(name, val) { diff --git a/webserver.js b/webserver.js index 5409b2ad..6587d915 100644 --- a/webserver.js +++ b/webserver.js @@ -3188,6 +3188,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } }); } + + obj.handlePluginAdminReq = function(req, res) { + const domain = checkUserIpAddress(req, res); + if (domain == null) { res.sendStatus(404); return; } + if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; } + var user = obj.users[req.session.userid]; + if ((user == null) || ((user.siteadmin & 0xFFFFFFFF) == 0)) { res.sendStatus(401); return; } + + parent.pluginHandler.handleAdminReq(req, res, obj); + } + + obj.handlePluginAdminPostReq = function(req, res) { + const domain = checkUserIpAddress(req, res); + if (domain == null) { res.sendStatus(404); return; } + if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; } + var user = obj.users[req.session.userid]; + if ((user == null) || ((user.siteadmin & 0xFFFFFFFF) == 0)) { res.sendStatus(401); return; } + + parent.pluginHandler.handleAdminPostReq(req, res, obj); + } // Starts the HTTPS server, this should be called after the user/mesh tables are loaded function serverStart() { @@ -3311,6 +3331,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.app.get(url + 'logo.png', handleLogoRequest); obj.app.get(url + 'welcome.jpg', handleWelcomeImageRequest); obj.app.ws(url + 'amtactivate', handleAmtActivateWebSocket); + if (parent.pluginHandler != null) { + obj.app.get(url + 'pluginadmin.ashx', obj.handlePluginAdminReq); + obj.app.post(url + 'pluginadmin.ashx', obj.handlePluginAdminPostReq); + } // Server redirects if (parent.config.domains[i].redirects) { for (var j in parent.config.domains[i].redirects) { if (j[0] != '_') { obj.app.get(url + j, obj.handleDomainRedirect); } } }