From a3f85bd0423c93e38038f7b649dc73afc4c2b669 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Mon, 22 Mar 2021 18:45:07 -0700 Subject: [PATCH] Started work on Intel AMT Click Once Recovery. --- meshuser.js | 4 ++++ views/default.handlebars | 41 ++++++++++++++++++++++++++++++++++++---- webserver.js | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/meshuser.js b/meshuser.js index 5dadded3..5d5a2f1e 100644 --- a/meshuser.js +++ b/meshuser.js @@ -5492,6 +5492,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } break; } + case 'clickoncerecovery': { + console.log(command); // TODO + break; + } default: { // Unknown user action console.log('Unknown action from user ' + user.name + ': ' + command.action + '.'); diff --git a/views/default.handlebars b/views/default.handlebars index 9bd94e93..cadff5d5 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1169,6 +1169,7 @@
Upload File
+ @@ -6612,6 +6613,7 @@ if (((currentNode.conn & 1) != 0) && ((rights & 131072) != 0)) { count++; y += ''; } // Remote command permission if ((currentNode.conn != 0) && ((rights & 262144) != 0)) { count++; y += ''; } if ((currentNode.conn & 16) != 0) { count++; y += ''; } + if ((getNodeAmtVersion(currentNode) >= 15) && ((currentNode.conn & 6) != 0) && (rights == 0xFFFFFFFF) && ((features & 0x00000400) == 0)) { count++; y += ''; } // CIRA (2) or AMT (4) connected if (((currentNode.conn & 1) != 0) && ((rights & 32768) != 0)) { count++; y += ''; } y += ''; x += addHtmlValue("Operation", y); @@ -6648,12 +6650,32 @@ Q('d2runcmd').focus(); //QE('idx_dlgOkButton', true); } + } else if (op == 107) { + // Intel AMT Click Once Recovery (OCR) + Q('d3localmodeform').action = 'clickoncerecovery.ashx'; + Q('d3auth').value = authCookie; + Q('d3filter').value = '.iso'; + Q('d3attrib').value = currentNode._id; + setDialogMode(3, "Intel® AMT Click Once Recovery", 3, deviceActionClickOnceRecovery); + d3init(); } else { // Power operation meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: parseInt(op) }); } } + function deviceActionClickOnceRecovery() { + var mode = Q('d3uploadMode').value; + if (mode == 1) { + // Boot using local disk image file + Q('d3submit').click(); + } else { + // Boot using server image file + var files = d3getFileSel(); + if (files.length == 1) { meshserver.send({ action: 'clickoncerecovery', nodeids: [ Q('d3attrib').value ], type: 'diskimage', path: d3filetreelocation.join('/') + '/' + files[0] }); } + } + } + function deviceRunCmdsFunctionEx() { var type = 3; try { type = parseInt(Q('d2cmdtype').value); } catch (ex) { } @@ -9664,6 +9686,7 @@ if (xxdialogMode) return; Q('d3localmodeform').action = 'uploadmeshcorefile.ashx'; Q('d3auth').value = authCookie; + Q('d3filter').value = '.js'; Q('d3attrib').value = currentNode._id; setDialogMode(3, "Upload Mesh Agent Core", 3, p15uploadCoreEx2); d3init(); @@ -11323,7 +11346,7 @@ } else { var link = shortname, publiclink = '', loginkey = (urlargs.key)?('&key=' + urlargs.key):''; if (publicfolder) { publiclink = ' '; } - if (f.s > 0) { link = publiclink + ' ' + shortname + ''; } + if (f.s > 0) { link = publiclink + '' + shortname + ''; } h = '
 ' + fdatestr + '' + fsize + '
' + link + '
'; } @@ -13521,6 +13544,7 @@ function d3init() { Q('d3localFile').value = ''; + Q('d3localFile').accept = Q('d3filter').value; d3modechange(); } @@ -13536,7 +13560,7 @@ function d3updatefiles() { if (Q('d3uploadMode').value == 1) return; - var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1; + var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1, publicPath = null; // Navigate to path location, build the paths at the same time var d3filetreelocation2 = [], oldlinkpath = d3filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc'); @@ -13564,10 +13588,17 @@ // Sort the files var filetreexx = p5sort_files(filetreex.f); + // File filter + var fileFilter = Q('d3filter').value + // Display all files and folders at this location for (var i in filetreexx) { // Figure out the name and shortname var f = filetreexx[i], name = f.n, shortname; + + // Filter out files + if ((f.t == 3) && (fileFilter != '') && (f.nx.toLowerCase().endsWith(fileFilter) == false)) { continue; } + shortname = name; if (name.length > 70) { shortname = '' + EscapeHtml(name.substring(0, 70)) + ("..." + ''); } else { shortname = EscapeHtml(name); } name = EscapeHtml(name); @@ -13577,7 +13608,7 @@ if (f.s != null) { fsize = getFileSizeStr(f.s); } var h = ''; - if (f.t < 3) { + if (f.t != 3) { var title = ''; h = ''; } else { @@ -13619,7 +13650,7 @@ drawNotifications(); } - // Set the notification count on the upper right oft he screen + // Set the notification count on the upper right of the screen function setNotificationCount(c) { if (parseInt(Q('notificationCount').innerHTML) == c) return; // If the count did not change, exit now. QH('notificationCount', c); @@ -14727,6 +14758,8 @@ meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } } + + function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); } function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } } function addLink(x, f) { return '' + x + ' '; } function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; } diff --git a/webserver.js b/webserver.js index efda54ef..3e507381 100644 --- a/webserver.js +++ b/webserver.js @@ -3407,6 +3407,45 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { }); } + // Upload a MeshCore.js file to the server + function handleClickOnceRecoveryFile(req, res) { + const domain = checkUserIpAddress(req, res); + if (domain == null) { return; } + if (domain.id !== '') { res.sendStatus(401); return; } + + var authUserid = null; + if ((req.session != null) && (typeof req.session.userid == 'string')) { authUserid = req.session.userid; } + + const multiparty = require('multiparty'); + const form = new multiparty.Form(); + form.parse(req, function (err, fields, files) { + // If an authentication cookie is embedded in the form, use that. + if ((fields != null) && (fields.auth != null) && (fields.auth.length == 1) && (typeof fields.auth[0] == 'string')) { + var loginCookie = obj.parent.decodeCookie(fields.auth[0], obj.parent.loginCookieEncryptionKey, 60); // 60 minute timeout + if ((loginCookie != null) && (obj.args.cookieipcheck !== false) && (loginCookie.ip != null) && (loginCookie.ip != req.clientIp)) { loginCookie = null; } // Check cookie IP binding. + if ((loginCookie != null) && (domain.id == loginCookie.domainid)) { authUserid = loginCookie.userid; } // Use cookie authentication + } + if (authUserid == null) { res.sendStatus(401); return; } + if ((fields == null) || (fields.attrib == null) || (fields.attrib.length != 1)) { res.sendStatus(404); return; } + + // Get the user + const user = obj.users[authUserid]; + if (user == null) { res.sendStatus(401); return; } // Check this user exists + + // Get the node and check node rights + const nodeid = fields.attrib[0]; + obj.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) { + if ((node == null) || (rights != 0xFFFFFFFF) || (visible == false)) { res.sendStatus(404); return; } // We don't have remote control rights to this device + for (var i in files.files) { + var file = files.files[i]; + console.log('ClickOnceRecovery', file); // TODO + try { obj.fs.unlinkSync(file.path); } catch (e) { } + } + res.send(''); + }); + }); + } + // Upload a file to the server function handleUploadFile(req, res) { const domain = checkUserIpAddress(req, res); @@ -5208,6 +5247,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.app.post(url + 'uploadfile.ashx', handleUploadFile); obj.app.post(url + 'uploadfilebatch.ashx', handleUploadFileBatch); obj.app.post(url + 'uploadmeshcorefile.ashx', handleUploadMeshCoreFile); + obj.app.post(url + 'clickoncerecovery.ashx', handleClickOnceRecoveryFile); obj.app.get(url + 'userfiles/*', handleDownloadUserFiles); obj.app.ws(url + 'echo.ashx', handleEchoWebSocket); obj.app.ws(url + 'apf.ashx', function (ws, req) { obj.parent.mpsserver.onWebSocketConnection(ws, req); })