You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					144 lines
				
				4.0 KiB
			
		
		
			
		
	
	
					144 lines
				
				4.0 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const fp = require('fastify-plugin') | ||
|  | const cookie = require('cookie') | ||
|  | 
 | ||
|  | const { Signer, sign, unsign } = require('./signer') | ||
|  | 
 | ||
|  | function fastifyCookieSetCookie (reply, name, value, options, signer) { | ||
|  |   const opts = Object.assign({}, options) | ||
|  |   if (opts.expires && Number.isInteger(opts.expires)) { | ||
|  |     opts.expires = new Date(opts.expires) | ||
|  |   } | ||
|  | 
 | ||
|  |   if (opts.signed) { | ||
|  |     value = signer.sign(value) | ||
|  |   } | ||
|  | 
 | ||
|  |   if (opts.secure === 'auto') { | ||
|  |     if (isConnectionSecure(reply.request)) { | ||
|  |       opts.secure = true | ||
|  |     } else { | ||
|  |       opts.sameSite = 'lax' | ||
|  |       opts.secure = false | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   const serialized = cookie.serialize(name, value, opts) | ||
|  |   let setCookie = reply.getHeader('Set-Cookie') | ||
|  |   if (!setCookie) { | ||
|  |     reply.header('Set-Cookie', serialized) | ||
|  |     return reply | ||
|  |   } | ||
|  | 
 | ||
|  |   if (typeof setCookie === 'string') { | ||
|  |     setCookie = [setCookie] | ||
|  |   } | ||
|  | 
 | ||
|  |   setCookie.push(serialized) | ||
|  |   reply.removeHeader('Set-Cookie') | ||
|  |   reply.header('Set-Cookie', setCookie) | ||
|  |   return reply | ||
|  | } | ||
|  | 
 | ||
|  | function fastifyCookieClearCookie (reply, name, options) { | ||
|  |   const opts = Object.assign({ path: '/' }, options || { }, { | ||
|  |     expires: new Date(1), | ||
|  |     signed: undefined, | ||
|  |     maxAge: undefined | ||
|  |   }) | ||
|  |   return fastifyCookieSetCookie(reply, name, '', opts) | ||
|  | } | ||
|  | 
 | ||
|  | function onReqHandlerWrapper (fastify) { | ||
|  |   return function fastifyCookieOnReqHandler (fastifyReq, fastifyRes, done) { | ||
|  |     fastifyReq.cookies = {} // New container per request. Issue #53
 | ||
|  |     const cookieHeader = fastifyReq.raw.headers.cookie | ||
|  |     if (cookieHeader) { | ||
|  |       fastifyReq.cookies = fastify.parseCookie(cookieHeader) | ||
|  |     } | ||
|  |     done() | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function plugin (fastify, options, next) { | ||
|  |   const secret = options.secret || '' | ||
|  |   const enableRotation = Array.isArray(secret) | ||
|  |   const algorithm = options.algorithm || 'sha256' | ||
|  |   const signer = typeof secret === 'string' || enableRotation ? new Signer(secret, algorithm) : secret | ||
|  | 
 | ||
|  |   fastify.decorate('parseCookie', parseCookie) | ||
|  |   fastify.decorate('signCookie', signCookie) | ||
|  |   fastify.decorate('unsignCookie', unsignCookie) | ||
|  | 
 | ||
|  |   fastify.decorateRequest('cookies', null) | ||
|  |   fastify.decorateRequest('unsignCookie', unsignCookie) | ||
|  |   fastify.decorateReply('setCookie', setCookie) | ||
|  |   fastify.decorateReply('cookie', setCookie) | ||
|  |   fastify.decorateReply('clearCookie', clearCookie) | ||
|  |   fastify.decorateReply('unsignCookie', unsignCookie) | ||
|  | 
 | ||
|  |   fastify.addHook('onRequest', onReqHandlerWrapper(fastify)) | ||
|  | 
 | ||
|  |   next() | ||
|  | 
 | ||
|  |   // ***************************
 | ||
|  |   function parseCookie (cookieHeader) { | ||
|  |     return cookie.parse(cookieHeader, options.parseOptions) | ||
|  |   } | ||
|  | 
 | ||
|  |   function signCookie (value) { | ||
|  |     return signer.sign(value) | ||
|  |   } | ||
|  | 
 | ||
|  |   function unsignCookie (value) { | ||
|  |     return signer.unsign(value) | ||
|  |   } | ||
|  | 
 | ||
|  |   function setCookie (name, value, cookieOptions) { | ||
|  |     const opts = Object.assign({}, options.parseOptions, cookieOptions) | ||
|  |     return fastifyCookieSetCookie(this, name, value, opts, signer) | ||
|  |   } | ||
|  | 
 | ||
|  |   function clearCookie (name, options) { | ||
|  |     return fastifyCookieClearCookie(this, name, options) | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function isConnectionSecure (request) { | ||
|  |   return ( | ||
|  |     request.raw.socket?.encrypted === true || | ||
|  |     request.headers['x-forwarded-proto'] === 'https' | ||
|  |   ) | ||
|  | } | ||
|  | 
 | ||
|  | const fastifyCookie = fp(plugin, { | ||
|  |   fastify: '4.x', | ||
|  |   name: '@fastify/cookie' | ||
|  | }) | ||
|  | 
 | ||
|  | /** | ||
|  |  * These export configurations enable JS and TS developers | ||
|  |  * to consume fastify-cookie in whatever way best suits their needs. | ||
|  |  * Some examples of supported import syntax includes: | ||
|  |  * - `const fastifyCookie = require('fastify-cookie')` | ||
|  |  * - `const { fastifyCookie } = require('fastify-cookie')` | ||
|  |  * - `import * as fastifyCookie from 'fastify-cookie'` | ||
|  |  * - `import { fastifyCookie } from 'fastify-cookie'` | ||
|  |  * - `import fastifyCookie from 'fastify-cookie'` | ||
|  |  */ | ||
|  | fastifyCookie.signerFactory = Signer | ||
|  | fastifyCookie.fastifyCookie = fastifyCookie | ||
|  | fastifyCookie.default = fastifyCookie | ||
|  | module.exports = fastifyCookie | ||
|  | 
 | ||
|  | fastifyCookie.fastifyCookie.signerFactory = Signer | ||
|  | fastifyCookie.fastifyCookie.Signer = Signer | ||
|  | fastifyCookie.fastifyCookie.sign = sign | ||
|  | fastifyCookie.fastifyCookie.unsign = unsign | ||
|  | 
 | ||
|  | module.exports.signerFactory = Signer | ||
|  | module.exports.Signer = Signer | ||
|  | module.exports.sign = sign | ||
|  | module.exports.unsign = unsign |