Socket
Socket
Sign inDemoInstall

@fastify/cookie

Package Overview
Dependencies
Maintainers
19
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/cookie - npm Package Compare versions

Comparing version 8.3.0 to 9.0.0

benchmark/cookie-multi.js

18

package.json
{
"name": "@fastify/cookie",
"version": "8.3.0",
"version": "9.0.0",
"description": "Plugin for fastify to add support for cookies",

@@ -8,10 +8,10 @@ "main": "plugin.js",

"scripts": {
"coverage": "npm run test:unit -- --coverage-report=html",
"lint": "standard | snazzy",
"lint:ci": "standard",
"lint:fix": "standard --fix",
"test": "npm run unit && npm run typescript",
"typescript": "tsd",
"unit": "tap -J \"test/*.test.js\"",
"unit:report": "npm run unit -- --coverage-report=html",
"unit:verbose": "npm run unit -- -Rspec"
"test": "npm run test:unit && npm run test:typescript",
"test:typescript": "tsd",
"test:unit": "tap",
"test:unit:verbose": "npm run test:unit -- -Rspec"
},

@@ -44,10 +44,10 @@ "precommit": [

"@fastify/pre-commit": "^2.0.2",
"@types/node": "^18.0.0",
"@types/node": "^20.1.0",
"benchmark": "^2.1.4",
"fastify": "^4.0.0",
"sinon": "^14.0.0",
"sinon": "^15.0.0",
"snazzy": "^9.0.0",
"standard": "^17.0.0",
"tap": "^16.0.0",
"tsd": "^0.24.1"
"tsd": "^0.28.0"
},

@@ -54,0 +54,0 @@ "dependencies": {

@@ -8,4 +8,7 @@ 'use strict'

function fastifyCookieSetCookie (reply, name, value, options, signer) {
const kReplySetCookies = Symbol('fastify.reply.setCookies')
function fastifyCookieSetCookie (reply, name, value, options) {
const opts = Object.assign({}, options)
if (opts.expires && Number.isInteger(opts.expires)) {

@@ -16,3 +19,3 @@ opts.expires = new Date(opts.expires)

if (opts.signed) {
value = signer.sign(value)
value = reply.signCookie(value)
}

@@ -29,16 +32,4 @@

const serialized = cookie.serialize(name, value, opts)
let setCookie = reply.getHeader('Set-Cookie')
if (!setCookie) {
reply.header('Set-Cookie', serialized)
return reply
}
reply[kReplySetCookies].set(`${name};${opts.domain};${opts.path || '/'}`, { name, value, opts })
if (typeof setCookie === 'string') {
setCookie = [setCookie]
}
setCookie.push(serialized)
reply.removeHeader('Set-Cookie')
reply.header('Set-Cookie', setCookie)
return reply

@@ -64,2 +55,3 @@ }

}
fastifyRes[kReplySetCookies] = new Map()
done()

@@ -73,2 +65,3 @@ }

}
fastifyRes[kReplySetCookies] = new Map()
done()

@@ -78,2 +71,32 @@ }

function fastifyCookieOnSendHandler (fastifyReq, fastifyRes, payload, done) {
if (fastifyRes[kReplySetCookies].size) {
let setCookie = fastifyRes.getHeader('Set-Cookie')
/* istanbul ignore else */
if (setCookie === undefined) {
if (fastifyRes[kReplySetCookies].size === 1) {
for (const c of fastifyRes[kReplySetCookies].values()) {
fastifyRes.header('Set-Cookie', cookie.serialize(c.name, c.value, c.opts))
}
return done()
}
setCookie = []
} else if (typeof setCookie === 'string') {
setCookie = [setCookie]
}
for (const c of fastifyRes[kReplySetCookies].values()) {
setCookie.push(cookie.serialize(c.name, c.value, c.opts))
}
fastifyRes.removeHeader('Set-Cookie')
fastifyRes.header('Set-Cookie', setCookie)
}
done()
}
function getHook (hook = 'onRequest') {

@@ -98,5 +121,5 @@ const hooks = {

const isSigner = !secret || (typeof secret.sign === 'function' && typeof secret.unsign === 'function')
const algorithm = options.algorithm || 'sha256'
const signer = isSigner ? secret : new Signer(secret, algorithm)
const signer = isSigner ? secret : new Signer(secret, options.algorithm || 'sha256')
fastify.decorate('serializeCookie', cookie.serialize)
fastify.decorate('parseCookie', parseCookie)

@@ -116,4 +139,5 @@

fastify.decorateRequest('cookies', null)
fastify.decorateReply(kReplySetCookies, null)
fastify.decorateReply('cookie', setCookie)
fastify.decorateReply('setCookie', setCookie)

@@ -124,2 +148,3 @@ fastify.decorateReply('clearCookie', clearCookie)

fastify.addHook(hook, onReqHandlerWrapper(fastify, hook))
fastify.addHook('onSend', fastifyCookieOnSendHandler)
}

@@ -144,3 +169,3 @@

const opts = Object.assign({}, options.parseOptions, cookieOptions)
return fastifyCookieSetCookie(this, name, value, opts, signer)
return fastifyCookieSetCookie(this, name, value, opts)
}

@@ -147,0 +172,0 @@

@@ -126,3 +126,3 @@ 'use strict'

test('share options for setCookie and clearCookie', (t) => {
t.plan(11)
t.plan(8)
const fastify = Fastify()

@@ -153,11 +153,8 @@ const secret = 'testsecret'

const cookies = res.cookies
t.equal(cookies.length, 2)
t.equal(cookies.length, 1)
t.equal(cookies[0].name, 'foo')
t.equal(cookies[0].value, sign('foo', secret))
t.equal(cookies[0].maxAge, 36000)
t.equal(cookies[0].value, '')
t.equal(cookies[0].maxAge, undefined)
t.equal(cookies[1].name, 'foo')
t.equal(cookies[1].value, '')
t.equal(cookies[1].path, '/')
t.ok(new Date(cookies[1].expires) < new Date())
t.ok(new Date(cookies[0].expires) < new Date())
})

@@ -167,3 +164,3 @@ })

test('expires should not be overridden in clearCookie', (t) => {
t.plan(11)
t.plan(7)
const fastify = Fastify()

@@ -194,12 +191,7 @@ const secret = 'testsecret'

const cookies = res.cookies
t.equal(cookies.length, 2)
t.equal(cookies.length, 1)
t.equal(cookies[0].name, 'foo')
t.equal(cookies[0].value, sign('foo', secret))
t.equal(cookies[0].value, '')
const expires = new Date(cookies[0].expires)
t.ok(expires < new Date(Date.now() + 5000))
t.equal(cookies[1].name, 'foo')
t.equal(cookies[1].value, '')
t.equal(cookies[1].path, '/')
t.equal(Number(cookies[1].expires), 0)
})

@@ -718,2 +710,14 @@ })

test('serialize cookie manually using decorator', (t) => {
t.plan(2)
const fastify = Fastify()
fastify.register(plugin)
fastify.ready(() => {
t.ok(fastify.serializeCookie)
t.same(fastify.serializeCookie('foo', 'bar', {}), 'foo=bar')
t.end()
})
})
test('parse cookie manually using decorator', (t) => {

@@ -952,3 +956,3 @@ t.plan(2)

test('clearCookie should include parseOptions', (t) => {
t.plan(14)
t.plan(10)
const fastify = Fastify()

@@ -984,16 +988,178 @@ fastify.register(plugin, {

t.equal(cookies.length, 2)
t.equal(cookies.length, 1)
t.equal(cookies[0].name, 'foo')
t.equal(cookies[0].value, 'foo')
t.equal(cookies[0].maxAge, 36000)
t.equal(cookies[0].value, '')
t.equal(cookies[0].maxAge, undefined)
t.equal(cookies[0].path, '/test')
t.equal(cookies[0].domain, 'example.com')
t.ok(new Date(cookies[0].expires) < new Date())
})
})
test('should update a cookie value when setCookie is called multiple times', (t) => {
t.plan(15)
const fastify = Fastify()
const secret = 'testsecret'
fastify.register(plugin, { secret })
const cookieOptions = {
signed: true,
path: '/foo',
maxAge: 36000
}
const cookieOptions2 = {
signed: true,
maxAge: 36000
}
fastify.get('/test1', (req, reply) => {
reply
.setCookie('foo', 'foo', cookieOptions)
.clearCookie('foo', cookieOptions)
.setCookie('foo', 'foo', cookieOptions2)
.setCookie('foos', 'foos', cookieOptions)
.setCookie('foos', 'foosy', cookieOptions)
.send({ hello: 'world' })
})
fastify.inject({
method: 'GET',
url: '/test1'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.body), { hello: 'world' })
const cookies = res.cookies
t.equal(cookies.length, 3)
t.equal(cookies[0].name, 'foo')
t.equal(cookies[0].value, '')
t.equal(cookies[0].path, '/foo')
t.equal(cookies[1].name, 'foo')
t.equal(cookies[1].value, sign('foo', secret))
t.equal(cookies[1].maxAge, 36000)
t.equal(cookies[2].name, 'foos')
t.equal(cookies[2].value, sign('foosy', secret))
t.equal(cookies[2].path, '/foo')
t.equal(cookies[2].maxAge, 36000)
t.ok(new Date(cookies[0].expires) < new Date())
})
})
test('should update a cookie value when setCookie is called multiple times (empty header)', (t) => {
t.plan(15)
const fastify = Fastify()
const secret = 'testsecret'
fastify.register(plugin, { secret })
const cookieOptions = {
signed: true,
path: '/foo',
maxAge: 36000
}
const cookieOptions2 = {
signed: true,
maxAge: 36000
}
fastify.get('/test1', (req, reply) => {
reply
.header('Set-Cookie', '', cookieOptions)
.setCookie('foo', 'foo', cookieOptions)
.clearCookie('foo', cookieOptions)
.setCookie('foo', 'foo', cookieOptions2)
.setCookie('foos', 'foos', cookieOptions)
.setCookie('foos', 'foosy', cookieOptions)
.send({ hello: 'world' })
})
fastify.inject({
method: 'GET',
url: '/test1'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.body), { hello: 'world' })
const cookies = res.cookies
t.equal(cookies.length, 3)
t.equal(cookies[0].name, 'foo')
t.equal(cookies[0].value, '')
t.equal(cookies[0].path, '/foo')
t.equal(cookies[1].name, 'foo')
t.equal(cookies[1].value, sign('foo', secret))
t.equal(cookies[1].maxAge, 36000)
t.equal(cookies[2].name, 'foos')
t.equal(cookies[2].value, sign('foosy', secret))
t.equal(cookies[2].path, '/foo')
t.equal(cookies[2].maxAge, 36000)
t.ok(new Date(cookies[0].expires) < new Date())
})
})
test('should update a cookie value when setCookie is called multiple times (non-empty header)', (t) => {
t.plan(15)
const fastify = Fastify()
const secret = 'testsecret'
fastify.register(plugin, { secret })
const cookieOptions = {
signed: true,
path: '/foo',
maxAge: 36000
}
const cookieOptions2 = {
signed: true,
maxAge: 36000
}
fastify.get('/test1', (req, reply) => {
reply
.header('Set-Cookie', 'manual=manual', cookieOptions)
.setCookie('foo', 'foo', cookieOptions)
.clearCookie('foo', cookieOptions)
.setCookie('foo', 'foo', cookieOptions2)
.setCookie('foos', 'foos', cookieOptions)
.setCookie('foos', 'foosy', cookieOptions)
.send({ hello: 'world' })
})
fastify.inject({
method: 'GET',
url: '/test1'
}, (err, res) => {
t.error(err)
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.body), { hello: 'world' })
const cookies = res.cookies
t.equal(cookies.length, 4)
t.equal(cookies[1].name, 'foo')
t.equal(cookies[1].value, '')
t.equal(cookies[1].path, '/test')
t.equal(cookies[1].domain, 'example.com')
t.equal(cookies[1].path, '/foo')
t.equal(cookies[2].name, 'foo')
t.equal(cookies[2].value, sign('foo', secret))
t.equal(cookies[2].maxAge, 36000)
t.equal(cookies[3].name, 'foos')
t.equal(cookies[3].value, sign('foosy', secret))
t.equal(cookies[3].path, '/foo')
t.equal(cookies[3].maxAge, 36000)
t.ok(new Date(cookies[1].expires) < new Date())
})
})

