Added Webkit download bug workaround.

Ylian Saint-Hilaire committed Oct 2, 2020 at 13:17 UTC dfe4273baf05da8c5d61a9fac572549287fdfb33
4 files changed +79 -64
meshdevicefile.js
+2 -2
@@ -204,9 +204,9 @@ module.exports.CreateMeshDeviceFile = function (parent, ws, res, req, domain, us
204 if ((cmd == null) || (typeof cmd.op == 'string')) {
205 if (cmd.op == 'ok') {
206 if (typeof cmd.size == 'number') {
207 - this.res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + require('path').basename(this.file) + '"', 'Content-Length': cmd.size });
207 + this.res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + require('path').basename(this.file) + '"', 'Content-Length': cmd.size });
208 } else {
209 - this.res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + require('path').basename(this.file) + '"' });
209 + this.res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + require('path').basename(this.file) + '"' });
210 }
211 } else {
212 try { this.res.sendStatus(401); } catch (ex) { }
redirserver.js
+1 -1
@@ -53,7 +53,7 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
53 obj.app.get('/MeshServerRootCert.cer', function (req, res) {
54 // The redirection server starts before certificates are loaded, make sure to handle the case where no certificate is loaded now.
55 if (obj.certificates != null) {
56 - res.set({ 'Cache-Control': "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", "Content-Type": "application/octet-stream", "Content-Disposition": "attachment; filename=\"" + obj.certificates.RootName + ".cer\"" });
56 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + obj.certificates.RootName + '.cer"' });
57 var rootcert = obj.certificates.root.cert;
58 var i = rootcert.indexOf('-----BEGIN CERTIFICATE-----\r\n');
59 if (i >= 0) { rootcert = rootcert.substring(i + 29); }
views/default.handlebars
+41 -26
@@ -1212,6 +1212,7 @@
1212 <form style="display:none" method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name" /><input id=p5fileDragAuthCookie name="auth" /><input id=p5fileDragSize name="size" /><input id=p5fileDragType name="type" /><input id=p5fileDragData name="data" /><input id=p5fileDragLink name="link" /><input type=submit id=p5loginSubmit2 style="display:none" /></form>
1213 <form style="display:none" method=post action=uploadnodefile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p13fileDragName name="name" /><input id=p13fileDragSize name="size" /><input id=p13fileDragType name="type" /><input id=p13fileDragData name="data" /><input id=p13fileDragLink name="link" /><input type=submit id=p13loginSubmit2 style="display:none" /></form>
1214 <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3" /></audio>
1215 + <iframe style=display:none name="fileDownloadFrame"></iframe>
1216 </div>
1217 <script type="text/javascript" nonce="abc">
1218 'use strict';
@@ -4116,14 +4117,14 @@
4117 // Setup CIRA using a MeshCommander script (Pretty Simple)
4118 x += '<div id=dlgAddCira0>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" with CIRA, download the following script files and use <a href='http://meshcommander.com' rel='noreferrer noopener' target='_blank'>MeshCommander</a> to run the script to configure computers.", EscapeHtml(mesh.name)) + '<br /><br />';
4119 //x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1' + (urlargs.key?('&key=' + urlargs.key):'') + '&meshid=' + meshidx.substring(0, 16) + '" download>cira_setup.mescript</a>');
4119 - x += addHtmlValue("Setup CIRA", '<a href="mescript.ashx?type=1' + (urlargs.key?('&key=' + urlargs.key):'') + '&meshid=' + meshid + '" download>cira_setup.mescript</a>');
4120 - x += addHtmlValue("Cleanup CIRA", '<a href="mescript.ashx?type=2' + (urlargs.key?('&key=' + urlargs.key):'') + '" download>cira_clean.mescript</a>');
4120 + x += addHtmlValue("Setup CIRA", '<a onclick=downloadFile("mescript.ashx?type=1' + (urlargs.key?('&key=' + urlargs.key):'') + '&meshid=' + meshid + '")>cira_setup.mescript</a>');
4121 + x += addHtmlValue("Cleanup CIRA", '<a onclick=downloadFile("mescript.ashx?type=2' + (urlargs.key?('&key=' + urlargs.key):'') + '")>cira_clean.mescript</a>');
4122 x += '</div>';
4123
4124 // Setup CIRA with user/pass authentication (Somewhat difficult)
4125 x += '<div id=dlgAddCira1 style=display:none>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" with CIRA, load the following certificate as trusted root within Intel&reg; AMT", EscapeHtml(mesh.name));
4126 if (serverinfo.mpspass) { x += (" and authenticate to the server using this username and password." + '<br /><br />'); } else { x += (" and authenticate to the server using this username and any password." + '<br /><br />'); }
4126 - x += addHtmlValue("Root Certificate", '<a href="' + "MeshServerRootCert.cer" + (urlargs.key?('?key=' + urlargs.key):'') + '" download>' + "Root Certificate File" + '</a>');
4127 + x += addHtmlValue("Root Certificate", '<a onclick=downloadFile("' + "MeshServerRootCert.cer" + (urlargs.key?('?key=' + urlargs.key):'') + '")>' + "Root Certificate File" + '</a>');
4128 x += addHtmlValue("Username", '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
4129 if (serverinfo.mpspass) { x += addHtmlValue("Password", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
4130 if (serverinfo != null) { x += addHtmlValue("MPS Server", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
@@ -4132,7 +4133,7 @@
4133 // Setup CIRA with certificate authentication (Really difficult, only if TLS offload is not used)
4134 if ((features & 16) == 0) {
4135 x += '<div id=dlgAddCira2 style=display:none>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" with CIRA, load the following certificate as trusted root within Intel&reg; AMT, authenticate using a client certificate with the following common name and connect to the following server.", EscapeHtml(mesh.name)) + '<br /><br />';
4135 - x += addHtmlValue("Root Certificate", '<a href="' + "MeshServerRootCert.cer" + (urlargs.key?('?key=' + urlargs.key):'') + '" download>' + "Root Certificate File" + '</a>');
4136 + x += addHtmlValue("Root Certificate", '<a onclick=downloadFile("' + "MeshServerRootCert.cer" + (urlargs.key?('?key=' + urlargs.key):'') + '")>' + "Root Certificate File" + '</a>');
4137 x += addHtmlValue("Organization", '<input style=width:230px readonly value="' + meshidx + '" />');
4138 if (serverinfo != null) { x += addHtmlValue("MPS Server", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
4139 x += '</div>';
@@ -4242,9 +4243,9 @@
4243
4244 // Windows agent install
4245 x += '<div id=agins_windows>' + format("To add a new computer to device group \"{0}\", download the mesh agent and install it the computer to manage. This agent has server and device group information embedded within it.", EscapeHtml(mesh.name)) + '<br /><br />';
4245 - x += addHtmlValue("Mesh Agent", '<a id=aginsw32lnk href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" download onclick="setDialogMode(0)" title="' + "32bit version of the MeshAgent" + '">' + "Windows (.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy Windows 32bit agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
4246 - x += addHtmlValue("Mesh Agent", '<a id=aginsw64lnk href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" download onclick="setDialogMode(0)" title="' + "64bit version of the MeshAgent" + '">' + "Windows x64 (.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy Windows 64bit agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
4247 - if (debugmode > 0) { x += addHtmlValue("Settings File", '<a id=aginswmshlnk href="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" download rel="noreferrer noopener" target="_blank">' + format("{0} settings (.msh)", EscapeHtml(mesh.name)) + '</a>'); }
4246 + x += addHtmlValue("Mesh Agent", '<a id=aginsw32lnk name="meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" title="' + "32bit version of the MeshAgent" + '">' + "Windows (.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy Windows 32bit agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
4247 + x += addHtmlValue("Mesh Agent", '<a id=aginsw64lnk name="meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" title="' + "64bit version of the MeshAgent" + '">' + "Windows x64 (.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy Windows 64bit agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
4248 + if (debugmode > 0) { x += addHtmlValue("Settings File", '<a id=aginswmshlnk name="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '">' + format("{0} settings (.msh)", EscapeHtml(mesh.name)) + '</a>'); }
4249 x += '</div>';
4250
4251 // Linux agent install
@@ -4254,13 +4255,13 @@
4255
4256 // macOS agent install
4257 x += '<div id=agins_osx style=display:none>' + format("To add a new computer to device group \"{0}\", download the mesh agent and install it the computer to manage. This agent installer has server and device group information embedded within it.", EscapeHtml(mesh.name)) + '<br /><br />';
4257 - x += addHtmlValue("Mesh Agent", '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + (urlargs.key?('&key=' + urlargs.key):'') + '" download rel="noreferrer noopener" target="_blank" title="' + "64bit version of macOS Mesh Agent" + '">macOS Agent (64bit)</a> <img src=images/link4.png height=10 width=10 title="' + "Copy macOS agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '",0)>');
4258 + x += addHtmlValue("Mesh Agent", '<a onclick=downloadFile("meshosxagent?id=16&meshid=' + meshid.split('/')[2] + (urlargs.key?('&key=' + urlargs.key):'') + '") title="' + "64bit version of macOS Mesh Agent" + '">macOS Agent (64bit)</a> <img src=images/link4.png height=10 width=10 title="' + "Copy macOS agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '",0)>');
4259 x += '</div>';
4260
4261 // Windows agent uninstall
4262 x += '<div id=agins_windows_un style=display:none>' + "To remove a mesh agent, download the file below, run it and click \"uninstall\"." + '<br /><br />';
4262 - x += addHtmlValue("Mesh Agent", '<a href="meshagents?id=3' + (urlargs.key?('&key=' + urlargs.key):'') + '" download onclick="setDialogMode(0)" title="' + "32bit version of the MeshAgent" + '">' + "Windows (.exe)" + '</a>');
4263 - x += addHtmlValue("Mesh Agent", '<a href="meshagents?id=4' + (urlargs.key?('&key=' + urlargs.key):'') + '" download onclick="setDialogMode(0)" title="' + "64bit version of the MeshAgent" + '">' + "Windows x64 (.exe)" + '</a>');
4263 + x += addHtmlValue("Mesh Agent", '<a onclick=downloadFile("meshagents?id=3' + (urlargs.key?('&key=' + urlargs.key):'') + '",null,true) title="' + "32bit version of the MeshAgent" + '">' + "Windows (.exe)" + '</a>');
4264 + x += addHtmlValue("Mesh Agent", '<a onclick=downloadFile("meshagents?id=4' + (urlargs.key?('&key=' + urlargs.key):'') + '",null,true) title="' + "64bit version of the MeshAgent" + '">' + "Windows x64 (.exe)" + '</a>');
4265 x += '</div>';
4266
4267 // Linux agent uninstall
@@ -4270,7 +4271,7 @@
4271
4272 // Linux binary installer
4273 x += '<div id=agins_linux_inst style=display:none>' + "This is a executable on OS's with graphical user interfaces. You need to 'chmod +x meshagent' and run this file." + '<br /><br />';
4273 - x += addHtmlValue("Mesh Agent", '<a id=aginsbinlnk href="meshagents?id=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '" download onclick="setDialogMode(0)">' + "meshagent" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=' + meshid.split('/')[2] + '&installflags=",1)>');
4274 + x += addHtmlValue("Mesh Agent", '<a id=aginsbinlnk name="meshagents?id=' + meshid.split('/')[2] + '&installflags=0' + (urlargs.key?('&key=' + urlargs.key):'') + '">' + "meshagent" + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=' + meshid.split('/')[2] + '&installflags=",1)>');
4275 x += addHtmlValue("Command", '<input id=aginsbincmd type=text style="width:216px" readonly value=\'wget -O meshagent' + (((features & 0x80000000) != 0)?' --no-check-certificate':'') + ' \"https://' + servername + portStr + domainUrl + 'meshagents?id=' + meshid.split('/')[2].split('$').join('%24').split('@').join('%40') + '\' /> <img src=images/link4.png height=10 width=10 title="' + "Copy agent URL to clipboard" + '" style=cursor:pointer onclick=copyAgentIdValue("aginsbincmd")>');
4276 x += '</div>';
4277
@@ -4312,7 +4313,6 @@
4313 function copyAgentIdValue(id) { copyTextToClip(Q(id).value); }
4314
4315 function copyAgentUrl(url,addflag) {
4315 - console.log('copyAgentUrl', url, addflag);
4316 var servername = serverinfo.name;
4317 if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
4318 var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
@@ -4333,14 +4333,14 @@
4333 QV('agins_linux_un', v == 4);
4334 QV('agins_linux_inst', v == 5);
4335 QV('aginsSysTypeDiv', v == 5);
4336 - Q('aginsbinlnk').href = (Q('aginsbinlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):'') + '&meshinstall=' + Q('aginsSysType').value;
4336 + Q('aginsbinlnk').onclick = function() { downloadFile((Q('aginsbinlnk').name.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):'') + '&meshinstall=' + Q('aginsSysType').value); };
4337 Q('aginsbincmd').value = (Q('aginsbincmd').value.split('&installflags=')[0]) + '&installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):'') + '&meshinstall=' + Q('aginsSysType').value + '\"';
4338 QV('aginsTypeDiv', (v == 0) || (v == 5));
4339
4340 // Fix the links if needed
4341 - Q('aginsw32lnk').href = (Q('aginsw32lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):'');
4342 - Q('aginsw64lnk').href = (Q('aginsw64lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):'');
4343 - if (debugmode > 0) { Q('aginswmshlnk').href = (Q('aginswmshlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):''); }
4341 + Q('aginsw32lnk').onclick = function() { downloadFile((Q('aginsw32lnk').name.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):''), null, true); }
4342 + Q('aginsw64lnk').onclick = function() { downloadFile((Q('aginsw64lnk').name.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):''), null, true); }
4343 + if (debugmode > 0) { Q('aginswmshlnk').onclick = function() { downloadFile((Q('aginswmshlnk').name.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value + (urlargs.key?('&key=' + urlargs.key):''), null, true); } }
4344 }
4345
4346 function validateDeviceToMesh() {
@@ -6206,7 +6206,7 @@
6206 date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
6207 }
6208
6209 - QH('p10html2', '<table cellpadding=2 cellspacing=0><thead><tr style=><th scope=col style=text-align:center;width:150px>' + "Day" + '</th><th scope=col style=text-align:center><a download href="devicepowerevents.ashx?id=' + currentNode._id + (urlargs.key?('&key=' + urlargs.key):'') + '" onclick="setDialogMode(0)"><img title="' + "Download power events" + '" src="images/link4.png" /></a>' + "7 Day Power State" + '</th></tr></thead><tbody>' + x + '</tbody></table>');
6209 + QH('p10html2', '<table cellpadding=2 cellspacing=0><thead><tr style=><th scope=col style=text-align:center;width:150px>' + "Day" + '</th><th scope=col style=text-align:center><a onclick=downloadFile("devicepowerevents.ashx?id=' + currentNode._id + (urlargs.key?('&key=' + urlargs.key):'') + '",null,true)><img title="' + "Download power events" + '" src="images/link4.png" /></a>' + "7 Day Power State" + '</th></tr></thead><tbody>' + x + '</tbody></table>');
6210 }
6211
6212 // Return a color for the given power state
@@ -6410,7 +6410,7 @@
6410 function p10showMeshRouterDialog() {
6411 if (xxdialogMode) return;
6412 var x = '<div>' + "MeshCentral Router is a Windows tool for TCP port mapping. You can, for example, RDP into a remote device thru this server." + '</div><br />';
6413 - x += addHtmlValue("Win32 Executable", '<a style=cursor:pointer download href="meshagents?meshaction=winrouter' + (urlargs.key?('&key=' + urlargs.key):'') + '" onclick="setDialogMode(0)">MeshCentralRouter.exe</a>');
6413 + x += addHtmlValue("Win32 Executable", '<a style=cursor:pointer onclick=downloadFile("meshagents?meshaction=winrouter' + (urlargs.key?('&key=' + urlargs.key):'') + '",null,true)>MeshCentralRouter.exe</a>');
6414 var servername = serverinfo.name;
6415 if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
6416 var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
@@ -6419,7 +6419,7 @@
6419 //x += addHtmlValue("Launch", '<a style=cursor:pointer target="mcrouterframe" rel="noreferrer noopener" download href="' + url + '">Start MeshCentral Router</a>');
6420 //x += '<br /><div style=width:100%><a style=cursor:pointer target="mcrouterframe" rel="noreferrer noopener" download href="' + url + '">' + "Start MeshCentral Router" + '</a>' + ", for this link to work you must download MeshCentral Router run it and click the install button." + '</div>';
6421 x += '<br /><div>' + "Run MeshCentral Router and click \"install\" to make it launchable from the browser." + '</div>';
6422 - x += '<br /><a style=cursor:pointer target="mcrouterframe" rel="noreferrer noopener" download href="' + url + '"><input type=button style=width:100%;cursor:pointer value="' + "Launch MeshCentral Router" + '" /></a>';
6422 + x += '<br /><a style=cursor:pointer target="mcrouterframe" rel="noreferrer noopener" href="' + url + '"><input type=button style=width:100%;cursor:pointer value="' + "Launch MeshCentral Router" + '" /></a>';
6423 x += '<iframe style=display:none name="mcrouterframe"></iframe>';
6424 setDialogMode(2, "MeshCentral Router", 1, null, x, 'fileDownload');
6425 }
@@ -6454,9 +6454,9 @@
6454 if (mode == 0) { x += '<div>' + "MeshCmd is a command line tool that performs lots of different operations. The action file can optionally be downloaded and edited to provide server information and credentials." + '<br /><br />'; }
6455 if (mode == 1) { x += '<div>' + "Download \"meshcmd\" with an action file to route traffic thru this server to this device. Make sure to edit meshaction.txt and add your account password or make any changes needed." + '<br /><br />'; }
6456 x += addHtmlValue("Operating System", y);
6457 - x += addHtmlValue("MeshCmd", '<a id=meshcmddownloadid href="meshagents?meshcmd=3' + (urlargs.key?('&key=' + urlargs.key):'') + '" download></a>');
6458 - if (mode == 0) { x += addHtmlValue("Action File", '<a href="meshagents?meshaction=generic' + (urlargs.key?('&key=' + urlargs.key):'') + '" download>' + "MeshAction (.txt)" + '</a>'); }
6459 - if (mode == 1) { x += addHtmlValue("Action File", '<a href="meshagents?meshaction=route&nodeid=' + nodeid + (urlargs.key?('&key=' + urlargs.key):'') + '" download>' + "MeshAction (.txt)" + '</a>'); }
6457 + x += addHtmlValue("MeshCmd", '<a id=meshcmddownloadid onclick=downloadFile("meshagents?meshcmd=3' + (urlargs.key?('&key=' + urlargs.key):'') + '")></a>');
6458 + if (mode == 0) { x += addHtmlValue("Action File", '<a onclick=downloadFile("meshagents?meshaction=generic' + (urlargs.key?('&key=' + urlargs.key):'') + '")>' + "MeshAction (.txt)" + '</a>'); }
6459 + if (mode == 1) { x += addHtmlValue("Action File", '<a onclick=downloadFile("meshagents?meshaction=route&nodeid=' + nodeid + (urlargs.key?('&key=' + urlargs.key):'') + '")>' + "MeshAction (.txt)" + '</a>'); }
6460 x += '</div>';
6461 setDialogMode(2, "Download MeshCmd", 9, null, x, 'fileDownload');
6462 meshCmdOsClick();
@@ -7949,7 +7949,9 @@
7949 // Local link
7950 //link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>';
7951 // Server link
7952 - link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download style=cursor:pointer">' + shortname + '</a>';
7952 + //link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download="' + name + '" style=cursor:pointer>' + shortname + '</a>';
7953 + // Server link
7954 + link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + name + '") style=cursor:pointer>' + shortname + '</a>';
7955 }
7956 h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7957 }
@@ -10367,7 +10369,7 @@
10369 } else {
10370 var link = shortname, publiclink = '';
10371 if (publicfolder) { publiclink = '<img src="images/link2.png" style=cursor:pointer title="' + "Display public link" + '" onclick=\'return p5showPublicLink("' + (publicPath + '/' + encodeURIComponentEx(f.nx)) + '?download=1' + '")\' width=10 height=10 /> <img src="images/link4.png" title="' + "Copy link to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(publicPath + '/' + encodeURIComponentEx(f.nx) + '?download=1') + '") width=10 height=10>'; }
10370 - if (f.s > 0) { link = publiclink + ' <a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponentEx(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>'; }
10372 + if (f.s > 0) { link = publiclink + ' <a onclick=downloadFile("downloadfile.ashx?link=' + encodeURIComponentEx(filetreelinkpath + '/' + f.nx) + '")>' + shortname + '</a>'; }
10373 h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
10374 }
10375
@@ -12445,7 +12447,7 @@
12447 }
12448 }
12449 var actions = '', icon = 'm0';
12448 - if (rec.present == 1) { icon = 'm1'; actions = '<div style=cursor:pointer;float:right><a href=recordings.ashx?file=' + encodeURIComponentEx(rec.filename) + ' download><img src=images/link4.png height=10 width=10 title="Download Recording" download></a>&nbsp;</div>'; }
12450 + if (rec.present == 1) { icon = 'm1'; actions = '<div style=cursor:pointer;float:right><a onclick=downloadFile("recordings.ashx?file=' + encodeURIComponentEx(rec.filename) + '")><img src=images/link4.png height=10 width=10 title="Download Recording"></a>&nbsp;</div>'; }
12451 var x = '<tr tabindex=0 onmouseover=userMouseHover2(this,1) onmouseout=userMouseHover2(this,0) onkeypress="if (event.key==\'Enter\') showRecordingDialog(event,\'' + i + '\')"><td style=cursor:pointer>';
12452 x += '<div class=bar style=width:100%>';
12453 //x += '<div class=baricon><input class=RecordingCheckbox value="' + encodeURIComponentEx(rec.filename) + '" onclick=p52updateInfo() type=checkbox></div>';
@@ -13619,6 +13621,19 @@
13621 function round(value, precision) { var multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; }
13622 function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
13623
13624 + // Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
13625 + // So we do that for all browsers except FireFox
13626 + function downloadFile(link, name, closeDialog) {
13627 + var element = document.createElement('a');
13628 + element.setAttribute('href', link);
13629 + element.setAttribute('rel', 'noreferrer noopener');
13630 + if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', name?name:''); } else { element.setAttribute('target', 'fileDownloadFrame'); }
13631 + document.body.appendChild(element);
13632 + element.click();
13633 + document.body.removeChild(element);
13634 + if (closeDialog) { setDialogMode(0); }
13635 + }
13636 +
13637 </script>
13638 </body>
13624 -</html>
13639 +</html>
\ No newline at end of file
webserver.js
+35 -35
@@ -675,7 +675,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
675 if (domain.auth == 'sspi') { parent.debug('web', 'handleLogoutRequest: failed checks.'); res.sendStatus(404); return; }
676 if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
677
678 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
678 + res.set({ 'Cache-Control': 'no-store' });
679 // Destroy the user's session to log them out will be re-created next request
680 if (req.session.userid) {
681 var user = obj.users[req.session.userid];
@@ -2134,7 +2134,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2134
2135 function handleRootRequestEx(req, res, domain, direct) {
2136 var nologout = false, user = null, features = 0;
2137 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2137 + res.set({ 'Cache-Control': 'no-store' });
2138
2139 // Check if we have an incomplete domain name in the path
2140 if ((domain.id != '') && (domain.dns == null) && (req.url.split('/').length == 2)) {
@@ -2557,7 +2557,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2557 if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
2558
2559 parent.debug('web', 'handleXTermRequest: sending xterm');
2560 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2560 + res.set({ 'Cache-Control': 'no-store' });
2561 if (req.session && req.session.userid) {
2562 if (req.session.domainid != domain.id) { res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2563 var user = obj.users[req.session.userid];
@@ -2592,7 +2592,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2592 // See if term.txt was loaded from the database
2593 if ((parent.configurationFiles != null) && (parent.configurationFiles['terms.txt'] != null)) {
2594 // Send the terms from the database
2595 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2595 + res.set({ 'Cache-Control': 'no-store' });
2596 if (req.session && req.session.userid) {
2597 if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2598 var user = obj.users[req.session.userid];
@@ -2611,7 +2611,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2611 if (err != null) { parent.debug('web', 'handleTermsRequest: no terms.txt'); res.sendStatus(404); return; }
2612
2613 // Send the terms from terms.txt
2614 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2614 + res.set({ 'Cache-Control': 'no-store' });
2615 if (req.session && req.session.userid) {
2616 if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2617 var user = obj.users[req.session.userid];
@@ -2626,7 +2626,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2626 } else {
2627 // Send the default terms
2628 parent.debug('web', 'handleTermsRequest: sending default terms');
2629 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2629 + res.set({ 'Cache-Control': 'no-store' });
2630 if (req.session && req.session.userid) {
2631 if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
2632 var user = obj.users[req.session.userid];
@@ -2649,7 +2649,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2649
2650 var webRtcConfig = null;
2651 if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)).replace(/'/g, '%27'); }
2652 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2652 + res.set({ 'Cache-Control': 'no-store' });
2653 render(req, res, getRenderPage('messenger', req, domain), getRenderArgs({ webrtconfig: webRtcConfig }, req, domain));
2654 }
2655
@@ -2671,9 +2671,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2671 if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { parent.debug('web', 'handleRootCertRequest: invalid ip'); return; } // Check server-wide IP filter only.
2672 parent.debug('web', 'handleRootCertRequest()');
2673 try {
2674 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + certificates.RootName + '.cer"' });
2674 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + certificates.RootName + '.cer"' });
2675 } catch (ex) {
2676 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="rootcert.cer"' });
2676 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="rootcert.cer"' });
2677 }
2678 res.send(Buffer.from(getRootCertBase64(), 'base64'));
2679 }
@@ -2779,9 +2779,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2779 if (script == null) { res.sendStatus(404); } else {
2780 try {
2781 var cirafilename = obj.meshes[req.query.meshid].name.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join('');
2782 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_setup_' + cirafilename + '.mescript"' });
2782 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_setup_' + cirafilename + '.mescript"' });
2783 } catch (ex) {
2784 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_setup.mescript"' });
2784 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_setup.mescript"' });
2785 }
2786 res.send(script);
2787 }
@@ -2790,7 +2790,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2790 // Get the CIRA cleanup script
2791 obj.getCiraCleanupScript(function (script) {
2792 if (script == null) { res.sendStatus(404); } else {
2793 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_cleanup.mescript"' });
2793 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="cira_cleanup.mescript"' });
2794 res.send(script);
2795 }
2796 });
@@ -2817,9 +2817,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2817 if ((stat != null) && ((stat.mode & 0x004000) == 0)) {
2818 if (req.query.download == 1) {
2819 try {
2820 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + filename + '\"' });
2820 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + filename + '\"' });
2821 } catch (ex) {
2822 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"file.bin\"' });
2822 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"file.bin\"' });
2823 }
2824 try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); }
2825 } else {
@@ -3035,7 +3035,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3035 if ((user.siteadmin & 512) == 0) { res.sendStatus(401); return; } // Check if we have right to get recordings
3036
3037 // Send the recorded file
3038 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + req.query.file + '\"' });
3038 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + req.query.file + '\"' });
3039 try { res.sendFile(obj.path.join(recordingsPath, req.query.file)); } catch (ex) { res.sendStatus(404); }
3040 }
3041
@@ -3045,7 +3045,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3045 if (domain == null) { return; }
3046
3047 parent.debug('web', 'handlePlayerRequest: sending player');
3048 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
3048 + res.set({ 'Cache-Control': 'no-store' });
3049 render(req, res, getRenderPage('player', req, domain), getRenderArgs({}, req, domain));
3050 }
3051
@@ -3066,7 +3066,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3066 // Lets respond by sending out the desktop viewer.
3067 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
3068 parent.debug('web', 'handleDesktopRequest: Sending guest desktop page for \"' + c.uid + '\", guest \"' + c.gn + '\".');
3069 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
3069 + res.set({ 'Cache-Control': 'no-store' });
3070 render(req, res, getRenderPage('desktop', req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: '', domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), nodeid: c.nid, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, expire: c.expire }, req, domain));
3071 }
3072
@@ -3131,9 +3131,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3131 const file = obj.getServerFilePath(user, domain, req.query.link);
3132 if (file == null) { res.sendStatus(404); return; }
3133 try {
3134 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + file.name + '\"' });
3134 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + file.name + '\"' });
3135 } catch (ex) {
3136 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"file.bin\"' });
3136 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"file.bin\"' });
3137 }
3138 obj.fs.exists(file.fullpath, function (exists) { if (exists == true) { res.sendFile(file.fullpath); } else { res.sendStatus(404); } });
3139 }
@@ -4144,7 +4144,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4144 for (var i in meshsettingslines) { tokens = meshsettingslines[i].split('='); if (tokens.length == 2) { msh[tokens[0]] = tokens[1]; } }
4145 var js = scriptInfo.data.replace('var msh = {};', 'var msh = ' + JSON.stringify(msh) + ';');
4146
4147 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshagent"' });
4147 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshagent"' });
4148 res.statusCode = 200;
4149 obj.parent.exeHandler.streamExeWithJavaScript({ platform: argentInfo.platform, sourceFileName: argentInfo.path, destinationStream: res, js: Buffer.from(js, 'utf8'), peinfo: argentInfo.pe });
4150 } else if (req.query.id != null) {
@@ -4152,7 +4152,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4152 var argentInfo = obj.parent.meshAgentBinaries[req.query.id];
4153 if (argentInfo == null) { res.sendStatus(404); return; }
4154 if ((req.query.meshid == null) || (argentInfo.platform != 'win32')) {
4155 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + argentInfo.rname + '"' });
4155 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + argentInfo.rname + '"' });
4156 if (argentInfo.data == null) { res.sendFile(argentInfo.path); } else { res.end(argentInfo.data); }
4157 } else {
4158 // Check if the meshid is a time limited, encrypted cookie
@@ -4199,9 +4199,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4199 if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
4200
4201 try {
4202 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + meshfilename + '"' });
4202 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + meshfilename + '"' });
4203 } catch (ex) {
4204 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + argentInfo.rname + '"' });
4204 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + argentInfo.rname + '"' });
4205 }
4206 obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe });
4207 }
@@ -4211,7 +4211,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4211 // Send a specific mesh install script back
4212 var scriptInfo = obj.parent.meshAgentInstallScripts[req.query.script];
4213 if (scriptInfo == null) { res.sendStatus(404); return; }
4214 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="' + scriptInfo.rname + '"' });
4214 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="' + scriptInfo.rname + '"' });
4215 var data = scriptInfo.data;
4216 var cmdoptions = { wgetoptionshttp: '', wgetoptionshttps: '', curloptionshttp: '-L ', curloptionshttps: '-L ' }
4217 if (obj.isTrustedCert(domain) != true) {
@@ -4235,17 +4235,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4235 if ((agentid == 3)) { // Signed Windows MeshCmd.exe x86
4236 var stats = null, meshCmdPath = obj.path.join(__dirname, 'agents', 'MeshCmd-signed.exe');
4237 try { stats = obj.fs.statSync(meshCmdPath); } catch (e) { }
4238 - if ((stats != null)) { res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 3) ? '.exe' : '') + '"' }); res.sendFile(meshCmdPath); return; }
4238 + if ((stats != null)) { res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 3) ? '.exe' : '') + '"' }); res.sendFile(meshCmdPath); return; }
4239 } else if ((agentid == 4)) { // Signed Windows MeshCmd64.exe x64
4240 var stats = null, meshCmd64Path = obj.path.join(__dirname, 'agents', 'MeshCmd64-signed.exe');
4241 try { stats = obj.fs.statSync(meshCmd64Path); } catch (e) { }
4242 - if ((stats != null)) { res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') + '"' }); res.sendFile(meshCmd64Path); return; }
4242 + if ((stats != null)) { res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') + '"' }); res.sendFile(meshCmd64Path); return; }
4243 }
4244 // No signed agents, we are going to merge a new MeshCmd.
4245 if ((agentid < 10000) && (obj.parent.meshAgentBinaries[agentid + 10000] != null)) { agentid += 10000; } // Avoid merging javascript to a signed mesh agent.
4246 var argentInfo = obj.parent.meshAgentBinaries[agentid];
4247 if ((argentInfo == null) || (obj.parent.defaultMeshCmd == null)) { res.sendStatus(404); return; }
4248 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') + '"' });
4248 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') + '"' });
4249 res.statusCode = 200;
4250 if (argentInfo.signedMeshCmdPath != null) {
4251 // If we have a pre-signed MeshCmd, send that.
@@ -4281,7 +4281,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4281 if (req.query.key != null) { meshaction.loginKey = req.query.key; }
4282 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4283 if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4284 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="meshaction.txt"' });
4284 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="meshaction.txt"' });
4285 res.send(JSON.stringify(meshaction, null, ' '));
4286 });
4287 } else if (req.query.meshaction == 'generic') {
@@ -4296,12 +4296,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4296 if (req.query.key != null) { meshaction.loginKey = req.query.key; }
4297 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4298 if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4299 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="meshaction.txt"' });
4299 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="meshaction.txt"' });
4300 res.send(JSON.stringify(meshaction, null, ' '));
4301 } else if (req.query.meshaction == 'winrouter') {
4302 var p = obj.path.join(__dirname, 'agents', 'MeshCentralRouter.exe');
4303 if (obj.fs.existsSync(p)) {
4304 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="MeshCentralRouter.exe"' });
4304 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="MeshCentralRouter.exe"' });
4305 try { res.sendFile(p); } catch (e) { res.sendStatus(404); }
4306 } else { res.sendStatus(404); }
4307 } else {
@@ -4324,7 +4324,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4324 // Download a dump file
4325 var dumpFile = obj.path.join(parent.datapath, '..', 'meshcentral-coredumps', req.query.dldump);
4326 if (obj.fs.existsSync(dumpFile)) {
4327 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename="' + req.query.dldump + '' });
4327 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename="' + req.query.dldump + '' });
4328 res.sendFile(dumpFile); return;
4329 } else {
4330 res.sendStatus(404); return;
@@ -4464,10 +4464,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4464 archive.on('error', function (err) { throw err; });
4465 try {
4466 // Set the agent download including the mesh name.
4467 - 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"' });
4467 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename="MeshAgent-' + mesh.name + '.zip"' });
4468 } catch (ex) {
4469 // If the mesh name contains invalid characters, just use a generic name.
4470 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename="MeshAgent.zip"' });
4470 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/zip', 'Content-Disposition': 'attachment; filename="MeshAgent.zip"' });
4471 }
4472 archive.pipe(res);
4473
@@ -4566,7 +4566,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4566 var meshsettings = getMshFromRequest(req, res, domain);
4567 if (meshsettings == null) { res.sendStatus(401); return; }
4568
4569 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshagent.msh"' });
4569 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshagent.msh"' });
4570 res.send(meshsettings);
4571 };
4572
@@ -4590,7 +4590,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4590 if (obj.GetNodeRights(user, node.meshid, node._id) == 0) { res.sendStatus(401); return; }
4591
4592 // Get the list of power events and send them
4593 - res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="powerevents.csv"' });
4593 + res.set({ 'Cache-Control': 'no-store', 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="powerevents.csv"' });
4594 obj.db.getPowerTimeline(node._id, function (err, docs) {
4595 var xevents = ['Time, State, Previous State'], prevState = 0;
4596 for (var i in docs) {