]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blobdiff - src/files.js
Make listen port and ldap filter more flexible
[perso/Immae/Projets/Nodejs/Surfer.git] / src / files.js
index 48f91a816574808cea9939c2ee4006cb5354066d..1af4a18a3ece1f215342cd2b90fda8fa871d28ff 100644 (file)
@@ -1,9 +1,9 @@
 'use strict';
 
-var fs = require('fs'),
+var async = require('async'),
+    fs = require('fs'),
     path = require('path'),
-    ejs = require('ejs'),
-    rimraf = require('rimraf'),
+    rm = require('del'),
     debug = require('debug')('files'),
     mkdirp = require('mkdirp'),
     HttpError = require('connect-lastmile').HttpError,
@@ -17,6 +17,7 @@ exports = module.exports = function (basePath) {
     return {
         get: get,
         put: put,
+        post: post,
         del: del
     };
 };
@@ -54,19 +55,30 @@ function copyFile(source, target, cb) {
     });
 }
 
-function render(view, options) {
-    return ejs.render(fs.readFileSync(view, 'utf8'), options);
+function createDirectory(targetPath, callback) {
+    mkdirp(targetPath, function (error) {
+        if (error) return callback(error);
+        callback(null);
+    });
+}
+
+function isProtected(targetPath) {
+    return targetPath.indexOf(getAbsolutePath('_admin')) === 0;
 }
 
 function getAbsolutePath(filePath) {
-    var absoluteFilePath = path.resolve(gBasePath, filePath);
+    var absoluteFilePath = path.resolve(path.join(gBasePath, filePath));
 
     if (absoluteFilePath.indexOf(gBasePath) !== 0) return null;
     return absoluteFilePath;
 }
 
+function removeBasePath(filePath) {
+    return filePath.slice(gBasePath.length);
+}
+
 function get(req, res, next) {
-    var filePath = req.params[0];
+    var filePath = decodeURIComponent(req.params[0]);
     var absoluteFilePath = getAbsolutePath(filePath);
     if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed'));
 
@@ -75,28 +87,54 @@ function get(req, res, next) {
 
         debug('get', absoluteFilePath);
 
-        if (result.isFile()) return res.sendfile(absoluteFilePath);
-        if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) });
-
-        return next(new HttpError(500, 'unsupported type'));
+        if (!result.isDirectory() && !result.isFile()) return next(new HttpError(500, 'unsupported type'));
+        if (result.isFile()) return res.download(absoluteFilePath);
+
+        async.map(fs.readdirSync(absoluteFilePath), function (filePath, callback) {
+            fs.stat(path.join(absoluteFilePath, filePath), function (error, result) {
+                if (error) return callback(error);
+
+                callback(null, {
+                    isDirectory: result.isDirectory(),
+                    isFile: result.isFile(),
+                    atime: result.atime,
+                    mtime: result.mtime,
+                    ctime: result.ctime,
+                    birthtime: result.birthtime,
+                    size: result.size,
+                    filePath: filePath
+                });
+            });
+        }, function (error, results) {
+            if (error) return next(new HttpError(500, error));
+            res.status(222).send({ entries: results });
+        });
     });
 }
 
-function put(req, res, next) {
-    var filePath = req.params[0];
+function post(req, res, next) {
+    var filePath = decodeURIComponent(req.params[0]);
 
-    if (!req.files.file) return next(new HttpError(400, 'missing file'));
+    if (!(req.files && req.files.file) && !req.query.directory) return next(new HttpError(400, 'missing file or directory'));
+    if ((req.files && req.files.file) && req.query.directory) return next(new HttpError(400, 'either file or directory'));
+
+    debug('post:', filePath);
 
     var absoluteFilePath = getAbsolutePath(filePath);
-    if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed'));
+    if (!absoluteFilePath || isProtected(absoluteFilePath)) return next(new HttpError(403, 'Path not allowed'));
 
     fs.stat(absoluteFilePath, function (error, result) {
         if (error && error.code !== 'ENOENT') return next(new HttpError(500, error));
 
-        debug('put', absoluteFilePath, req.files.file);
+        if (result && req.query.directory) return next(new HttpError(409, 'name already exists'));
+        if (result && result.isDirectory()) return next(new HttpError(409, 'cannot post on directories'));
 
-        if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories'));
-        if (!result || result.isFile()) {
+        if (req.query.directory) {
+            return createDirectory(absoluteFilePath, function (error) {
+                if (error) return next(new HttpError(500, error));
+                next(new HttpSuccess(201, {}));
+            });
+        } else if (!result || result.isFile()) {
             return copyFile(req.files.file.path, absoluteFilePath, function (error) {
                 if (error) return next(new HttpError(500, error));
                 next(new HttpSuccess(201, {}));
@@ -107,18 +145,57 @@ function put(req, res, next) {
     });
 }
 
+function put(req, res, next) {
+    var oldFilePath = decodeURIComponent(req.params[0]);
+
+    if (!req.body || !req.body.newFilePath) return next(new HttpError(400, 'missing newFilePath'));
+
+    var newFilePath = decodeURIComponent(req.body.newFilePath);
+
+    debug('put: %s -> %s', oldFilePath, newFilePath);
+
+    var absoluteOldFilePath = getAbsolutePath(oldFilePath);
+    if (!absoluteOldFilePath || isProtected(absoluteOldFilePath)) return next(new HttpError(403, 'Path not allowed'));
+
+    var absoluteNewFilePath = getAbsolutePath(newFilePath);
+    if (!absoluteNewFilePath || isProtected(absoluteNewFilePath)) return next(new HttpError(403, 'Path not allowed'));
+
+    fs.rename(absoluteOldFilePath, absoluteNewFilePath, function (error) {
+        if (error) return next (new HttpError(500, error));
+
+        debug('put: successful');
+
+        return next(new HttpSuccess(200, {}));
+    });
+}
+
 function del(req, res, next) {
-    var filePath = req.params[0];
+    var filePath = decodeURIComponent(req.params[0]);
+    var recursive = !!req.query.recursive;
+    var dryRun = !!req.query.dryRun;
+
     var absoluteFilePath = getAbsolutePath(filePath);
     if (!absoluteFilePath) return next(new HttpError(404, 'Not found'));
-    if (absoluteFilePath.slice(gBasePath.length) === '') return next(new HttpError(403, 'Forbidden'));
+
+    if (isProtected(absoluteFilePath)) return next(new HttpError(403, 'Path not allowed'));
+
+    // absoltueFilePath has to have the base path prepended
+    if (absoluteFilePath.length <= gBasePath.length) return next(new HttpError(404, 'Not found'));
 
     fs.stat(absoluteFilePath, function (error, result) {
         if (error) return next(new HttpError(404, error));
 
-        rimraf(absoluteFilePath, function (error) {
-            if (error) return next(new HttpError(500, 'Unable to remove'));
-            next(new HttpSuccess(200, {}));
+        if (result.isDirectory() && !recursive) return next(new HttpError(403, 'Is directory'));
+
+        // add globs to get file listing
+        if (result.isDirectory()) absoluteFilePath += '/**';
+
+        rm(absoluteFilePath, { dryRun: dryRun, force: true }).then(function (result) {
+            result = result.map(removeBasePath);
+            next(new HttpSuccess(200, { entries: result }));
+        }, function (error) {
+            console.error(error);
+            next(new HttpError(500, 'Unable to remove'));
         });
     });
 }