Fixed server files upload/download
Ylian Saint-Hilaire committed
Nov 30, 2017 at 14:40 UTC
e740045b39545e170a5f89179e001f3f8b64ac9f
6 files changed
+57
-47
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_pi
Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ
meshuser.js
+3
-36
@@ -165,7 +165,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
165
var rootfolder = command.path[0];
166
var rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
167
if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
168
- var path = obj.path.join(obj.filespath, domainx + "/" + rootfoldersplit[0] + "-" + rootfoldersplit[2]);
168
+ var path = obj.parent.path.join(obj.parent.filespath, domainx, rootfoldersplit[0] + "-" + rootfoldersplit[2]);
169
for (var i = 1; i < command.path.length; i++) { if (obj.common.IsFilenameValid(command.path[i]) == false) { path = null; break; } path += ("/" + command.path[i]); }
170
if (path == null) break;
171
@@ -833,39 +833,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
833
}
834
} catch (e) { console.log(e); }
835
836
- // Return the maximum number of bytes allowed in the user account "My Files".
837
- function getQuota(objid, domain) {
838
- if (objid == null) return 0;
839
- if (objid.startsWith('user/')) {
840
- var user = obj.parent.users[objid];
841
- if (user == null) return 0;
842
- if ((user.quota != null) && (typeof user.quota == 'number')) { return user.quota; }
843
- if ((domain != null) && (domain.userQuota != null) && (typeof domain.userQuota == 'number')) { return domain.userQuota; }
844
- return 1048576; // By default, the server will have a 1 meg limit on user accounts
845
- } else if (objid.startsWith('mesh/')) {
846
- var mesh = obj.parent.meshes[objid];
847
- if (mesh == null) return 0;
848
- if ((mesh.quota != null) && (typeof mesh.quota == 'number')) { return mesh.quota; }
849
- if ((domain != null) && (domain.meshQuota != null) && (typeof domain.meshQuota == 'number')) { return domain.meshQuota; }
850
- return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
851
- }
852
- return 0;
853
- }
854
-
855
- // Take a "user/domain/userid/path/file" format and return the actual server disk file path if access is allowed
856
- function getServerFilePath(user, domain, path) {
857
- var splitpath = path.split('/'), serverpath = obj.path.join(obj.filespath, 'domain'), filename = '';
858
- if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
859
- var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
860
- if (splitpath[0] == 'user' && (objid != user._id)) return null; // User validation, only self allowed
861
- if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == null) || (link.rights == null) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
862
- if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
863
- serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
864
- for (var i = 3; i < splitpath.length; i++) { if (obj.common.IsFilenameValid(splitpath[i]) == true) { serverpath += '/' + splitpath[i]; filename = splitpath[i]; } else { return null; } } // Check that each folder is correct
865
- var fullpath = obj.path.resolve(obj.filespath, serverpath), quota = 0;
866
- return { fullpath: fullpath, path: serverpath, name: filename, quota: getQuota(objid, domain) };
867
- }
868
-
836
// Read the folder and all sub-folders and serialize that into json.
837
function readFilesRec(path) {
838
var r = {}, dir = obj.fs.readdirSync(path);
@@ -884,7 +851,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
851
852
// Add user files
853
files.filetree.f[user._id] = { t: 1, n: 'My Files', f: {} };
887
- files.filetree.f[user._id].maxbytes = getQuota(user._id, domain);
854
+ files.filetree.f[user._id].maxbytes = obj.parent.getQuota(user._id, domain);
855
var usersplit = user._id.split('/'), domainx = 'domain';
856
if (usersplit[1].length > 0) domainx = 'domain-' + usersplit[1];
857
@@ -907,7 +874,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
874
if (mesh) {
875
var meshsplit = mesh._id.split('/');
876
files.filetree.f[mesh._id] = { t: 1, n: mesh.name, f: {} };
910
- files.filetree.f[mesh._id].maxbytes = getQuota(mesh._id, domain);
877
+ files.filetree.f[mesh._id].maxbytes = obj.parent.getQuota(mesh._id, domain);
878
879
// Read all files recursively
880
try {
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.0-k",
3
+ "version": "0.1.0-l",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
webserver.js
+53
-10
@@ -599,6 +599,39 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
599
}
600
}
601
602
+ // Take a "user/domain/userid/path/file" format and return the actual server disk file path if access is allowed
603
+ obj.getServerFilePath = function(user, domain, path) {
604
+ var splitpath = path.split('/'), serverpath = obj.path.join(obj.filespath, 'domain'), filename = '';
605
+ if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
606
+ var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
607
+ if (splitpath[0] == 'user' && (objid != user._id)) return null; // User validation, only self allowed
608
+ if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == null) || (link.rights == null) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
609
+ if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
610
+ serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
611
+ for (var i = 3; i < splitpath.length; i++) { if (obj.common.IsFilenameValid(splitpath[i]) == true) { serverpath += '/' + splitpath[i]; filename = splitpath[i]; } else { return null; } } // Check that each folder is correct
612
+ var fullpath = obj.path.resolve(obj.filespath, serverpath), quota = 0;
613
+ return { fullpath: fullpath, path: serverpath, name: filename, quota: obj.getQuota(objid, domain) };
614
+ }
615
+
616
+ // Return the maximum number of bytes allowed in the user account "My Files".
617
+ obj.getQuota = function(objid, domain) {
618
+ if (objid == null) return 0;
619
+ if (objid.startsWith('user/')) {
620
+ var user = obj.users[objid];
621
+ if (user == null) return 0;
622
+ if ((user.quota != null) && (typeof user.quota == 'number')) { return user.quota; }
623
+ if ((domain != null) && (domain.userQuota != null) && (typeof domain.userQuota == 'number')) { return domain.userQuota; }
624
+ return 1048576; // By default, the server will have a 1 meg limit on user accounts
625
+ } else if (objid.startsWith('mesh/')) {
626
+ var mesh = obj.meshes[objid];
627
+ if (mesh == null) return 0;
628
+ if ((mesh.quota != null) && (typeof mesh.quota == 'number')) { return mesh.quota; }
629
+ if ((domain != null) && (domain.meshQuota != null) && (typeof domain.meshQuota == 'number')) { return domain.meshQuota; }
630
+ return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
631
+ }
632
+ return 0;
633
+ }
634
+
635
// Download a file from the server
636
function handleDownloadFile(req, res) {
637
var domain = checkUserIpAddress(req, res);
@@ -606,7 +639,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
639
if ((req.query.link == null) || (req.session == null) || (req.session.userid == null) || (domain == null) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
640
var user = obj.users[req.session.userid];
641
if (user == null) { res.sendStatus(404); return; }
609
- var file = getServerFilePath(user, domain, req.query.link);
642
+ var file = obj.getServerFilePath(user, domain, req.query.link);
643
if (file == null) { res.sendStatus(404); return; }
644
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 + '\"' });
645
try { res.sendFile(file.fullpath); } catch (e) { res.sendStatus(404); }
@@ -649,7 +682,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
682
var form = new multiparty.Form();
683
form.parse(req, function (err, fields, files) {
684
if ((fields == null) || (fields.link == null) || (fields.link.length != 1)) { res.sendStatus(404); return; }
652
- var xfile = getServerFilePath(user, domain, decodeURIComponent(fields.link[0]));
685
+ var xfile = obj.getServerFilePath(user, domain, decodeURIComponent(fields.link[0]));
686
if (xfile == null) { res.sendStatus(404); return; }
687
// Get total bytes in the path
688
var totalsize = readTotalFileSize(xfile.fullpath);
@@ -662,24 +695,33 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
695
if (obj.common.IsFilenameValid(names[i]) == false) { res.sendStatus(404); return; }
696
var filedata = new Buffer(datas[i].split(',')[1], 'base64');
697
if ((totalsize + filedata.length) < xfile.quota) { // Check if quota would not be broken if we add this file
665
- obj.fs.writeFileSync(xfile.fullpath + '/' + names[i], filedata);
698
+ // Create the user folder if needed
699
+ (function (fullpath, filename, filedata) {
700
+ obj.fs.mkdir(xfile.fullpath, function () {
701
+ // Write the file
702
+ obj.fs.writeFile(obj.path.join(xfile.fullpath, filename), filedata, function () {
703
+ obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
704
+ });
705
+ });
706
+ })(xfile.fullpath, names[i], filedata);
707
}
708
}
709
}
710
} else {
711
// More typical upload method, the file data is in a multipart mime post.
712
for (var i in files.files) {
672
- var file = files.files[i], fpath = xfile.fullpath + '/' + file.originalFilename;
713
+ var file = files.files[i], fpath = obj.path.join(xfile.fullpath, file.originalFilename);
714
if (obj.common.IsFilenameValid(file.originalFilename) && ((totalsize + file.size) < xfile.quota)) { // Check if quota would not be broken if we add this file
674
- obj.fs.rename(file.path, fpath);
715
+ obj.fs.rename(file.path, fpath, function () {
716
+ obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
717
+ });
718
} else {
676
- try { obj.fs.unlinkSync(file.path); } catch (e) { }
719
+ try { obj.fs.unlink(file.path); } catch (e) { }
720
}
721
}
722
}
723
}
724
res.send('');
682
- obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
725
});
726
}
727
@@ -978,9 +1020,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1020
ws.on('close', function (req) { });
1021
}
1022
981
- // Get the total size of all files in a folder and all sub-folders
1023
+ // Get the total size of all files in a folder and all sub-folders. (TODO: try to make all async version)
1024
function readTotalFileSize(path) {
983
- var r = 0, dir = obj.fs.readdirSync(path);
1025
+ var r = 0, dir;
1026
+ try { dir = obj.fs.readdirSync(path); } catch (e) { return 0; }
1027
for (var i in dir) {
1028
var stat = obj.fs.statSync(path + '/' + dir[i])
1029
if ((stat.mode & 0x004000) == 0) { r += stat.size; } else { r += readTotalFileSize(path + '/' + dir[i]); }
@@ -988,7 +1031,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1031
return r;
1032
}
1033
991
- // Delete a folder and all sub items.
1034
+ // Delete a folder and all sub items. (TODO: try to make all async version)
1035
function deleteFolderRec(path) {
1036
if (obj.fs.existsSync(path) == false) return;
1037
obj.fs.readdirSync(path).forEach(function (file, index) {