@@ -8,2 +8,11 @@ /// <reference types='node' />

/**
* Serialize a cookie name-value pair into a Set-Cookie header string
* @param name Cookie name
* @param value Cookie value
* @param opts Options
* @throws {TypeError} When maxAge option is invalid
*/
serializeCookie(name: string, value: string, opts?: fastifyCookie.SerializeOptions): string;
/**
* Manual cookie parsing method

@@ -109,5 +118,6 @@ * @docs https://github.com/fastify/fastify-cookie#manual-cookie-parsing

export interface CookieSerializeOptions {
export interface SerializeOptions {
/** The `Domain` attribute. */
domain?: string;
/** Specifies a function that will be used to encode a cookie's value. Since value of a cookie has a limited character set (and must be a simple string), this function can be used to encode a value into a string suited for a cookie's value. */
encode?(val: string): string;

@@ -118,3 +128,3 @@ /** The expiration `date` used for the `Expires` attribute. If both `expires` and `maxAge` are set, then `expires` is used. */

httpOnly?: boolean;
/** A `number` in milliseconds that specifies the `Expires` attribute by adding the specified milliseconds to the current date. If both `expires` and `maxAge` are set, then `expires` is used. */
/** A `number` in seconds that specifies the `Expires` attribute by adding the specified seconds to the current date. If both `expires` and `maxAge` are set, then `expires` is used. */
maxAge?: number;

@@ -124,5 +134,9 @@ /** The `Path` attribute. Defaults to `/` (the root path). */

priority?: "low" | "medium" | "high";
/** A `boolean` or one of the `SameSite` string attributes. E.g.: `lax`, `node` or `strict`. */
/** A `boolean` or one of the `SameSite` string attributes. E.g.: `lax`, `none` or `strict`. */
sameSite?: 'lax' | 'none' | 'strict' | boolean;
/** The `boolean` value of the `Secure` attribute. Set this option to false when communicating over an unencrypted (HTTP) connection. Value can be set to `auto`; in this case the `Secure` attribute will be set to false for HTTP request, in case of HTTPS it will be set to true. Defaults to true. */
secure?: boolean;
}
export interface CookieSerializeOptions extends Omit<SerializeOptions, 'secure'> {
secure?: boolean | 'auto';

@@ -176,2 +190,2 @@ signed?: boolean;

export = fastifyCookie;
export = fastifyCookie;

@@ -42,2 +42,6 @@ import cookie from '..';

server.after((_err) => {
expectType< string >(
server.serializeCookie('sessionId', 'aYb4uTIhdBXC')
);
expectType<{ [key: string]: string }>(

@@ -44,0 +48,0 @@ // See https://github.com/fastify/fastify-cookie#manual-cookie-parsing

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