-
-
Notifications
You must be signed in to change notification settings - Fork 158
Expand file tree
/
Copy pathcookies.js
More file actions
148 lines (113 loc) · 3.68 KB
/
cookies.js
File metadata and controls
148 lines (113 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
var base64 = require('base64-url')
var Keygrip = require('keygrip')
var Cookie = require('./cookie')
var utils = require('./utils')
var getPattern = utils.getPattern
var pushCookie = utils.pushCookie
var merge = utils.merge
module.exports = function (options, keys) {
if (Array.isArray(options)
|| (options && options.constructor && options.constructor.name === 'Keygrip')) {
keys = options
options = {}
}
options = options || {}
keys = keys || options.keys
if (Array.isArray(keys)) keys = new Keygrip(keys)
function Cookies(req, res, next) {
if (!(this instanceof Cookies)) return new Cookies(req, res, next)
this.req = req
this.res = res
// middleware support
if (typeof next === 'function') {
req.cookies = res.cookies = this
next()
}
}
Cookies.prototype.get = function (name) {
var header = this.req.headers.cookie
if (!header) return
var match = header.match(getPattern(name))
if (!match) return
return match[1]
}
Cookies.prototype.set = function (name, value, opts) {
opts = this.extend(opts)
var res = this.res
var headers = res.getHeader('Set-Cookie') || []
// node.js header sillyness
if (typeof headers == "string") headers = [headers]
var cookie = new Cookie(name, value, opts)
headers = pushCookie(headers, cookie)
res.setHeader('Set-Cookie', headers)
return this
}
Cookies.prototype.decode = function (name, buffer) {
var value = this.get(name)
if (!value) return
var buf = new Buffer(base64.unescape(value), 'base64')
if (buffer) return buf
return buf.toString('utf8')
}
Cookies.prototype.encode = function (name, value, opts) {
opts = this.extend(opts)
var digest = base64.escape(new Buffer(value, 'utf8').toString('base64'))
this.set(name, digest, opts)
return this
}
Cookies.prototype.unsign = function (name, opts) {
opts = this.extend(opts)
assertKeys()
var value = opts.encoded
? this.decode(name + '.b64')
: this.get(name)
if (!value) return
var remote = this.decode(name + '.sig', true)
if (!remote) return // no signature
var data = name + '=' + value
var index = keys.index(data, remote)
// invalid signature, so we clear it
if (index < 0) return this.clear(name + '.sig', opts)
// update the signature to the latest key
// to do: update the original cookie as well
if (index > 0) this.encode(name + '.sig', data, opts)
return value
}
Cookies.prototype.sign = function (name, value, opts) {
opts = this.extend(opts)
assertKeys()
if (opts.encoded) this.encode(name + '.b64', value, opts)
else this.set(name, value, opts)
this.encode(name + '.sig', keys.sign(name + '=' + value), opts)
return this
}
Cookies.prototype.decrypt = function (name, opts) {
opts = this.extend(opts)
assertKeys()
var value = this.decode(name + '.enc', true)
if (!value) return
var msg = keys.decrypt(value)
if (!msg) return // bad decryption
// re-encrypt if not using the latest key
if (msg[1] > 0) this.encrypt(name, msg[0], opts)
return msg[0].toString('utf8')
}
Cookies.prototype.encrypt = function (name, value, opts) {
opts = this.extend(opts)
assertKeys()
this.encode(name + '.enc', keys.encrypt(value), opts)
return this
}
// clear a cookie
Cookies.prototype.clear = function (name, opts) {
this.set(name, null, opts)
}
// inherit the options from the main options
Cookies.prototype.extend = function (opts) {
return merge(Object.create(options), opts || {})
}
return Cookies
function assertKeys() {
if (!keys) throw new Error('.keys required for signed cookies')
}
}