Issue #312 - enforce filesystem limits

This commit is contained in:
Ali Al Dallal 2014-09-29 16:04:28 -04:00
Родитель ae0e2572a8
Коммит 58281d1997
8 изменённых файлов: 111 добавлений и 3 удалений

Просмотреть файл

@ -6,4 +6,4 @@ before_install:
before_script:
- grunt init
env:
- "PORT=9090 ALLOWED_CORS_DOMAINS=\"http://localhost:7777\" NODE_ENV=\"development\" ENABLE_GELF_LOGS=false SESSION_SECRET=\"secret value\" FORCE_SSL=false LOGIN_SERVER_URL_WITH_AUTH=\"http://localhost:3000\" ENABLE_PATH_ROUTE=true ENABLE_JSON_ROUTE=true ENABLE_ZIP_ROUTE=true"
- "PORT=9090 ALLOWED_CORS_DOMAINS=\"http://localhost:7777\" NODE_ENV=\"development\" ENABLE_GELF_LOGS=false SESSION_SECRET=\"secret value\" FORCE_SSL=false LOGIN_SERVER_URL_WITH_AUTH=\"http://localhost:3000\" ENABLE_PATH_ROUTE=true ENABLE_JSON_ROUTE=true ENABLE_ZIP_ROUTE=true MAX_SYNC_SIZE_BYTES=2000000"

Просмотреть файл

