bloody-simple-s3
Advanced tools
Comparing version 0.3.5 to 0.4.0
@@ -0,1 +1,7 @@ | ||
## 0.4.0 - 2015-05-15 | ||
* Calculate md5 checksum on #upload() and #download() to make sure the file's integrity is intact | ||
* Install type-of@2.0.1 for better (i.e. more descriptive) error messages | ||
* Update npm dependencies (aws-sdk@2.1.28, mocha@2.2.5) | ||
## 0.3.5 - 2015-05-05 | ||
@@ -2,0 +8,0 @@ |
{ | ||
"name": "bloody-simple-s3", | ||
"version": "0.3.5", | ||
"version": "0.4.0", | ||
"description": "A bloody simple interface to S3, based on the official AWS sdk", | ||
@@ -26,5 +26,6 @@ "repository": { | ||
"dependencies": { | ||
"aws-sdk": "^2.1.26", | ||
"aws-sdk": "^2.1.28", | ||
"bluebird": "^2.9.25", | ||
"lodash": "^3.8.0" | ||
"lodash": "^3.8.0", | ||
"type-of": "^2.0.1" | ||
}, | ||
@@ -34,4 +35,4 @@ "devDependencies": { | ||
"dotenv": "^1.1.0", | ||
"mocha": "^2.2.4" | ||
"mocha": "^2.2.5" | ||
} | ||
} |
@@ -10,2 +10,3 @@ # Bloody simple S3 | ||
* Promise and callback interface; | ||
* Automatic file integrity check; | ||
* Bloody simple API. | ||
@@ -12,0 +13,0 @@ |
var path = require('path'); | ||
var fs = require('fs'); | ||
var os = require('os'); | ||
var crypto = require('crypto'); | ||
var Promise = require('bluebird'); | ||
var fs = Promise.promisifyAll(require('fs')); | ||
var os = require('os'); | ||
var stream = require('stream'); | ||
@@ -8,6 +11,7 @@ var AWS = require('aws-sdk'); | ||
var _ = require('lodash'); | ||
var type = require('type-of'); | ||
function BloodySimpleS3(options) { | ||
if (!_.isPlainObject(options)) { | ||
throw new Error('Invalid options param; expected object, received ' + typeof(options)); | ||
throw new Error('Invalid options param; expected object, received ' + type(options)); | ||
} | ||
@@ -21,19 +25,19 @@ | ||
if (!_.isString(options.bucket)) { | ||
throw new Error('Invalid bucket option; expected string, received ' + typeof(options.bucket)); | ||
throw new Error('Invalid bucket option; expected string, received ' + type(options.bucket)); | ||
} | ||
if (!_.isString(options.accessKeyId)) { | ||
throw new Error('Invalid accessKeyId option; expected string, received ' + typeof(options.accessKeyId)); | ||
throw new Error('Invalid accessKeyId option; expected string, received ' + type(options.accessKeyId)); | ||
} | ||
if (!_.isString(options.secretAccessKey)) { | ||
throw new Error('Invalid secretAccessKey option; expected string, received ' + typeof(options.secretAccessKey)); | ||
throw new Error('Invalid secretAccessKey option; expected string, received ' + type(options.secretAccessKey)); | ||
} | ||
if (!_.isString(options.region)) { | ||
throw new Error('Invalid region option; expected string, received ' + typeof(options.region)); | ||
throw new Error('Invalid region option; expected string, received ' + type(options.region)); | ||
} | ||
if (!_.isBoolean(options.sslEnabled)) { | ||
throw new Error('Invalid sslEnabled option; expected boolean, received ' + typeof(options.sslEnabled)); | ||
throw new Error('Invalid sslEnabled option; expected boolean, received ' + type(options.sslEnabled)); | ||
} | ||
@@ -56,3 +60,3 @@ | ||
if (!_.isString(filename)) { | ||
throw new Error('Invalid filename param; expected string, received ' + typeof(filename)); | ||
throw new Error('Invalid filename param; expected string, received ' + type(filename)); | ||
} | ||
@@ -68,3 +72,3 @@ | ||
BloodySimpleS3.prototype.download = function (source, target, callback) { | ||
BloodySimpleS3.prototype.downloadWithoutCheck = function (source, target, callback) { | ||
var _this = this; | ||
@@ -74,3 +78,3 @@ var resolver; | ||
if (!_.isString(source)) { | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + typeof(source))) | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + type(source))) | ||
.nodeify(callback); | ||
@@ -87,3 +91,3 @@ } | ||
if (!_.isString(target)) { | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + typeof(target))) | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + type(target))) | ||
.nodeify(callback); | ||
@@ -120,3 +124,26 @@ } | ||
return new Promise(resolver) | ||
return new Promise(resolver).nodeify(callback); | ||
}; | ||
BloodySimpleS3.prototype.download = function (source, target, callback) { | ||
return Promise.props({ | ||
file: this.downloadWithoutCheck(source, target), | ||
meta: this.getFileMeta(source) | ||
}) | ||
.then(function (props) { | ||
return fs.readFileAsync(props.file.name) | ||
.then(function (buf) { | ||
var err; | ||
if (props.meta.ETag !== '"' + crypto.createHash('md5').update(buf).digest().toString('hex') + '"') { | ||
err = new Error('Bad MD5 digest for file ' + source); | ||
err.code = 'BAD_DIGEST'; | ||
return fs.unlinkAsync(props.file.name) // remove downloaded file from disk | ||
.throw(err); | ||
} | ||
return props.file; | ||
}); | ||
}) | ||
.nodeify(callback); | ||
@@ -154,12 +181,8 @@ }; | ||
if (!_.isString(filename)) { | ||
return Promise.reject(new Error('Invalid filename param; expected string, received ' + typeof(filename))) | ||
return Promise.reject(new Error('Invalid filename param; expected string, received ' + type(filename))) | ||
.nodeify(callback); | ||
} | ||
if ( | ||
!(contents instanceof stream.Readable) && | ||
!(Buffer.isBuffer(contents)) && | ||
!_.isString(contents) | ||
) { | ||
return Promise.reject(new Error('Invalid contents param; expected readable stream, buffer or string, received ' + typeof(contents))) | ||
if (!(contents instanceof stream.Readable) && !(Buffer.isBuffer(contents)) && !_.isString(contents)) { | ||
return Promise.reject(new Error('Invalid contents param; expected readable stream, buffer or string, received ' + type(contents))) | ||
.nodeify(callback); | ||
@@ -174,2 +197,6 @@ } | ||
if (Buffer.isBuffer(contents)) { | ||
params.ContentMD5 = crypto.createHash('md5').update(contents).digest().toString('base64'); // force integrity check | ||
} | ||
resolver = function(resolve, reject) { | ||
@@ -188,6 +215,5 @@ _this.s3.putObject(params, function (err) { | ||
var _this = this; | ||
var resolver; | ||
if (!_.isString(source)) { | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + typeof(source))) | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + type(source))) | ||
.nodeify(callback); | ||
@@ -206,23 +232,25 @@ } | ||
if (!_.isString(target)) { | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + typeof(target))) | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + type(target))) | ||
.nodeify(callback); | ||
} | ||
resolver = function(resolve, reject) { | ||
fs.stat(source, function (err, stats) { | ||
var readable; | ||
return fs.statAsync(source) | ||
.then(function (stats) { | ||
var err; | ||
if (err) return reject(err); | ||
if (!stats.isFile()) { | ||
return reject(new Error('Source is invalid; you must reference a file')); | ||
err = new Error('Source is invalid; you must reference a file'); | ||
err.code = 'INVALID_SOURCE'; | ||
throw err; | ||
} | ||
readable = fs.createReadStream(source); | ||
if (stats.size < os.freemem()) { | ||
return fs.readFileAsync(source); // memory is suffient - use buffer | ||
} | ||
resolve(_this.writeFile(target, readable)); | ||
}); | ||
}; | ||
return new Promise(resolver) | ||
return fs.createReadStream(source); | ||
}) | ||
.then(function (contents) { | ||
return _this.writeFile(target, contents); | ||
}) | ||
.nodeify(callback); | ||
@@ -237,3 +265,3 @@ }; | ||
if (!_.isString(dir)) { | ||
return Promise.reject(new Error('Invalid dir param; expected string, received ' + typeof(dir))) | ||
return Promise.reject(new Error('Invalid dir param; expected string, received ' + type(dir))) | ||
.nodeify(callback); | ||
@@ -250,3 +278,3 @@ } | ||
if (!_.isPlainObject(options)) { | ||
return Promise.reject(new Error('Invalid options param; expected object, received ' + typeof(options))) | ||
return Promise.reject(new Error('Invalid options param; expected object, received ' + type(options))) | ||
.nodeify(callback); | ||
@@ -289,3 +317,3 @@ } | ||
if (!_.isString(source)) { | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + typeof(source))) | ||
return Promise.reject(new Error('Invalid source param; expected string, received ' + type(source))) | ||
.nodeify(callback); | ||
@@ -295,3 +323,3 @@ } | ||
if (!_.isString(target)) { | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + typeof(target))) | ||
return Promise.reject(new Error('Invalid target param; expected string, received ' + type(target))) | ||
.nodeify(callback); | ||
@@ -308,3 +336,3 @@ } | ||
if (!_.isPlainObject(options)) { | ||
return Promise.reject(new Error('Invalid options param; expected object, received ' + typeof(options))) | ||
return Promise.reject(new Error('Invalid options param; expected object, received ' + type(options))) | ||
.nodeify(callback); | ||
@@ -336,3 +364,3 @@ } | ||
if (!_.isString(filename)) { | ||
return Promise.reject(new Error('Invalid filename param; expected string, received ' + typeof(filename))) | ||
return Promise.reject(new Error('Invalid filename param; expected string, received ' + type(filename))) | ||
.nodeify(callback); | ||
@@ -372,2 +400,26 @@ } | ||
BloodySimpleS3.prototype.getFileMeta = function (filename, callback) { | ||
var _this = this; | ||
var params; | ||
var resolver; | ||
if (!_.isString(filename)) { | ||
throw new Error('Invalid filename param; expected string, received ' + type(filename)); | ||
} | ||
params = { | ||
Key: filename, | ||
Bucket: this.bucket | ||
}; | ||
resolver = function(resolve, reject) { | ||
_this.s3.headObject(params, function (err, data) { | ||
if (err) return reject(err); | ||
resolve(data); | ||
}); | ||
}; | ||
return new Promise(resolver).nodeify(callback); | ||
}; | ||
module.exports = BloodySimpleS3; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15524
323
64
4
+ Addedtype-of@^2.0.1
+ Addedtype-of@2.0.1(transitive)
Updatedaws-sdk@^2.1.28