Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 104 lines (69 sloc) 3.724 kb
1511dd7 @jed fleshed out README, added capitalization
jed authored
1 Keygrip
a2d85bf @jed oops, wrong README.
jed authored
2 =======
ea228fc @jed first commit, code coming.
jed authored
3
ecd46e5 @jed add travis-ci
jed authored
4 [![Build Status](https://secure.travis-ci.org/jed/keygrip.png)](http://travis-ci.org/jed/keygrip)
ea228fc @jed first commit, code coming.
jed authored
5
ecd46e5 @jed add travis-ci
jed authored
6 Keygrip is a [node.js](http://nodejs.org/) module for signing and verifying data (such as cookies or URLs) through a rotating credential system, in which new server keys can be added and old ones removed regularly, without invalidating client credentials.
ea228fc @jed first commit, code coming.
jed authored
7
a2d85bf @jed oops, wrong README.
jed authored
8 ## Install
ea228fc @jed first commit, code coming.
jed authored
9
a2d85bf @jed oops, wrong README.
jed authored
10 $ npm install keygrip
f8a83f1 @jed more formatting
jed authored
11
1511dd7 @jed fleshed out README, added capitalization
jed authored
12 ## API
13
f8a83f1 @jed more formatting
jed authored
14 ### keys = new Keygrip([keylist])
1511dd7 @jed fleshed out README, added capitalization
jed authored
15
a9690c2 @jed added that keys are stored in a closure
jed authored
16 This creates a new Keygrip based on the provided keylist, an array of secret keys used for SHA1 HMAC digests. If no list is given, or the list is empty, Keygrip uses the default key created during `npm` installation, and will issue a warning to the console.
1511dd7 @jed fleshed out README, added capitalization
jed authored
17
f8a83f1 @jed more formatting
jed authored
18 Note that the `new` operator is also optional, so all of the following will work when `Keygrip = require("keygrip")`:
1511dd7 @jed fleshed out README, added capitalization
jed authored
19
ce75ac0 @jed syntax highlighting
jed authored
20 ```javascript
21 keys = new Keygrip
f8a83f1 @jed more formatting
jed authored
22 keys = new Keygrip(["SEKRIT2", "SEKRIT1"])
ce75ac0 @jed syntax highlighting
jed authored
23 keys = Keygrip()
f8a83f1 @jed more formatting
jed authored
24 keys = Keygrip(["SEKRIT2", "SEKRIT1"])
25 keys = require("keygrip")()
ce75ac0 @jed syntax highlighting
jed authored
26 ```
f8a83f1 @jed more formatting
jed authored
27
1511dd7 @jed fleshed out README, added capitalization
jed authored
28 The keylist is an array of all valid keys for signing, in descending order of freshness; new keys should be `unshift`ed into the array and old keys should be `pop`ped.
29
30 The tradeoff here is that adding more keys to the keylist allows for more granular freshness for key validation, at the cost of a more expensive worst-case scenario for old or invalid hashes.
31
a9690c2 @jed added that keys are stored in a closure
jed authored
32 Keygrip keeps a reference to this array to automatically reflect any changes. This reference is stored using a closure to prevent external access.
33
f8a83f1 @jed more formatting
jed authored
34 ### keys.sign(data)
1511dd7 @jed fleshed out README, added capitalization
jed authored
35
36 This creates a SHA1 HMAC based on the _first_ key in the keylist, and outputs it as a 27-byte url-safe base64 digest (base64 without padding, replacing `+` with `-` and `/` with `_`).
37
f8a83f1 @jed more formatting
jed authored
38 ### keys.index(data, digest)
1511dd7 @jed fleshed out README, added capitalization
jed authored
39
40 This loops through all of the keys currently in the keylist until the digest of the current key matches the given digest, at which point the current index is returned. If no key is matched, `-1` is returned.
41
42 The idea is that if the index returned is greater than `0`, the data should be re-signed to prevent premature credential invalidation, and enable better performance for subsequent challenges.
43
f8a83f1 @jed more formatting
jed authored
44 ### keys.verify(data, digest)
e6c3de3 @jed updated README with .index
jed authored
45
46 This uses `index` to return `true` if the digest matches any existing keys, and `false` otherwise.
47
c60811d @jed npm now auto-creates default key during install
jed authored
48 ## Example
ea228fc @jed first commit, code coming.
jed authored
49
ce75ac0 @jed syntax highlighting
jed authored
50 ```javascript
51 // ./test.js
f8a83f1 @jed more formatting
jed authored
52 var assert = require("assert")
53 , Keygrip = require("keygrip")
ce75ac0 @jed syntax highlighting
jed authored
54 , keylist, keys, hash, index
55
56 // keygrip takes an array of keys, but if none exist,
57 // it uses the defaults created during npm installation.
58 // (but it'll will warn you)
f8a83f1 @jed more formatting
jed authored
59 console.log("Ignore this message:")
60 keys = new Keygrip(/* empty list */)
ce75ac0 @jed syntax highlighting
jed authored
61
62 // .sign returns the hash for the first key
63 // all hashes are SHA1 HMACs in url-safe base64
f8a83f1 @jed more formatting
jed authored
64 hash = keys.sign("bieberschnitzel")
65 assert.ok(/^[\w\-]{27}$/.test(hash))
ce75ac0 @jed syntax highlighting
jed authored
66
67 // but we're going to use our list.
68 // (note that the 'new' operator is optional)
f8a83f1 @jed more formatting
jed authored
69 keylist = ["SEKRIT3", "SEKRIT2", "SEKRIT1"]
70 keys = Keygrip(keylist)
71 hash = keys.sign("bieberschnitzel")
ce75ac0 @jed syntax highlighting
jed authored
72
73 // .index returns the index of the first matching key
f8a83f1 @jed more formatting
jed authored
74 index = keys.index("bieberschnitzel", hash)
75 assert.equal(index, 0)
ce75ac0 @jed syntax highlighting
jed authored
76
77 // .verify returns the a boolean indicating a matched key
f8a83f1 @jed more formatting
jed authored
78 matched = keys.verify("bieberschnitzel", hash)
79 assert.ok(matched)
ce75ac0 @jed syntax highlighting
jed authored
80
f8a83f1 @jed more formatting
jed authored
81 index = keys.index("bieberschnitzel", "o_O")
82 assert.equal(index, -1)
ce75ac0 @jed syntax highlighting
jed authored
83
84 // rotate a new key in, and an old key out
f8a83f1 @jed more formatting
jed authored
85 keylist.unshift("SEKRIT4")
ce75ac0 @jed syntax highlighting
jed authored
86 keylist.pop()
87
88 // if index > 0, it's time to re-sign
f8a83f1 @jed more formatting
jed authored
89 index = keys.index("bieberschnitzel", hash)
90 assert.equal(index, 1)
91 hash = keys.sign("bieberschnitzel")
ce75ac0 @jed syntax highlighting
jed authored
92 ```
61d33da @jed updated README with .index
jed authored
93
1511dd7 @jed fleshed out README, added capitalization
jed authored
94 ## TODO
95
96 * Write a library for URL signing
78c41a4 @jed use test.js for README usage example.
jed authored
97
a2d85bf @jed oops, wrong README.
jed authored
98 Copyright
99 ---------
ea228fc @jed first commit, code coming.
jed authored
100
ecd46e5 @jed add travis-ci
jed authored
101 Copyright (c) 2012 Jed Schmidt. See LICENSE.txt for details.
ea228fc @jed first commit, code coming.
jed authored
102
f8a83f1 @jed more formatting
jed authored
103 Send any questions or comments [here](http://twitter.com/jedschmidt).
Something went wrong with that request. Please try again.