@ -192,7 +192,7 @@ module.exports = function(grunt) {
},
makeDriveClient: {
files: ['client/src/*.js'],
tasks: ["build"],
tasks: ["makedriveClient"],
options: {
spawn: false
}
@ -228,6 +228,7 @@ module.exports = function(grunt) {
grunt.registerTask( "default", [ "test" ] );
grunt.registerTask( "init", [ "exec:grunt_bower" ] );
grunt.registerTask( "build", [ "clean", "browserify:makedriveClient", "uglify" ] );
grunt.registerTask( "makedriveClient", [ "clean", "browserify:makedriveClient", "uglify:develop" ] );
grunt.registerTask( "install", [ "less", "uglify:dependencies", "uglify:angular_app" ] );
grunt.registerTask( "dev", [ "less", "uglify:angular_app", "build", "express:dev", "watch" ] );

Просмотреть файл

@ -223,6 +223,9 @@ function handleError(syncManager, data) {
var message = SyncMessage.request.reset;
syncManager.send(message.stringify());
onError(syncManager, new Error('Could not sync filesystem from server... trying again'));
} else if(data.is.maxsizeExceeded) {
// We are only emitting the error since this is can be sync again from the client
syncManager.sync.emit('error', new Error('Maximum file size exceeded'));
} else {
onError(syncManager, new Error('Failed to sync with the server. Current step is: ' +
session.step + '. Current state is: ' + session.state));

Просмотреть файл

@ -87,3 +87,7 @@ export MAKEDRIVE_UPSTREAM_NAME="upstream"
# Upstream branch to ovewrite on a grunt release command
# (Default to "master")
export MAKEDRIVE_UPSTREAM_BRANCH="master"
# Maximum file size allow to sync.
# (Default to unlimited if not set)
export MAX_SYNC_SIZE_BYTES=

Просмотреть файл

@ -61,6 +61,9 @@ function SyncMessage(type, name, content) {
},
get downstreamLocked() {
return that.name === SyncMessage.DOWNSTREAM_LOCKED;
},
get fileSizeError() {
return that.type === SyncMessage.ERROR && that.name === SyncMessage.MAXSIZE;
}
};
}
@ -101,6 +104,7 @@ SyncMessage.AUTHZ = "AUTHORIZED";
SyncMessage.IMPL = "IMPLEMENTATION";
SyncMessage.SERVER_RESET = "SERVER_RESET";
SyncMessage.DOWNSTREAM_LOCKED = "DOWNSTREAM_LOCKED";
SyncMessage.MAXSIZE = "MAXSIZE";
// SyncMessage Error constants
SyncMessage.INFRMT = "INVALID FORMAT";
@ -120,7 +124,8 @@ function isValidName(name) {
name === SyncMessage.INFRMT ||
name === SyncMessage.INCONT ||
name === SyncMessage.SERVER_RESET ||
name === SyncMessage.DOWNSTREAM_LOCKED;
name === SyncMessage.DOWNSTREAM_LOCKED ||
name === SyncMessage.MAXSIZE;
}
function isValidType(type) {
@ -189,6 +194,9 @@ SyncMessage.error = {
get downstreamLocked() {
return new SyncMessage(SyncMessage.ERROR, SyncMessage.DOWNSTREAM_LOCKED, 'Downstream syncs are locked!');
},
get maxsizeExceeded() {
return new SyncMessage(SyncMessage.ERROR, SyncMessage.MAXSIZE, 'Maximum file size exceeded');
},
get verification() {
return new SyncMessage(SyncMessage.ERROR,
SyncMessage.VERIFICATION,

Просмотреть файл

@ -21,6 +21,7 @@ var ActiveSyncManager = require('../../server/lib/active-sync-manager');
var connectedClients = {};
var CLIENT_TIMEOUT_MS = env.get('CLIENT_TIMEOUT_MS') || 5000;
var MAX_SYNC_SIZE_BYTES = env.get('MAX_SYNC_SIZE_BYTES', Math.Infinity);
function Sync(username, id, ws) {
EventEmitter.call(this);
@ -410,6 +411,20 @@ function handleRequest(sync, data) {
var srcList = data.content.srcList;
// Check file size limit
for (var key in srcList) {
var obj = srcList[key];
for (var prop in obj) {
if(obj.hasOwnProperty(prop) && prop === 'size') {
if(obj.size > MAX_SYNC_SIZE_BYTES) {
sync.state = Sync.LISTENING;
ActiveSyncManager.remove(sync.username);
return sync.sendMessage(SyncMessage.error.maxsizeExceeded, true);
}
}
}
}
rsync.checksums(sync.fs, sync.path, srcList, rsyncOptions, function(err, checksums) {
if(err) {
sync.state = Sync.LISTENING;

Просмотреть файл

@ -18,6 +18,8 @@ var MakeDrive = require('../../client/src/index.js');
// Ensure the client timeout restricts tests to a reasonable length
var env = require('../../server/lib/environment');
env.set('CLIENT_TIMEOUT_MS', 1000);
// Set maximum file size limit to 2000000 bytes
env.set('MAX_SYNC_SIZE_BYTES', 2000000);
// Enable a username:password for BASIC_AUTH_USERS to enable /api/get route
env.set('BASIC_AUTH_USERS', 'testusername:testpassword');

Просмотреть файл

@ -0,0 +1,75 @@
var env = require('../../../server/lib/environment');
var expect = require('chai').expect;
var util = require('../../lib/util.js');
var MakeDrive = require('../../../client/src');
var Filer = require('../../../lib/filer.js');
var MAX_SIZE_BYTES = 2000000;
describe('Syncing file larger than size limit', function(){
var provider;
beforeEach(function() {
var username = util.username();
provider = new Filer.FileSystem.providers.Memory(username);
});
afterEach(function() {
provider = null;
});
it('should return an error if file exceeded the size limit', function(done) {
util.authenticatedConnection(function(err, result) {
expect(err).not.to.exist;
var fs = MakeDrive.fs({provider: provider, manual: true, forceCreate: true});
var sync = fs.sync;
var layout = {'/hello.txt': new Filer.Buffer(MAX_SIZE_BYTES+1) };
sync.once('connected', function onClientConnected() {
util.createFilesystemLayout(fs, layout, function(err) {
expect(err).not.to.exist;
sync.request();
});
});
sync.once('error', function onClientError(error) {
expect(error).to.eql(new Error('Maximum file size exceeded'));
done();
});
sync.connect(util.socketURL, result.token);
});
});
it('should not return an error if file did not exceed the size limit', function(done) {
var everError = false;
util.authenticatedConnection(function(err, result) {
expect(err).not.to.exist;
var fs = MakeDrive.fs({provider: provider, manual: true, forceCreate: true});
var sync = fs.sync;
var layout = {'/hello.txt': new Filer.Buffer(MAX_SIZE_BYTES) };
sync.once('connected', function onClientConnected() {
util.createFilesystemLayout(fs, layout, function(err) {
expect(err).not.to.exist;
sync.request();
});
});
sync.once('completed', function() {
expect(everError).to.be.false;
done();
});
sync.once('error', function onClientError(error) {
everError = true;
});
sync.connect(util.socketURL, result.token);
});
});
});