commit
2effdf2b95
9 changed files with 1528 additions and 1063 deletions
|
@ -2,6 +2,7 @@ env:
|
||||||
browser: true
|
browser: true
|
||||||
es6: true
|
es6: true
|
||||||
jquery: true
|
jquery: true
|
||||||
|
mocha: true
|
||||||
node: true
|
node: true
|
||||||
|
|
||||||
extends:
|
extends:
|
||||||
|
|
4
circle.yml
Normal file
4
circle.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
machine:
|
||||||
|
node:
|
||||||
|
version: 8.0.0
|
||||||
|
|
2216
package-lock.json
generated
2216
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -27,8 +27,11 @@
|
||||||
"eslint-plugin-node": "5.0.0",
|
"eslint-plugin-node": "5.0.0",
|
||||||
"eslint-plugin-security": "1.3.0",
|
"eslint-plugin-security": "1.3.0",
|
||||||
"htmllint-cli": "0.0.6",
|
"htmllint-cli": "0.0.6",
|
||||||
|
"mocha": "^3.4.2",
|
||||||
"npm-run-all": "4.0.2",
|
"npm-run-all": "4.0.2",
|
||||||
"prettier": "1.4.4",
|
"prettier": "1.4.4",
|
||||||
|
"proxyquire": "^1.8.0",
|
||||||
|
"sinon": "^2.3.5",
|
||||||
"stylelint": "7.11.0",
|
"stylelint": "7.11.0",
|
||||||
"stylelint-config-standard": "16.0.0",
|
"stylelint-config-standard": "16.0.0",
|
||||||
"watchify": "^3.9.0"
|
"watchify": "^3.9.0"
|
||||||
|
@ -46,6 +49,6 @@
|
||||||
"lint:html": "htmllint 'views/*.handlebars'",
|
"lint:html": "htmllint 'views/*.handlebars'",
|
||||||
"lint:js": "eslint .",
|
"lint:js": "eslint .",
|
||||||
"start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js",
|
"start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "mocha"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ const conf = convict({
|
||||||
env: 'P2P_LISTEN_PORT'
|
env: 'P2P_LISTEN_PORT'
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
format: ['production', 'development'],
|
format: ['production', 'development', 'test'],
|
||||||
default: 'development',
|
default: 'development',
|
||||||
env: 'NODE_ENV'
|
env: 'NODE_ENV'
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ app.get('/assets/download/:id', (req, res) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
log.info('Deleted:', id);
|
log.info('Deleted:', id);
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
log.info('DeleteError:', id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -89,7 +91,7 @@ app.post('/delete/:id', (req, res) => {
|
||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
|
|
||||||
if (!validateID(id)) {
|
if (!validateID(id)) {
|
||||||
res.send(404);
|
res.sendStatus(404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ app.post('/delete/:id', (req, res) => {
|
||||||
|
|
||||||
storage
|
storage
|
||||||
.delete(id, delete_token)
|
.delete(id, delete_token)
|
||||||
.then(err => {
|
.then(() => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
log.info('Deleted:', id);
|
log.info('Deleted:', id);
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
|
@ -112,7 +114,7 @@ app.post('/delete/:id', (req, res) => {
|
||||||
|
|
||||||
app.post('/upload/:id', (req, res, next) => {
|
app.post('/upload/:id', (req, res, next) => {
|
||||||
if (!validateID(req.params.id)) {
|
if (!validateID(req.params.id)) {
|
||||||
res.send(404);
|
res.sendStatus(404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ const redis_client = redis.createClient({
|
||||||
});
|
});
|
||||||
|
|
||||||
redis_client.on('error', err => {
|
redis_client.on('error', err => {
|
||||||
log.info('Redis: ', err);
|
log.info('Redis:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (notLocalHost) {
|
if (notLocalHost) {
|
||||||
|
@ -94,7 +94,10 @@ function localSet(id, file, filename, url) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
fstream.on('error', () => reject());
|
fstream.on('error', () => {
|
||||||
|
log.error('localSet:', 'Failed upload of ' + id);
|
||||||
|
reject();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +143,12 @@ function awsGet(id) {
|
||||||
Key: id
|
Key: id
|
||||||
};
|
};
|
||||||
|
|
||||||
return s3.getObject(params).createReadStream();
|
try {
|
||||||
|
return s3.getObject(params).createReadStream();
|
||||||
|
} catch(err) {
|
||||||
|
log.info('GetFailed', 'Get Object from s3 failed.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function awsSet(id, file, filename, url) {
|
function awsSet(id, file, filename, url) {
|
||||||
|
@ -203,7 +211,7 @@ function awsDelete(id, delete_token) {
|
||||||
};
|
};
|
||||||
|
|
||||||
s3.deleteObject(params, function(err, _data) {
|
s3.deleteObject(params, function(err, _data) {
|
||||||
resolve(err);
|
err ? reject(err) : resolve(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -219,7 +227,7 @@ function awsForceDelete(id) {
|
||||||
};
|
};
|
||||||
|
|
||||||
s3.deleteObject(params, function(err, _data) {
|
s3.deleteObject(params, function(err, _data) {
|
||||||
resolve(err);
|
err ? reject(err) : resolve(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
165
test/aws.storage.test.js
Normal file
165
test/aws.storage.test.js
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const proxyquire = require('proxyquire');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const conf = require('../server/config.js');
|
||||||
|
conf.notLocalHost = true;
|
||||||
|
|
||||||
|
let redisStub = {};
|
||||||
|
let exists = sinon.stub();
|
||||||
|
let hget = sinon.stub();
|
||||||
|
let hmset = sinon.stub();
|
||||||
|
let expire = sinon.spy();
|
||||||
|
let del = sinon.stub();
|
||||||
|
|
||||||
|
redisStub.createClient = function() {
|
||||||
|
return {
|
||||||
|
on: sinon.spy(),
|
||||||
|
exists: exists,
|
||||||
|
hget: hget,
|
||||||
|
hmset: hmset,
|
||||||
|
expire: expire,
|
||||||
|
del: del
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fsStub = {};
|
||||||
|
fsStub.statSync = sinon.stub();
|
||||||
|
fsStub.createReadStream = sinon.stub();
|
||||||
|
fsStub.createWriteStream = sinon.stub();
|
||||||
|
fsStub.unlinkSync = sinon.stub();
|
||||||
|
|
||||||
|
let logStub = {};
|
||||||
|
logStub.info = sinon.stub();
|
||||||
|
logStub.error = sinon.stub();
|
||||||
|
|
||||||
|
let s3Stub = {};
|
||||||
|
s3Stub.headObject = sinon.stub();
|
||||||
|
s3Stub.getObject = sinon.stub();
|
||||||
|
s3Stub.upload = sinon.stub();
|
||||||
|
s3Stub.deleteObject = sinon.stub();
|
||||||
|
|
||||||
|
let awsStub = {
|
||||||
|
S3: function() {
|
||||||
|
return s3Stub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = proxyquire('../server/storage', {
|
||||||
|
'redis': redisStub,
|
||||||
|
'fs': fsStub,
|
||||||
|
'./log.js': function() { return logStub },
|
||||||
|
'aws-sdk': awsStub
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Length using aws', function() {
|
||||||
|
it('Filesize returns properly if id exists', function() {
|
||||||
|
s3Stub.headObject.callsArgWith(1, null, {ContentLength: 1});
|
||||||
|
return storage.length('123')
|
||||||
|
.then(reply => assert.equal(reply, 1))
|
||||||
|
.catch(err => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Filesize fails if the id does not exist', function() {
|
||||||
|
s3Stub.headObject.callsArgWith(1, new Error(), null);
|
||||||
|
return storage.length('123')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(err => assert(1))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Get using aws', function() {
|
||||||
|
|
||||||
|
it('Should not error out when the file exists', function() {
|
||||||
|
let spy = sinon.spy();
|
||||||
|
s3Stub.getObject.returns({
|
||||||
|
createReadStream: spy
|
||||||
|
});
|
||||||
|
|
||||||
|
storage.get('123');
|
||||||
|
assert(spy.calledOnce);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should error when the file does not exist', function() {
|
||||||
|
let err = function() { throw new Error(); }
|
||||||
|
let spy = sinon.spy(err);
|
||||||
|
s3Stub.getObject.returns({
|
||||||
|
createReadStream: spy
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(storage.get('123'), null);
|
||||||
|
assert(spy.threw());
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Set using aws', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
expire.reset();
|
||||||
|
})
|
||||||
|
|
||||||
|
after(function() {
|
||||||
|
crypto.randomBytes.restore();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should pass when the file is successfully uploaded and no bitly key', function() {
|
||||||
|
conf.bitly_key = null;
|
||||||
|
const buf = new Buffer(10);
|
||||||
|
sinon.stub(crypto, 'randomBytes').returns(buf);
|
||||||
|
s3Stub.upload.callsArgWith(1, null, {});
|
||||||
|
return storage.set('123', {}, 'Filename.moz', 'url.com')
|
||||||
|
.then(reply => {
|
||||||
|
assert.equal(reply.uuid, buf.toString('hex'));
|
||||||
|
assert.equal(reply.url, 'url.com');
|
||||||
|
assert.notEqual(reply.uuid, null);
|
||||||
|
assert(expire.calledOnce);
|
||||||
|
assert(expire.calledWith('123', 86400000));
|
||||||
|
})
|
||||||
|
.catch(err => assert.fail());
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail if there was an error during uploading', function() {
|
||||||
|
s3Stub.upload.callsArgWith(1, new Error(), null);
|
||||||
|
return storage.set('123', {}, 'Filename.moz', 'url.com')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(err => assert(1));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Delete from aws', function() {
|
||||||
|
it('Returns successfully if the id is deleted off aws', function() {
|
||||||
|
hget.callsArgWith(2, null, 'delete_token');
|
||||||
|
s3Stub.deleteObject.callsArgWith(1, null, {});
|
||||||
|
return storage.delete('file_id', 'delete_token')
|
||||||
|
.then(reply => assert(1), err => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Delete fails if id exists locally but does not in aws', function() {
|
||||||
|
hget.callsArgWith(2, null, 'delete_token');
|
||||||
|
s3Stub.deleteObject.callsArgWith(1, new Error(), {});
|
||||||
|
return storage.delete('file_id', 'delete_token')
|
||||||
|
.then(reply => assert.fail(), err => assert(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Delete fails if the delete token does not match', function() {
|
||||||
|
hget.callsArgWith(2, null, {});
|
||||||
|
return storage.delete('Filename.moz', 'delete_token')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Forced Delete from aws', function() {
|
||||||
|
it('Deletes properly if id exists', function() {
|
||||||
|
s3Stub.deleteObject.callsArgWith(1, null, {});
|
||||||
|
return storage.forceDelete('file_id', 'delete_token')
|
||||||
|
.then(reply => assert(1), err => assert.fail());
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Deletes fails if id does not exist', function() {
|
||||||
|
s3Stub.deleteObject.callsArgWith(1, new Error(), {});
|
||||||
|
return storage.forceDelete('file_id')
|
||||||
|
.then(reply => assert.fail(), err => assert(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
172
test/local.storage.test.js
Normal file
172
test/local.storage.test.js
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const proxyquire = require('proxyquire');
|
||||||
|
|
||||||
|
const conf = require('../server/config.js')
|
||||||
|
conf.notLocalHost = false;
|
||||||
|
|
||||||
|
let redisStub = {};
|
||||||
|
let exists = sinon.stub();
|
||||||
|
let hget = sinon.stub();
|
||||||
|
let hmset = sinon.stub();
|
||||||
|
let expire = sinon.stub();
|
||||||
|
let del = sinon.stub();
|
||||||
|
|
||||||
|
redisStub.createClient = function() {
|
||||||
|
return {
|
||||||
|
on: sinon.spy(),
|
||||||
|
exists: exists,
|
||||||
|
hget: hget,
|
||||||
|
hmset: hmset,
|
||||||
|
expire: expire,
|
||||||
|
del: del
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fsStub = {};
|
||||||
|
fsStub.statSync = sinon.stub();
|
||||||
|
fsStub.createReadStream = sinon.stub();
|
||||||
|
fsStub.createWriteStream = sinon.stub();
|
||||||
|
fsStub.unlinkSync = sinon.stub();
|
||||||
|
|
||||||
|
let logStub = {};
|
||||||
|
logStub.info = sinon.stub();
|
||||||
|
logStub.error = sinon.stub();
|
||||||
|
|
||||||
|
const storage = proxyquire('../server/storage', {
|
||||||
|
'redis': redisStub,
|
||||||
|
'fs': fsStub,
|
||||||
|
'./log.js': function() { return logStub }
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Exists from local filesystem', function() {
|
||||||
|
it('Exists returns true when file exists', function() {
|
||||||
|
exists.callsArgWith(1, null, 1);
|
||||||
|
return storage.exists('test')
|
||||||
|
.then((reply) => assert(reply));
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Exists returns false when file does not exist', function() {
|
||||||
|
exists.callsArgWith(1, null, 0);
|
||||||
|
return storage.exists('test')
|
||||||
|
.then((reply) => assert(!reply));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Filename from local filesystem', function() {
|
||||||
|
it('Filename returns properly if id exists', function() {
|
||||||
|
hget.callsArgWith(2, null, 'Filename.moz');
|
||||||
|
return storage.filename('test')
|
||||||
|
.then(reply => assert(1))
|
||||||
|
.catch(reply => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Filename fails if id does not exist', function() {
|
||||||
|
hget.callsArgWith(2, null, 'Filename.moz');
|
||||||
|
return storage.filename('test')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing Length from local filesystem', function() {
|
||||||
|
it('Filesize returns properly if id exists', function() {
|
||||||
|
fsStub.statSync.returns({size: 10});
|
||||||
|
return storage.length('Filename.moz')
|
||||||
|
.then(reply => assert(1))
|
||||||
|
.catch(reply => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Filesize fails if the id does not exist', function() {
|
||||||
|
fsStub.statSync.returns(null);
|
||||||
|
return storage.length('Filename.moz')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing Get from local filesystem', function() {
|
||||||
|
it('Get returns properly if id exists', function() {
|
||||||
|
fsStub.createReadStream.returns(1);
|
||||||
|
if (storage.get('Filename.moz')) {
|
||||||
|
assert(1)
|
||||||
|
} else {
|
||||||
|
assert.fail();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Get fails if the id does not exist', function() {
|
||||||
|
fsStub.createReadStream.returns(null);
|
||||||
|
if (storage.get('Filename.moz')) {
|
||||||
|
assert.fail();
|
||||||
|
} else {
|
||||||
|
assert(1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing Set to local filesystem', function() {
|
||||||
|
it('Successfully writes the file to the local filesystem', function() {
|
||||||
|
let stub = sinon.stub();
|
||||||
|
stub.withArgs('close', sinon.match.any).callsArgWithAsync(1)
|
||||||
|
stub.withArgs('error', sinon.match.any).returns(1);
|
||||||
|
fsStub.createWriteStream.returns({ on: stub })
|
||||||
|
|
||||||
|
return storage.set('test', { pipe: sinon.stub() }, 'Filename.moz', 'moz.la')
|
||||||
|
.then(reply => {
|
||||||
|
assert(reply.uuid);
|
||||||
|
assert.equal(reply.url, 'moz.la');
|
||||||
|
})
|
||||||
|
.catch(reply => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Fails when the file is not properly written to the local filesystem', function() {
|
||||||
|
let stub = sinon.stub();
|
||||||
|
stub.withArgs('error', sinon.match.any).callsArgWithAsync(1)
|
||||||
|
stub.withArgs('close', sinon.match.any).returns(1);
|
||||||
|
fsStub.createWriteStream.returns({ on: stub })
|
||||||
|
|
||||||
|
return storage.set('test', {pipe: sinon.stub()}, 'Filename.moz', 'moz.la')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing Delete from local filesystem', function() {
|
||||||
|
it('Deletes properly if id exists', function() {
|
||||||
|
hget.callsArgWith(2, null, '123');
|
||||||
|
fsStub.unlinkSync.returns(1);
|
||||||
|
return storage.delete('Filename.moz', '123')
|
||||||
|
.then(reply => assert(reply))
|
||||||
|
.catch(reply => assert.fail())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Delete fails if id does not exist', function() {
|
||||||
|
hget.callsArgWith(2, null, null);
|
||||||
|
return storage.delete('Filename.moz', '123')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Delete fails if the delete token does not match', function() {
|
||||||
|
hget.callsArgWith(2, null, null);
|
||||||
|
return storage.delete('Filename.moz', '123')
|
||||||
|
.then(reply => assert.fail())
|
||||||
|
.catch(reply => assert(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Testing Forced Delete from local filesystem', function() {
|
||||||
|
it('Deletes properly if id exists', function() {
|
||||||
|
fsStub.unlinkSync.returns(1);
|
||||||
|
return storage.forceDelete('Filename.moz')
|
||||||
|
.then(reply => assert(reply))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Deletes fails if id does not exist, but no reject is called', function() {
|
||||||
|
fsStub.unlinkSync.returns(0);
|
||||||
|
return storage.forceDelete('Filename.moz')
|
||||||
|
.then(reply => assert(!reply))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
Loading…
Reference in a new issue