Skip to content

Commit 97dcc90

Browse files
committed
fix: support cookie v2.x
v2 removed the / exports in favour of /, which broke every route that sets or reads a cookie (all requests returned 500). - adapt to the new cookie@2 API while keeping the historic / signatures for @fastify/cookie's own public API (fastify.parseCookie, fastify.serializeCookie, module.exports.parse/serialize) - bump the dependency to ^2.0.0 - fix README links that pointed to now-outdated v1 anchors
1 parent 172ffc6 commit 97dcc90

3 files changed

Lines changed: 59 additions & 33 deletions

File tree

README.md

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ upon this plugin's actions.
1414
It is also possible to [import the low-level cookie parsing and serialization functions](#importing-serialize-and-parse).
1515

1616
## Install
17+
1718
```sh
1819
npm i @fastify/cookie
1920
```
2021

2122
### Compatibility
23+
2224
| Plugin version | Fastify version |
2325
| ---------------|-----------------|
2426
| `>=10.x` | `^5.x` |
@@ -162,14 +164,13 @@ attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not.
162164

163165
More information about this can be found in [the proposal](https://github.com/privacycg/CHIPS).
164166

165-
166167
##### priority
167168

168169
Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/draft-west-cookie-priority-00#section-4.1).
169170

170-
- `'low'` will set the `Priority` attribute to `Low`.
171-
- `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
172-
- `'high'` will set the `Priority` attribute to `High`.
171+
- `'low'` will set the `Priority` attribute to `Low`.
172+
- `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
173+
- `'high'` will set the `Priority` attribute to `High`.
173174

174175
More information about the different priority levels can be found in
175176
[the specification](https://datatracker.ietf.org/doc/html/draft-west-cookie-priority-00#section-4.1).
@@ -185,11 +186,11 @@ is considered the ["default path"](https://datatracker.ietf.org/doc/html/rfc6265
185186

186187
Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).
187188

188-
- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
189-
- `false` will not set the `SameSite` attribute.
190-
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
191-
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
192-
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
189+
- `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
190+
- `false` will not set the `SameSite` attribute.
191+
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
192+
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
193+
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
193194

194195
More information about the different enforcement levels can be found in
195196
[the specification](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).
@@ -214,7 +215,7 @@ as an object named `cookies`. Thus, if a request contains the header
214215
`Cookie: foo=foo` then, within your handler, `req.cookies.foo` would equal
215216
`'foo'`.
216217

217-
You can pass options to the [cookie parse](https://github.com/jshttp/cookie#cookieparsestr-options) by setting an object named `parseOptions` in the plugin config object.
218+
You can pass options to the [cookie parse](https://github.com/jshttp/cookie#cookieparsecookiestr-options) by setting an object named `parseOptions` in the plugin config object.
218219

219220
### Sending
220221

@@ -223,11 +224,11 @@ via the Fastify `decorateReply` API. Thus, in a request handler,
223224
`reply.setCookie('foo', 'foo', {path: '/'})` will set a cookie named `foo`
224225
with a value of `'foo'` on the cookie path `/`.
225226

226-
+ `name`: a string name for the cookie to be set
227-
+ `value`: a string value for the cookie
228-
+ `options`: an options object as described in the [cookie serialize][cs] documentation
229-
+ `options.signed`: the cookie should be signed
230-
+ `options.secure`: if set to `true` it will set the Secure-flag. If it is set to `"auto"` Secure-flag is set when the connection is using tls.
227+
- `name`: a string name for the cookie to be set
228+
- `value`: a string value for the cookie
229+
- `options`: an options object as described in the [cookie serialize][cs] documentation
230+
- `options.signed`: the cookie should be signed
231+
- `options.secure`: if set to `true` it will set the Secure-flag. If it is set to `"auto"` Secure-flag is set when the connection is using tls.
231232

232233
#### Securing the cookie
233234

@@ -245,8 +246,8 @@ via the Fastify `decorateReply` API. Thus, in a request handler,
245246
`reply.clearCookie('foo', {path: '/'})` will clear a cookie named `foo`
246247
on the cookie path `/`.
247248

248-
+ `name`: a string name for the cookie to be cleared
249-
+ `options`: an options object as described in the [cookie serialize][cs]
249+
- `name`: a string name for the cookie to be cleared
250+
- `options`: an options object as described in the [cookie serialize][cs]
250251
documentation. It is optional to pass an `options` object
251252

252253
### Manual cookie parsing
@@ -255,14 +256,16 @@ The method `parseCookie(cookieHeader)` is added to the `fastify` instance
255256
via the Fastify `decorate` API. Thus, `fastify.parseCookie('sessionId=aYb4uTIhdBXC')`
256257
will parse the raw cookie header and return an object `{ "sessionId": "aYb4uTIhdBXC" }`.
257258

258-
[cs]: https://www.npmjs.com/package/cookie#options-1
259+
[cs]: https://github.com/jshttp/cookie#cookiestringifysetcookiesetcookieobj-options
259260

260261
<a id="rotating-secret"></a>
262+
261263
### Rotating signing secret
262264

263265
Key rotation is when an encryption key is retired and replaced by generating a new cryptographic key. To implement rotation, supply an `Array` of keys to `secret` option.
264266

265267
**Example:**
268+
266269
```js
267270
fastify.register(require('@fastify/cookie'), {
268271
secret: [key1, key2]
@@ -272,11 +275,13 @@ fastify.register(require('@fastify/cookie'), {
272275
The plugin will **always** use the first key (`key1`) to sign cookies. When parsing incoming cookies, it will iterate over the supplied array to see if any of the available keys are able to decode the given signed cookie. This ensures that any old signed cookies are still valid.
273276

274277
Note:
278+
275279
- Key rotation is **only** achieved by redeploying the server again with the new `secret` array.
276280
- Iterating through all secrets is an expensive process, so the rotation list should contain as few keys as possible. Ideally, only the current key and the most recently retired key.
277281
- Although previously signed cookies are valid even after rotation, cookies should be updated with the new key as soon as possible. See the following example for how to accomplish this.
278282

279283
**Example:**
284+
280285
```js
281286
fastify.get('/', (req, reply) => {
282287
const result = reply.unsignCookie(req.cookies.myCookie)
@@ -293,11 +298,13 @@ fastify.get('/', (req, reply) => {
293298
```
294299

295300
<a id="custom-cookie-signer"></a>
301+
296302
### Custom cookie signer
297303

298304
The `secret` option optionally accepts an object with `sign` and `unsign` functions. This allows for implementing a custom cookie signing mechanism. See the following example:
299305

300306
**Example:**
307+
301308
```js
302309
fastify.register(require('@fastify/cookie'), {
303310
secret: {
@@ -382,7 +389,6 @@ const signedValue = fastifyCookie.sign('test', 'secret');
382389
const unsignedvalue = fastifyCookie.unsign(signedValue, 'secret');
383390
```
384391

385-
386392
## License
387393

388394
Licensed under [MIT](./LICENSE).

index.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
'use strict'
22

33
const fp = require('fastify-plugin')
4-
const cookie = require('cookie')
4+
const { parseCookie: cookieParse, stringifySetCookie } = require('cookie')
55

66
const { Signer, sign, unsign } = require('./signer')
77

8+
function parse (str, options) {
9+
return cookieParse(str, options)
10+
}
11+
12+
function serialize (name, value, options) {
13+
return stringifySetCookie(Object.assign({ name, value }, options))
14+
}
15+
816
const kReplySetCookies = Symbol('fastify.reply.setCookies')
917
const kReplySetCookiesHookRan = Symbol('fastify.reply.setCookiesHookRan')
1018

@@ -29,7 +37,11 @@ function fastifyCookieSetCookie (reply, name, value, options) {
2937
}
3038
}
3139

32-
reply[kReplySetCookies].set(`${name};${opts.domain};${opts.path || '/'}`, { name, value, opts })
40+
reply[kReplySetCookies].set(`${name};${opts.domain};${opts.path || '/'}`, {
41+
name,
42+
value,
43+
opts
44+
})
3345

3446
if (reply[kReplySetCookiesHookRan]) {
3547
setCookies(reply)
@@ -77,7 +89,7 @@ function setCookies (reply) {
7789
if (reply[kReplySetCookies].size === 1) {
7890
// Fast path for single cookie
7991
const c = reply[kReplySetCookies].values().next().value
80-
reply.header('Set-Cookie', cookie.serialize(c.name, c.value, c.opts))
92+
reply.header('Set-Cookie', serialize(c.name, c.value, c.opts))
8193
reply[kReplySetCookies].clear()
8294
return
8395
}
@@ -90,7 +102,7 @@ function setCookies (reply) {
90102
}
91103

92104
for (const c of reply[kReplySetCookies].values()) {
93-
cookieValue.push(cookie.serialize(c.name, c.value, c.opts))
105+
cookieValue.push(serialize(c.name, c.value, c.opts))
94106
}
95107

96108
reply.removeHeader('Set-Cookie')
@@ -117,12 +129,20 @@ function plugin (fastify, options, next) {
117129
const secret = options.secret
118130
const hook = getHook(options.hook)
119131
if (hook === undefined) {
120-
return next(new Error('@fastify/cookie: Invalid value provided for the hook-option. You can set the hook-option only to false, \'onRequest\' , \'preParsing\' , \'preValidation\' or \'preHandler\''))
121-
}
122-
const isSigner = !secret || (typeof secret.sign === 'function' && typeof secret.unsign === 'function')
123-
const signer = isSigner ? secret : new Signer(secret, options.algorithm || 'sha256')
124-
125-
fastify.decorate('serializeCookie', cookie.serialize)
132+
return next(
133+
new Error(
134+
"@fastify/cookie: Invalid value provided for the hook-option. You can set the hook-option only to false, 'onRequest' , 'preParsing' , 'preValidation' or 'preHandler'"
135+
)
136+
)
137+
}
138+
const isSigner =
139+
!secret ||
140+
(typeof secret.sign === 'function' && typeof secret.unsign === 'function')
141+
const signer = isSigner
142+
? secret
143+
: new Signer(secret, options.algorithm || 'sha256')
144+
145+
fastify.decorate('serializeCookie', serialize)
126146
fastify.decorate('parseCookie', parseCookie)
127147

128148
if (secret !== undefined) {
@@ -153,7 +173,7 @@ function plugin (fastify, options, next) {
153173

154174
// ***************************
155175
function parseCookie (cookieHeader) {
156-
return cookie.parse(cookieHeader, options.parseOptions)
176+
return parse(cookieHeader, options.parseOptions)
157177
}
158178

159179
function signCookie (value) {
@@ -206,8 +226,8 @@ module.exports = fastifyCookie
206226
module.exports.default = fastifyCookie // supersedes fastifyCookie.default = fastifyCookie
207227
module.exports.fastifyCookie = fastifyCookie // supersedes fastifyCookie.fastifyCookie = fastifyCookie
208228

209-
module.exports.serialize = cookie.serialize
210-
module.exports.parse = cookie.parse
229+
module.exports.serialize = serialize
230+
module.exports.parse = parse
211231

212232
module.exports.signerFactory = Signer
213233
module.exports.Signer = Signer

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"tstyche": "^7.0.0"
6969
},
7070
"dependencies": {
71-
"cookie": "^1.0.0",
71+
"cookie": "^2.0.0",
7272
"fastify-plugin": "^6.0.0"
7373
},
7474
"publishConfig": {

0 commit comments

Comments
 (0)