Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

knox

Package Overview
Dependencies
Maintainers
2
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knox - npm Package Compare versions

Comparing version 0.0.9 to 0.0.10

.npmignore

0

History.md

@@ -0,0 +0,0 @@

module.exports = require('./lib/knox');

6

lib/knox/auth.js

@@ -182,5 +182,7 @@

Object.keys(url.query).forEach(function(key){
if (!~keys.indexOf(key)) return;
var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]);
buf.push(key + val);
if (key === '') // this is something like ?delete (which is part of the S3 api) so it has no key because there is no '='
buf.push(val.substring(1));
else
buf.push(key + val);
});

@@ -187,0 +189,0 @@

@@ -16,6 +16,9 @@

, url = require('url')
, join = require('path').join
, mime = require('./mime')
, fs = require('fs');
, fs = require('fs')
, crypto = require('crypto');
// The max for multi-object delete, bucket listings, etc.
var BUCKET_OPS_MAX = 1000;
/**

@@ -40,2 +43,3 @@ * Initialize a `Client` with the given `options`.

this.endpoint = options.bucket + '.s3.amazonaws.com';
this.port = 80;
utils.merge(this, options);

@@ -55,3 +59,3 @@ };

Client.prototype.request = function(method, filename, headers){
var options = { host: this.endpoint, port: 80 }
var options = { host: this.endpoint, port: this.port }
, date = new Date

@@ -72,4 +76,5 @@ , headers = headers || {};

, date: date
, resource: auth.canonicalizeResource(join('/', this.bucket, filename))
, resource: auth.canonicalizeResource('/' + this.bucket + filename)
, contentType: headers['Content-Type']
, md5: headers['Content-MD5'] || ''
, amazonHeaders: auth.canonicalizeHeaders(headers)

@@ -80,3 +85,3 @@ });

options.method = method;
options.path = join('/', filename);
options.path = filename;
options.headers = headers;

@@ -130,2 +135,23 @@ var req = http.request(options);

/**
* Copy files from `sourceFilename` to `destFilename` with optional `headers`.
*
* @param {String} sourceFilename
* @param {String} destFilename
* @param {Object} headers
* @return {ClientRequest}
* @api public
*/
Client.prototype.copy = function(sourceFilename, destFilename, headers){
headers = utils.merge({
Expect: '100-continue'
, 'x-amz-acl': 'public-read'
}, headers || {});
headers['x-amz-copy-source'] = '/' + this.bucket + sourceFilename;
headers['Content-Length'] = 0; // to avoid Node's automatic chunking if omitted
return this.request('PUT', destFilename, headers);
};
/**
* PUT the file at `src` to `filename`, with callback `fn`

@@ -164,2 +190,3 @@ * receiving a possible exception, and the response object.

, 'Content-Type': mime.lookup(src)
, 'Content-MD5': crypto.createHash('md5').update(buf).digest('base64')
}, headers);

@@ -199,3 +226,3 @@ self.put(filename, headers).on('response', function(res){

stream
.on('error', function(err){fn(null, err); })
.on('error', function(err){fn(err); })
.on('data', function(chunk){ req.write(chunk); })

@@ -305,3 +332,53 @@ .on('end', function(){ req.end(); });

function xmlEscape(string) {
return string.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
function makeDeleteXmlString(keys) {
var tags = keys.map(function (key) {
return "<Object><Key>" + xmlEscape(key) + "</Key></Object>";
});
return "<Delete>" + tags.join("") + "</Delete>";
}
/**
* Delete up to 1000 files at a time, with optional `headers`
* and callback `fn` with a possible exception and the response.
*
* @param {Array[String]} filenames
* @param {Object|Function} headers
* @param {Function} fn
* @api public
*/
Client.prototype.deleteMultiple = function(filenames, headers, fn){
if (filenames.length > BUCKET_OPS_MAX) {
throw new Error('Can only delete up to ' + BUCKET_OPS_MAX + ' files ' +
'at a time. You\'ll need to batch them.');
}
if ('function' == typeof headers) {
fn = headers;
headers = {};
}
var xml = makeDeleteXmlString(filenames);
headers['Content-Length'] = xml.length;
headers['Content-MD5'] = crypto.createHash('md5').update(xml).digest('base64');
return this.request('POST', '/?delete', headers)
.on('response', function(res){
fn(null, res);
})
.on('error', function(err){
fn(err);
})
.end(xml);
};
/**
* Return a url to the given `filename`.

@@ -316,3 +393,3 @@ *

Client.prototype.http = function(filename){
return 'http://' + join(this.endpoint, filename);
return 'http://' + this.endpoint + filename;
};

@@ -329,3 +406,3 @@

Client.prototype.https = function(filename){
return 'https://' + join(this.endpoint, filename);
return 'https://' + this.endpoint + filename;
};

@@ -347,3 +424,3 @@

date: epoch,
resource: '/' + this.bucket + url.parse(filename).pathname
resource: '/' + url.parse(filename).pathname
});

@@ -350,0 +427,0 @@

@@ -0,0 +0,0 @@

@@ -162,2 +162,3 @@ var path = require('path');

, "ogm" : "application/ogg"
, "ogv" : "video/ogg"
, "p" : "text/x-pascal"

@@ -255,2 +256,3 @@ , "pas" : "text/x-pascal"

, "wax" : "audio/x-ms-wax"
, "webm" : "video/webm"
, "wma" : "audio/x-ms-wma"

@@ -257,0 +259,0 @@ , "wmv" : "video/x-ms-wmv"

@@ -0,0 +0,0 @@ {

@@ -0,0 +0,0 @@ A library for doing simple mime-type lookups.

@@ -0,0 +0,0 @@

@@ -5,3 +5,3 @@ {

"keywords": ["aws", "amazon", "s3"],
"version": "0.0.9",
"version": "0.0.10",
"author": "TJ Holowaychuk <tj@learnboost.com>",

@@ -13,3 +13,9 @@ "main": "./index.js",

"url": "git://github.com/LearnBoost/knox.git"
},
"devDependencies": {
"mocha": "*"
},
"scripts": {
"test": "mocha"
}
}

@@ -8,4 +8,3 @@

- Not outdated :), developed for node 0.2.x
- RESTful api (`client.get()`, `client.put()`, etc)
- Familiar API (`client.get()`, `client.put()`, etc)
- Uses node's crypto library (fast!, the others used native js)

@@ -17,17 +16,22 @@ - Very node-like low-level request api via `http.Client`

- TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
- TJ Holowaychuk ([visionmedia](https://github.com/visionmedia))
- Domenic Denicola ([domenic](https://github.com/domenic))
## Examples
The following examples demonstrate some capabilities of knox and the s3 REST API. First things first, create an s3 client:
The following examples demonstrate some capabilities of knox and the S3 REST
API. First things first, create an S3 client:
var client = knox.createClient({
key: '<api-key-here>'
, secret: '<secret-here>'
, bucket: 'learnboost'
});
```js
var client = knox.createClient({
key: '<api-key-here>'
, secret: '<secret-here>'
, bucket: 'learnboost'
});
```
By default knox will send all requests to the global endpoint (bucket.s3.amazonaws.com).
This works regardless of the region where the bucket is. But if you want to manually set
the endpoint (for performance reasons) you can do it with the `endpoint` option.
By default knox will send all requests to the global endpoint
(bucket.s3.amazonaws.com). This works regardless of the region where the bucket
is. But if you want to manually set the endpoint (for performance reasons) you
can do it with the `endpoint` option.

@@ -39,72 +43,100 @@ ### PUT

filename as the first parameter (_/test/Readme.md_), and some headers. Then
we listen for the _response_ event, just as we would for any `http.Client` request, if we have a 200 response, great! output the destination url to stdout.
we listen for the _response_ event, just as we would for any `http.Client`
request, if we have a 200 response, great! output the destination url to
stdout.
fs.readFile('Readme.md', function(err, buf){
var req = client.put('/test/Readme.md', {
'Content-Length': buf.length
, 'Content-Type': 'text/plain'
});
req.on('response', function(res){
if (200 == res.statusCode) {
console.log('saved to %s', req.url);
}
});
req.end(buf);
});
```js
fs.readFile('Readme.md', function(err, buf){
var req = client.put('/test/Readme.md', {
'Content-Length': buf.length
, 'Content-Type': 'text/plain'
});
req.on('response', function(res){
if (200 == res.statusCode) {
console.log('saved to %s', req.url);
}
});
req.end(buf);
});
```
By default the _x-amz-acl_ header is _public-read_, meaning anyone can __GET__ the file. To alter this simply pass this header to the client request method. Note that the field name __MUST__ be lowercase, do not use 'X-Amz-Acl' etc, as this will currently result in duplicate headers (although different case).
By default the _x-amz-acl_ header is _public-read_, meaning anyone can __GET__
the file. To alter this simply pass this header to the client request method.
Note that the field name __MUST__ be lowercase, do not use 'X-Amz-Acl' etc, as
this will currently result in duplicate headers (although different case).
client.put('/test/Readme.md', { 'x-amz-acl': 'private' });
```js
client.put('/test/Readme.md', { 'x-amz-acl': 'private' });
```
Each HTTP verb has an alternate method with the "File" suffix, for example `put()` also has a higher level method named `putFile()`, accepting a src filename and performs the dirty work shown above for you. Here is an example usage:
Each HTTP verb has an alternate method with the "File" suffix, for example
`put()` also has a higher level method named `putFile()`, accepting a src
filename and performs the dirty work shown above for you. Here is an example
usage:
client.putFile('my.json', '/user.json', function(err, res){
// Logic
});
```js
client.putFile('my.json', '/user.json', function(err, res){
// Logic
});
```
Another alternative is to stream via `Client#putStream()`, for example:
var stream = fs.createReadStream('data.json');
client.putStream(stream, '/some-data.json', function(err, res){
// Logic
});
```js
var stream = fs.createReadStream('data.json');
client.putStream(stream, '/some-data.json', function(err, res){
// Logic
});
```
(Note that this only works with file streams currently.)
An example of moving a file:
client.put('0/0/0.png', {
'Content-Type': 'image/jpg',
'Content-Length': '0',
'x-amz-copy-source': '/test-tiles/0/0/0.png',
'x-amz-metadata-directive': 'REPLACE'
}).on('response', function(res) {
// Logic
}).end();
```js
client.put('0/0/0.png', {
'Content-Type': 'image/jpg'
, 'Content-Length': '0'
, 'x-amz-copy-source': '/test-tiles/0/0/0.png'
, 'x-amz-metadata-directive': 'REPLACE'
}).on('response', function(res) {
// Logic
}).end();
```
### GET
Below is an example __GET__ request on the file we just shoved at s3, and simply outputs the response status code, headers, and body.
Below is an example __GET__ request on the file we just shoved at S3. It simply
outputs the response status code, headers, and body.
client.get('/test/Readme.md').on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
res.setEncoding('utf8');
res.on('data', function(chunk){
console.log(chunk);
});
}).end();
```js
client.get('/test/Readme.md').on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
res.setEncoding('utf8');
res.on('data', function(chunk){
console.log(chunk);
});
}).end();
```
## DELETE
### DELETE
Delete our file:
client.del('/test/Readme.md').on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
}).end();
```js
client.del('/test/Readme.md').on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
}).end();
```
Likewise we also have `client.deleteFile()` as a more concise (yet less flexible) solution:
Likewise we also have `client.deleteFile()` as a more concise (yet less
flexible) solution:
client.deleteFile('/test/Readme.md', function(err, res){
// Logic
});
```js
client.deleteFile('/test/Readme.md', function(err, res){
// Logic
});
```

@@ -116,9 +148,14 @@ ## Running Tests

{"key":"<api-key-here>",
"secret":"<secret-here>",
"bucket":"<your-bucket-name>"}
```json
{
"key":"<api-key-here>",
"secret":"<secret-here>",
"bucket":"<your-bucket-name>"
}
```
Then simply execute:
Then install the dev dependencies and execute the test suite:
$ make test
$ npm install
$ npm test

@@ -125,0 +162,0 @@ ## License

@@ -6,7 +6,8 @@

var knox = require('knox')
, auth = knox.auth;
var knox = require('..')
, auth = knox.auth
, assert = require('assert');
module.exports = {
'test .stringToSign()': function(assert){
'test .stringToSign()': function(){
var str = auth.stringToSign({

@@ -31,3 +32,3 @@ verb: 'PUT'

'test .sign()': function(assert){
'test .sign()': function(){
var str = auth.sign({

@@ -45,3 +46,3 @@ verb: 'PUT'

'test .canonicalizeHeaders()': function(assert){
'test .canonicalizeHeaders()': function(){
var str = auth.canonicalizeHeaders({

@@ -48,0 +49,0 @@ 'X-Amz-Date': 'some date'

@@ -6,4 +6,6 @@

var knox = require('knox')
, fs = require('fs');
var knox = require('..')
, fs = require('fs')
, assert = require('assert')
, crypto = require('crypto');

@@ -14,3 +16,3 @@ try {

} catch (err) {
console.error('`make test` requires ./auth to contain a JSON string with');
console.error('The tests require ./auth to contain a JSON string with');
console.error('`key, secret, and bucket in order to run tests.');

@@ -23,7 +25,7 @@ process.exit(1);

module.exports = {
'test .version': function(assert){
assert.match(knox.version, /^\d+\.\d+\.\d+$/);
'test .version': function(){
assert.ok(/^\d+\.\d+\.\d+$/.test(knox.version));
},
'test .createClient() invalid': function(assert){
'test .createClient() invalid': function(){
var err;

@@ -36,3 +38,3 @@ try {

assert.equal('aws "key" required', err.message);
var err;

@@ -45,3 +47,3 @@ try {

assert.equal('aws "secret" required', err.message);
var err;

@@ -55,4 +57,4 @@ try {

},
'test .createClient() valid': function(assert){
'test .createClient() valid': function(){
var client = knox.createClient({

@@ -63,3 +65,3 @@ key: 'foobar'

});
assert.equal('foobar', client.key);

@@ -70,4 +72,4 @@ assert.equal('baz', client.secret);

},
'test .createClient() custom endpoint': function(assert){
'test .createClient() custom endpoint': function(){
var client = knox.createClient({

@@ -83,8 +85,8 @@ key: 'foobar'

'test .putFile()': function(assert, done){
'test .putFile()': function(done){
var n = 0;
client.putFile(jsonFixture, '/test/user.json', function(err, res){
client.putFile(jsonFixture, '/test/user2.json', function(err, res){
assert.ok(!err, 'putFile() got an error!');
assert.equal(200, res.statusCode);
client.get('/test/user.json').on('response', function(res){
client.get('/test/user2.json').on('response', function(res){
assert.equal('application/json', res.headers['content-type']);

@@ -95,4 +97,4 @@ done();

},
'test .put()': function(assert, done){
'test .put()': function(done){
var n = 0;

@@ -111,6 +113,6 @@ fs.stat(jsonFixture, function(err, stat){

assert.equal(
'http://'+client.bucket+'.s3.amazonaws.com/test/user.json'
'http://'+client.endpoint+'/test/user.json'
, client.url('/test/user.json'));
assert.equal(
'http://'+client.bucket+'.s3.amazonaws.com/test/user.json'
'http://'+client.endpoint+'/test/user.json'
, req.url);

@@ -123,4 +125,4 @@ done();

},
'test .putStream()': function(assert, done){
'test .putStream()': function(done){
var stream = fs.createReadStream(jsonFixture);

@@ -133,4 +135,4 @@ client.putStream(stream, '/test/user.json', function(err, res){

},
'test .getFile()': function(assert, done){
'test .getFile()': function(done){
client.getFile('/test/user.json', function(err, res){

@@ -144,4 +146,4 @@ assert.ok(!err);

},
'test .get()': function(assert, done){
'test .get()': function(done){
client.get('/test/user.json').on('response', function(res){

@@ -154,4 +156,4 @@ assert.equal(200, res.statusCode);

},
'test .head()': function(assert, done){
'test .head()': function(done){
client.head('/test/user.json').on('response', function(res){

@@ -164,4 +166,4 @@ assert.equal(200, res.statusCode);

},
'test .headFile()': function(assert, done){
'test .headFile()': function(done){
client.headFile('/test/user.json', function(err, res){

@@ -175,4 +177,4 @@ assert.ok(!err);

},
'test .del()': function(assert, done){
'test .del()': function(done){
client.del('/test/user.json').on('response', function(res){

@@ -183,5 +185,5 @@ assert.equal(204, res.statusCode);

},
'test .deleteFile()': function(assert, done){
client.deleteFile('/test/user.json', function(err, res){
'test .deleteFile()': function(done){
client.deleteFile('/test/user2.json', function(err, res){
assert.ok(!err);

@@ -192,4 +194,32 @@ assert.equal(204, res.statusCode);

},
'test .get() 404': function(assert, done){
'test .deleteMultiple()': function(done){
client.deleteMultiple(['test/user.json', '/test/user2.json'],
function (err, res) {
assert.ok(!err);
assert.equal(200, res.statusCode);
done();
});
},
'test /?delete': function (done) {
var xml = ['<?xml version="1.0" encoding="UTF-8"?>\n','<Delete>'];
xml.push('<Object><Key>/test/user3.json</Key></Object>');
xml.push('</Delete>');
xml = xml.join('');
var req = client.request('POST', '/?delete', {
'Content-Length': xml.length,
'Content-MD5': crypto.createHash('md5').update(xml).digest('base64'),
'Accept:': '*/*',
}).on('error', function (err) {
assert.ok(!err);
}).on('response', function (res) {
assert.equal(200, res.statusCode);
done();
});
req.write(xml);
req.end();
},
'test .get() 404': function(done){
client.get('/test/user.json').on('response', function(res){

@@ -200,4 +230,4 @@ assert.equal(404, res.statusCode);

},
'test .head() 404': function(assert, done){
'test .head() 404': function(done){
client.head('/test/user.json').on('response', function(res){

@@ -204,0 +234,0 @@ assert.equal(404, res.statusCode);

@@ -6,13 +6,14 @@

var knox = require('knox')
, utils = knox.utils;
var knox = require('..')
, utils = knox.utils
, assert = require('assert');
module.exports = {
'test .base64.encode()': function(assert){
'test .base64.encode()': function(){
assert.equal('aGV5', utils.base64.encode('hey'));
},
'test .base64.decode()': function(assert){
'test .base64.decode()': function(){
assert.equal('hey', utils.base64.decode('aGV5'));
}
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc