diff --git a/agents/MeshAgentOSXPackager.zip b/agents/MeshAgentOSXPackager.zip
new file mode 100644
index 00000000..b6c29dfd
Binary files /dev/null and b/agents/MeshAgentOSXPackager.zip differ
diff --git a/package.json b/package.json
index d057d185..fbb1f476 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "meshcentral",
- "version": "0.2.0-f",
+ "version": "0.2.0-h",
"keywords": [
"Remote Management",
"Intel AMT",
diff --git a/public/scripts/amt-0.2.0.js b/public/scripts/amt-0.2.0.js
index e56e1fb0..9fefec20 100644
--- a/public/scripts/amt-0.2.0.js
+++ b/public/scripts/amt-0.2.0.js
@@ -1,5 +1,5 @@
/**
-* @fileoverview Intel(r) AMT Communication StackXX
+* @fileoverview Intel(r) AMT Communication Stack
* @author Ylian Saint-Hilaire
* @version v0.2.0b
*/
diff --git a/views/default.handlebars b/views/default.handlebars
index 0fb56911..4ea5665c 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -1984,7 +1984,8 @@
function addAgentToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid], x = '';
- x += addHtmlValue('Operating System', 'Windows Linux Windows (UnInstall) Linux (UnInstall) ') + '
To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage. ";
@@ -1999,6 +2000,11 @@
x += '';
x += "
";
+ // OSX agent install
+ x += "To remove a mesh agent, download the file below, run it and click \"uninstall\".
";
x += addHtmlValue('Mesh Agent', '
Windows (.exe) ');
@@ -2030,8 +2036,9 @@
var v = Q('aginsSelect').value;
QV('agins_windows', v == 0);
QV('agins_linux', v == 1);
- QV('agins_windows_un', v == 2);
- QV('agins_linux_un', v == 3);
+ QV('agins_osx', v == 2);
+ QV('agins_windows_un', v == 3);
+ QV('agins_linux_un', v == 4);
}
function validateDeviceToMesh() {
@@ -5060,35 +5067,49 @@
function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); }
function p5fileDragDrop(e) {
+ if (xxdialogMode) return;
haltEvent(e);
QV('bigfail', false);
QV('bigok', false);
//QV('p5fileCatchAllInput', false);
- if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
- var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length;
- for (var i = 0; i < e.dataTransfer.files.length; i++) {
- var reader = new FileReader(), file = e.dataTransfer.files[i];
- names.push(file.name);
- sizes.push(file.size);
- types.push(file.type);
- reader.onload = function (event) {
- console.log(event.target.result.length);
- datas.push(event.target.result);
- if (--readercount == 0) {
- Q('p5fileDragName').value = names.join('*');
- Q('p5fileDragSize').value = sizes.join('*');
- Q('p5fileDragType').value = types.join('*');
- Q('p5fileDragData').value = datas.join('*'); // TODO: This will not work for large files!!! *****************
- Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
- Q('p5loginSubmit2').click();
+
+ // For Chrome & Firefox
+ var error = 0;
+ p5uploadFile(); // Display the the dialog box
+ try { Q('p5uploadinput').files = e.dataTransfer.files; } catch (ex) { error = 1; } // Set the files in the dialog box
+ if (error == 0) { p5uploadFileEx(); } // Press the submit button
+ setDialogMode(0); // Close the dialog box
+
+ // For IE browser - This will not work with very large files
+ if (error == 1) {
+ if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
+ var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length, totalSize = 0;
+ for (var i = 0; i < e.dataTransfer.files.length; i++) { totalSize += e.dataTransfer.files[i].size; }
+ if (totalSize > 1300000) { p5uploadFile(); return; } // File is too large, not sure what the real maximum is.
+ for (var i = 0; i < e.dataTransfer.files.length; i++) {
+ var reader = new FileReader(), file = e.dataTransfer.files[i];
+ names.push(file.name);
+ sizes.push(file.size);
+ types.push(file.type);
+ reader.onload = function (event) {
+ datas.push(event.target.result);
+ if (--readercount == 0) {
+ Q('p5fileDragName').value = names.join('*');
+ Q('p5fileDragSize').value = sizes.join('*');
+ Q('p5fileDragType').value = types.join('*');
+ Q('p5fileDragData').value = datas.join('*'); // This will not work for large files, there is a limit on the data size in a field.
+ Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
+ Q('p5loginSubmit2').click();
+ }
}
+ reader.readAsDataURL(file);
}
- reader.readAsDataURL(file);
}
}
var p5dragtimer = null;
function p5fileDragOver(e) {
+ if (xxdialogMode) return;
haltEvent(e);
if (p5dragtimer != null) { clearTimeout(p5dragtimer); p5dragtimer = null; }
var ac = true; // TODO: Set to true if we can accept the file
@@ -5099,6 +5120,7 @@
}
function p5fileDragLeave(e) {
+ if (xxdialogMode) return;
haltEvent(e);
if (e.target.id != "p5filetable") {
QV('bigfail', false);
diff --git a/webserver.js b/webserver.js
index 00e8fe10..2c6040bd 100644
--- a/webserver.js
+++ b/webserver.js
@@ -1630,6 +1630,87 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
return obj.certificates.CommonName;
}
+ // Create a OSX mesh agent installer
+ obj.handleMeshOsxAgentRequest = function (req, res) {
+ var domain = checkUserIpAddress(req, res);
+ if ((domain == null) || (req.query.id == null)) { res.sendStatus(404); return; }
+
+ // If required, check if this user has rights to do this
+ if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true) && (req.session.userid == null)) { res.sendStatus(401); console.log('2'); return; }
+
+ // Send a specific mesh agent back
+ var argentInfo = obj.parent.meshAgentBinaries[req.query.id];
+ if ((argentInfo == null) || (req.query.meshid == null)) { res.sendStatus(404); console.log('3'); return; }
+
+ // We are going to embed the .msh file into the Windows executable (signed or not).
+ // First, fetch the mesh object to build the .msh file
+ var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.meshid];
+ if (mesh == null) { res.sendStatus(401); return; }
+
+ // If required, check if this user has rights to do this
+ if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) {
+ var user = obj.users[req.session.userid];
+ var escUserId = obj.common.escapeFieldName(user._id);
+ if ((user == null) || (mesh.links[escUserId] == null) || ((mesh.links[escUserId].rights & 1) == 0)) { res.sendStatus(401); console.log('4'); return; }
+ if (domain.id != mesh.domain) { res.sendStatus(401); console.log('5'); return; }
+ }
+
+ var meshidhex = new Buffer(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
+ var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
+ var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
+
+ // Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
+ var xdomain = (domain.dns == null) ? domain.id : '';
+ if (xdomain != '') xdomain += "/";
+ var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
+ if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
+ if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
+
+ // Setup the response output
+ var archive = require('archiver')('zip', { level: 5 }); // Sets the compression method.
+ archive.on('error', function (err) { throw err; });
+ res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename=MeshAgent-' + mesh.name + '.zip' });
+ archive.pipe(res);
+
+ // Opens the "MeshAgentOSXPackager.zip"
+ var yauzl = require("yauzl");
+ yauzl.open(obj.path.join(__dirname, 'agents', 'MeshAgentOSXPackager.zip'), { lazyEntries: true }, function (err, zipfile) {
+ if (err) { res.sendStatus(500); return; }
+ zipfile.readEntry();
+ zipfile.on("entry", function (entry) {
+ if (/\/$/.test(entry.fileName)) {
+ // Skip all folder entries
+ zipfile.readEntry();
+ } else {
+ if (entry.fileName == 'Mesh Agent.mpkg/Contents/distribution.dist') {
+ // This is a special file entry, we need to fix it.
+ zipfile.openReadStream(entry, function (err, readStream) {
+ readStream.on("data", function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } });
+ readStream.on("end", function () {
+ var welcomemsg = 'Welcome to the MeshCentral agent for OSX\\\n\\\nThis installer will install the mesh agent for "' + mesh.name + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to info.meshcentral.com.\\\n\\\nThis software is provided under Apache 2.0 license.\\\n';
+ var installsize = Math.floor((argentInfo.size + meshsettings.length) / 1024);
+ archive.append(readStream.xxdata.toString().split('###WELCOMEMSG###').join(welcomemsg).split('###INSTALLSIZE###').join(installsize), { name: entry.fileName });
+ zipfile.readEntry();
+ });
+ });
+ } else {
+ // Normal file entry
+ zipfile.openReadStream(entry, function (err, readStream) {
+ if (err) { throw err; }
+ archive.append(readStream, { name: entry.fileName });
+ readStream.on('end', function () { zipfile.readEntry(); });
+ });
+ }
+ }
+ });
+ zipfile.on("end", function () {
+ archive.file(argentInfo.path, { name: "Mesh Agent.mpkg/Contents/Packages/meshagent.pkg/Contents/MeshAgent" });
+ archive.append(meshsettings, { name: "Mesh Agent.mpkg/Contents/Packages/meshagent.pkg/Contents/MeshAgent.msh" });
+ archive.finalize();
+ });
+ });
+ }
+
// Handle a request to download a mesh settings
obj.handleMeshSettingsRequest = function (req, res) {
var domain = checkUserIpAddress(req, res);
@@ -1722,6 +1803,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.app.ws(url + 'webrelay.ashx', handleRelayWebSocket);
obj.app.ws(url + 'control.ashx', function (ws, req) { try { var domain = checkUserIpAddress(ws, req); if (domain != null) { obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws, req, obj.args, domain); } } catch (e) { console.log(e); } });
obj.app.get(url + 'meshagents', obj.handleMeshAgentRequest);
+ obj.app.get(url + 'meshosxagent', obj.handleMeshOsxAgentRequest);
obj.app.get(url + 'meshsettings', obj.handleMeshSettingsRequest);
obj.app.get(url + 'downloadfile.ashx', handleDownloadFile);
obj.app.post(url + 'uploadfile.ashx', handleUploadFile);