Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyruppel committed Mar 23, 2016
0 parents commit 3b3ba47
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 0 deletions.
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

# Created by https://www.gitignore.io/api/node

### Node ###
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history

20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 Yahoo Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
hooks: .git/hooks/pre-commit
hooks: .git/hooks/pre-push

.git/hooks/pre-commit: hook.sh
cp $< $@

.git/hooks/pre-push: hook.sh
cp $< $@
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# incoming-message-hash

Generate a one-way hash from an [http.IncomingMessage][]

## install

``` bash
$ npm install incoming-message-hash --save
```

## example

This example demonstrates how the hashing function returns a different hash based on the IncomingMessage's method, path, query string, headers and body.

``` js
var hash = require('incoming-message-hash');
var http = require('http');

http.createServer(function (req, res) {
req.pipe(hash()).pipe(res);
}).listen(4567, function () {
console.log('Server is listening on port 4567');
});
```

``` bash
$ curl http://localhost:4567; echo
e91caf6d7b009b5af0fb2e18cff95598
$ curl http://localhost:4567/foo; echo
2f24d536fd0ca7c4eb72a8d64440066f
$ curl http://localhost:4567/foo?a=b; echo
0bb92c398df54668d9020b835c345cb8
$ curl http://localhost:4567/foo?a=c; echo
02bd995c9ebccfc0332619a03ce0a688
$ curl -H "Host: www.flickr.com" http://localhost:4567; echo
ce8f3e6257911a9499923d0deebe56b5
$ curl -X POST http://localhost:4567; echo
41ba64dca3f3070b361b302a17742973
$ curl -X POST -d "yay" http://localhost:4567; echo
64ae029a6a4add75fadb03811a13caa7
```

## usage

``` js
var hash = require('incoming-message-hash');
```

### hash(algorithm='md5', encoding='hex')

Returns a new [crypto.Hash][] stream using the specified algorithm and encoding (defaults to "md5" and "hex"). You can pipe your [http.IncomingMessage][] in and get a hash back.

[http.IncomingMessage]: https://nodejs.org/api/http.html#http_class_http_incomingmessage
[crypto.Hash]: https://nodejs.org/api/crypto.html#crypto_class_hash

## license

This software is free to use under the MIT license. See the [LICENSE][] file for license text and copyright information.

[LICENSE]: https://github.com/flickr/incoming-message-hash/blob/master/LICENSE
11 changes: 11 additions & 0 deletions example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.

var hash = require(__dirname);
var http = require('http');

http.createServer(function (req, res) {
req.pipe(hash()).pipe(res);
}).listen(4567, function () {
console.log('Server is listening on port 4567');
});
7 changes: 7 additions & 0 deletions hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

set -ex

npm test

node package.json
36 changes: 36 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.

var crypto = require('crypto');
var url = require('url');

module.exports = createHash;

function createHash(algorithm, encoding) {
var hash = crypto.createHash(algorithm || 'md5');

hash.setEncoding(encoding || 'hex');

hash.on('pipe', function (req) {
var parts = url.parse(req.url, true);

hash.update(req.httpVersion);
hash.update(req.method);
hash.update(parts.pathname);
hash.update(JSON.stringify(sort(parts.query)));
hash.update(JSON.stringify(sort(req.headers)));
hash.update(JSON.stringify(sort(req.trailers)));
});

return hash;
}

function sort(obj) {
var ret = {};

Object.keys(obj).sort().forEach(function (key) {
ret[key] = obj[key];
});

return ret;
}
27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "incoming-message-hash",
"version": "3.1.3",
"description": "Generate a one-way hash from an http.IncomingMessage",
"main": "index.js",
"scripts": {
"test": "mocha test.js"
},
"keywords": [
"http",
"https",
"IncomingMessage",
"request",
"hash",
"md5",
"crypto",
"stream",
"fingerprint"
],
"author": "Jeremy Ruppel",
"license": "MIT",
"devDependencies": {
"mocha": "~2.4.5",
"supertest": "~1.1.0"
},
"dependencies": {}
}
75 changes: 75 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.

var subject = require(__dirname);
var request = require('supertest');

describe('hash', function() {
function app(algorithm, encoding) {
return function (req, res) {
req.pipe(subject(algorithm, encoding)).pipe(res);
};
}

it('hashes an http.IncomingMessage', function(done) {
request(app())
.get('/')
.set('host', 'localhost:4567')
.expect('09a3df93c944461cee09969f2a4bb848', done);
});
it('produces a different hash for a different path', function(done) {
request(app())
.get('/quux')
.set('host', 'localhost:4567')
.expect('85713c266b81f0be1d61b281405bafc0', done);
});
it('produces a different hash for a different query string', function (done) {
request(app())
.get('/?foo=1')
.set('host', 'localhost:4567')
.expect('f688a385e4fad0700c0db23f6d2c7434', done);
});
it('produces a different hash for a different method', function(done) {
request(app())
.post('/')
.set('host', 'localhost:4567')
.expect('31c4e9ea422c968d96092259bdca158e', done);
});
it('produces a different hash for different headers', function(done) {
request(app())
.get('/')
.set('host', 'localhost:4567')
.set('x-foo', 'bar')
.expect('46e486ddb60f2236f77c8bbe29d6c760', done);
});
it('produces a different hash for a different post body', function (done) {
request(app())
.post('/')
.set('host', 'localhost:4567')
.send('yay')
.expect('e84cf2827fbc172a5957e3b29a1f47d5', done);
});
it('produces the same hash for different ordered query params', function (done) {
request(app())
.get('/?foo=1&bar=2')
.set('host', 'localhost:4567')
.expect('2f8a8a2c8b6f286e65848160ba8c6ab1', function () {
request(app())
.get('/?bar=2&foo=1')
.set('host', 'localhost:4567')
.expect('2f8a8a2c8b6f286e65848160ba8c6ab1', done);
});
});
it('can use a different hash algorithm', function(done) {
request(app('sha1'))
.get('/')
.set('host', 'localhost:4567')
.expect('d8b3b0f8af8babb29291719b3bbbaa45b1aaaa85', done);
});
it('can use a different encoding', function(done) {
request(app('md5', 'base64'))
.get('/')
.set('host', 'localhost:4567')
.expect('CaPfk8lERhzuCZafKku4SA==', done);
});
});

0 comments on commit 3b3ba47

Please sign in to comment.