Skip to content

Commit

Permalink
Go back to use our own cookie implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Matteo Collina <hello@matteocollina.com>
  • Loading branch information
mcollina committed Nov 6, 2023
1 parent 2c4c0f0 commit 7d35b97
Show file tree
Hide file tree
Showing 4 changed files with 433 additions and 3 deletions.
225 changes: 225 additions & 0 deletions cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*!
* Adapted from https://github.com/jshttp/cookie
*
* (The MIT License)
*
* Copyright (c) 2012-2014 Roman Shtylman <shtylman@gmail.com>
* Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

'use strict'

/**
* Module exports.
* @public
*/

exports.parse = parse
exports.serialize = serialize

/**
* Module variables.
* @private
*/

const decode = decodeURIComponent
const encode = encodeURIComponent

/**
* RegExp to match field-content in RFC 7230 sec 3.2
*
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
* field-vchar = VCHAR / obs-text
* obs-text = %x80-FF
*/

const fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/ // eslint-disable-line

/**
* Parse a cookie header.
*
* Parse the given cookie header string into an object
* The object has the various cookies as keys(names) => values
*
* @param {string} str
* @param {object} [options]
* @return {object}
* @public
*/

function parse (str, options) {
if (typeof str !== 'string') {
throw new TypeError('argument str must be a string')
}

const result = {}
const dec = (options && options.decode) || decode

let pos = 0
let terminatorPos = 0
let eqIdx = 0

while (true) {
if (terminatorPos === str.length) {
break
}
terminatorPos = str.indexOf(';', pos)
terminatorPos = (terminatorPos === -1) ? str.length : terminatorPos
eqIdx = str.indexOf('=', pos)

// skip things that don't look like key=value
if (eqIdx === -1 || eqIdx > terminatorPos) {
pos = terminatorPos + 1
continue
}

const key = str.substring(pos, eqIdx++).trim()

// only assign once
if (undefined === result[key]) {
const val = (str.charCodeAt(eqIdx) === 0x22)
? str.substring(eqIdx + 1, terminatorPos - 1).trim()
: str.substring(eqIdx, terminatorPos).trim()

result[key] = (dec !== decode || val.indexOf('%') !== -1)
? tryDecode(val, dec)
: val
}
pos = terminatorPos + 1
}
return result
}

/**
* Serialize data into a cookie header.
*
* Serialize the a name value pair into a cookie string suitable for
* http headers. An optional options object specified cookie parameters.
*
* serialize('foo', 'bar', { httpOnly: true })
* => "foo=bar; httpOnly"
*
* @param {string} name
* @param {string} val
* @param {object} [options]
* @return {string}
* @public
*/

function serialize (name, val, options) {
const opt = options || {}
const enc = opt.encode || encode
if (typeof enc !== 'function') {
throw new TypeError('option encode is invalid')
}

if (!fieldContentRegExp.test(name)) {
throw new TypeError('argument name is invalid')
}

const value = enc(val)
if (value && !fieldContentRegExp.test(value)) {
throw new TypeError('argument val is invalid')
}

let str = name + '=' + value
if (opt.maxAge != null) {
const maxAge = opt.maxAge - 0
if (isNaN(maxAge) || !isFinite(maxAge)) {
throw new TypeError('option maxAge is invalid')
}

str += '; Max-Age=' + Math.floor(maxAge)
}

if (opt.domain) {
if (!fieldContentRegExp.test(opt.domain)) {
throw new TypeError('option domain is invalid')
}

str += '; Domain=' + opt.domain
}

if (opt.path) {
if (!fieldContentRegExp.test(opt.path)) {
throw new TypeError('option path is invalid')
}

str += '; Path=' + opt.path
}

if (opt.expires) {
if (typeof opt.expires.toUTCString !== 'function') {
throw new TypeError('option expires is invalid')
}

str += '; Expires=' + opt.expires.toUTCString()
}

if (opt.httpOnly) {
str += '; HttpOnly'
}

if (opt.secure) {
str += '; Secure'
}

if (opt.sameSite) {
const sameSite = typeof opt.sameSite === 'string'
? opt.sameSite.toLowerCase()
: opt.sameSite
switch (sameSite) {
case true:
str += '; SameSite=Strict'
break
case 'lax':
str += '; SameSite=Lax'
break
case 'strict':
str += '; SameSite=Strict'
break
case 'none':
str += '; SameSite=None'
break
default:
throw new TypeError('option sameSite is invalid')
}
}

return str
}

/**
* Try decoding a string using a decoding function.
*
* @param {string} str
* @param {function} decode
* @private
*/

function tryDecode (str, decode) {
try {
return decode(str)
} catch (e) {
return str
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"tsd": "^0.29.0"
},
"dependencies": {
"cookie": "^0.5.0",
"fastify-plugin": "^4.0.0"
"fastify-plugin": "^4.0.0",
"cookie-signature": "^1.1.0"
},
"tsd": {
"directory": "test"
Expand Down
2 changes: 1 addition & 1 deletion plugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const fp = require('fastify-plugin')
const cookie = require('cookie')
const cookie = require('./cookie')

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

Expand Down
Loading

0 comments on commit 7d35b97

Please sign in to comment.