jshttp / cookie Goto Github PK
View Code? Open in Web Editor NEWHTTP server cookie parsing and serialization
License: MIT License
HTTP server cookie parsing and serialization
License: MIT License
Is there any way to get Cookie.parse to be able to parse a set-cookie ?
Example:
visitor=35396244; Domain=.blah.com; Expires=Fri, 06-Jul-2018 00:23:32 GMT; Path=/
{
visitor: '35396244',
Domain: '.blah.com',
Expires: 'Fri, 06-Jul-2018 00:23:32 GMT',
Path: '/'
}
but here there's no deterministic way of saying that visitor
is the name of the cookie
Or is there another recommended npm module to do this?
I installed it using
npm install cookie
It complains that it cannot find the module cookie if I do this.
var cookie = require("cookie");
/[;,] */
is too aggressive (it should be changed to just /; *
, otherwise it fails on toUTCString
strings:
cookie.parse('expires=Wed, 29 Jan 2014 17:43:25 GMT; Path=/')
--> {Path: '/', expires: 'Wed'}
httpOnly and secure aren't mutually exclusive flags: httpOnly just means you can't get at the cookie from a script and secure means "only send this over https."
With both flags set, serialize works properly,
> a = c.serialize('foo','bar',{maxAge:1000,httpOnly:true,secure:true})
'foo=bar; Max-Age=1000; HttpOnly; Secure'
but alas parse
causes the two flags to clobber on an empty key. This probably should have been an empty (or, better yet, boolean) value. Perhaps this,
> c.parse(a)
{ foo: 'bar',
'Max-Age': '1000',
'': 'HttpOnly' }
should be this instead,
> c.parse(a)
{ foo: 'bar',
'Max-Age': '1000',
'HttpOnly': true,
'Secure': true, }
my bro sends weird cookies (after deleting and installing cookies again):
user_id=; session_id=; session_id=XXXXXXX; user_id=6
cookie-parser
parse e.g. user_id
as a ''
but expected reading a latest value of each cookie
Suppose I have a Cookie header like this:
Cookie: foo=bar; baz
What gets parsed is { foo: 'bar' }
, but I don't get baz
. This should be a valid cookie header since I extracted it from something that Firefox sent out but replaced the keys and values.
In Node.js express server:
const cookieBaseOpts = {
path: '/',
secure: true,
httpOnly: true,
};
const cookieOpts = Object.assign({}, cookieBaseOpts, {
expires: new Date(decodedRT.exp * 1000)
});
res.cookie('accessToken', tokens.accessToken, cookieOpts);
res.cookie('refreshToken', tokens.refreshToken, cookieOpts);
This will result the response set-cookie
header like this:
accessToken=eyJhbGciOiJIUzI1NiIsInRI6IkpXVCJ9.eyJ1aWQiJTMXhNWVA1Y0ZaIiwiY2lkIjoiQnlmS3c1OXRaIiwiZGlkIjoiQjF3TXR3cTV0VyIsInNjcCI6W10sImV4cCI6MTUwNDUxOTU2MiwiaXNzIjoiVi1jdWJlLCBJbmMuIiwic3ViIjoiQVQiLCJqdGkiOiJya19mdEQNVlXIn0.f12SwbI9LEgB7feqdMYgvivhw4bJtkqVx6ivdvGj8; Path=/; Expires=Wed, 04 Oct 2017 09:06:02 GMT; HttpOnly; Secure,refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCIkpXVCJ9.eyJleHAiOjE1MDcxMDc5NjIsImlzcyI6IlYtY3ViZSwgSW5jLiIsInN1YiI6IlJUIiwianRpIjoicmtfZnREOTVZVyJ9.GHKjlE8t0x2rDpuCPOFGEvMFXZxV0JVsoI1sGN7o3U; Path=/; Expires=Wed, 04 Oct 2017 09:06:02 GMT; HttpOnly; Secure
Which if call the parse
method, will get wrong parsed object:
{
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkVCJ9.eyJ1aWQiOiJTMXhNWVA1Y0ZaIiwiY2lkIjiwiZGlkIjoiQjF3TXR3cTV0VyIsInNjcCI6W10sImV4cCI6MTUwNDUxOTU2MiwiaXNzIjoiVi1jdWJlLCBJbmMuIiwic3ViIjoiQVQiLCJqdGkiOiJya19mdEQ5NVlXIn0.f12OSwbI9LEgeqdMYOgvivhwbJtkqVx6ivdvGj8',
Path: '/',
Expires: 'Wed, 04 Oct 2017 09:06:02 GMT',
'Secure,refreshToken': 'eyJhbGciOiJIUzI1NiIsInR5cCIpXVCJ9.eyJleHAiOjE1MDcxMDc5NjIsIIlYtY3ViZSwgSW5jLiIsInN1YiI6IlJUIiwianRpIjoicmtfZnREOTVZVyJ9.GHKjlEA8t0x2rDpuCPFGEvMFXZxV0JVsoI1sGN7o3U'
}
See the key: Secure,refreshToken
Wrong option parameter name: expires. Correct is expire.
Please change the readme file.
Hello,
Intellij can not recognize the function of the cookie object, when the methods are not defined before the export statement. In this case these two lines should be flipped, so they are in the right order. First declaration, then assignment.
// ...
exports.parse = parse;
exports.serialize = serialize;
cookie.parse() doesn't encode/decode all the cookie-octets as specified in the rfc.
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
Hi,
I've used the cookie.parse function to parse a cookie to extract a string. I've notice though that it has changed the % to a :. for example:
Original string in cookie: s%3AYICgq7xLgu5NOy
Parsed string: s:YICgq7xLgu5NOy
Could anyone help by letting me know what the start of the string is parsed incorrectly?
Bw
The README here on github has a link to RFC6265 for e.g. Domain Set-Cookie attribute
, but somehow the link on the npm
version of README is to RFC6266. Seems to happen for most/all of the links (Expires
, Max-Age
, Path
).
Not sure if that's under control of the repo owner, or an issue on the npm
side.
Just a thought: if you set a cookie for a domain (for example: example.com) and then set a cookie for a subdomain (test.example.com), the next time you request something from the subdomain, both cookies (with the same name!!!) are sent to the server.
In the case of node-cookie, only the first cookie is parsed (the one that comes first in the Cookie header), the other is ignored.
I tried to find how this case should be handled by webservers in general, but couldn't, so I thought a good place to start gathering opinions and information would be here.
Should same name cookies really be ignored? Or should there be a way to retrieve all from the application?
The Doc say the unit of 'maxAge' is seconde...
But I use the module like this
var express = require("express")
, Cookies = require("cookies")
, cookiesOption = {
maxAge: 2592000
, httpOnly: false
, path: '/'
, secure: false
};
//setcookie
cookies.set("storeId", results.getStoreInfo.id, cookiesOption);
cookies.set("phoneNum", results.getToken.phoneNum, cookiesOption);
2592000=60 * 60 * 24 * 30, if the unit of maxAge is second , this is one month .
When I run this at 2016-3-8 16:32:47(UTC/GMT+08:00),
then I see Resource in Chrome Broswer ,'Expires/Max-Age' is '2016-03-08T09:16:59.008Z'.
package.json like this:
"cookie-parser": "^1.4.1",
"cookies": "^0.5.1",
what's wrong???
I've had a very rare problem in my express application that was causing the process to crash. I tracked the issue down to an incoming cookie that was corrupted/incomplete by the client ... I think. After read
https://mathiasbynens.be/notes/javascript-unicode, I found that some more obscure utf characters actually have a length property of 2, and then if you try to access the first character in them, javascript flips out. Example:
'𠮷'.length // is 2
'𠮷'[0] // invalid character
Now, if I try to set an outgoing cookie to that value, express crashes.
var express = require('express');
var app = express();
app.get('/', function (req, res) {
setTimeout(function(){
res.cookie('myCookie','𠮷'[0]) // let's say this came in that way and I'm just writing it back
res.send('Hello World!');
},1)
});
app.listen(8123, function () {
console.log('Example app listening on port 8123!');
})
Note that the setTimeout is important to crash the process. Any sort of async callback will likely do the trick.
Internally, there is a call to encodeURIComponent
to set the cookie, and it is effectively doing encodeURIComponent('𠮷'[0])
which is bad.
What is the solution here? Wrap that call in a try catch so that it will fail gracefully?
The serialize method should be updated to accept an object of key/values and serialize to a cookie string. This would make the serialize/parse methods complement each other.
Hi Roman,
do you thing you can add a license file to the repository that states the type of license this project is developed under? I need this for a internal software introduction process 👍
Best,
Alex
It would be great to implement ES module entrypoint
Hi! Just a small issue, I think maxAge is in seconds (RFC), but jshttp/cookie uses milliseconds.
As well in NPM is shows seconds, when in the cookie underlying implementation uses milliseconds.
https://tools.ietf.org/html/rfc7234#section-5.2.2.8 - seconds
https://www.npmjs.com/package/cookie - shows seconds
But when I uses it i have to use milliseconds.
( I divided by 1000 and it was wrong, so I tried with milliseconds and it works now. :) )
https://github.com/defunctzombie/node-cookie/blob/master/index.js#L34
If a cookie has a comma in its text, the cookie winds up cut off.
Example:
testCookie=a,b;
Would come out as testCookie=a
I don't know if this was done for some strange browser that splits with commas, so I'm not sure if it should be an option to turn off splitting at commas or if it should just be removed.
Hi,
When parsing a cookie, I can see all the properties but how can realize which key represents the cookie name? I want to iterate over all http response cookies and act on a specific cookie, this why I need its name
Thanks!
Yoni
Hello, I have a express.js server with connect-session and it sends a cookie that looks like this
"language=en-US; Path=/, keystone.uid=s%3A5b4f9dc45e23fe02b4b24862%3ACzrzXyYInv7VKl5PaevC9Ynd1qJD72Ip%2BmCd7NynoxU.rGWyRaQecitVOH4vQpZTD1ThpvQ44BI%2BmzOF51kjSms; Max-Age=864; Path=/; Expires=Wed, 25 Jul 2018 19:07:02 GMT; HttpOnly, this.sid=s%3AappByhX2Ao31t5RlBF9cd80lZcsQEjE3.o4Wq9o7bhpptCrcJt6XIh1jjKQgWPgibnoI8TDalkDk; Path=/; Expires=Thu, 25 Jul 2019 18:52:38 GMT; HttpOnly"
I then store that string and whenever I try to parse it with this module, it gives me an object with the following keys
[ 'language', 'Path', 'Max-Age', 'Expires', 'HttpOnly, this.sid' ]
notice that the last object's key is 'HttpOnly, this.sid'
The cookie is passed without the quotes of course. I am trying to extract the this.sid value. Is this a limitation of this parser or are the cookies my server is sending wrong?
For example:
"NID=74=kU1rGWqE7kKmIrTtMVRJ-viL0fk1uih6tN0PTjiW2M_sh85c1WtSAsjuA3ITsx_mrcM37mya9N1HElQDeuM4siZb2Yn16cIE24i68YUsCLQpvsl-KPf3Rl7YmqwYDNRu; expires=Mon, 20-Jun-2016 19:36:37 GMT; path=/; domain=.google.pl; HttpOnly"
trying to parse above gives an error:
node_modules/cookie/index.js:49
throw new TypeError('argument str must be a string');
Not sure about older internet explorer versions, but on Edge the maxAge parameter doesn't seem to be setting.
According to this site, max age is not a supported parameter on some IE versions:
http://mrcoles.com/media/test/cookies-max-age-vs-expires.html
Are you letting people use this code that you published here?
If so, please put an Open Source license on the code -- e.g. the MIT license is very common for this kind of software. Here's the text you can use. Just add a file called LICENSE, or add this text to your README, and we'll know that you are giving people permission to use your code. If this is your code, put in your name for the copyright. If you work for a company and they own your IP, then use your company's name (with permission of course).
Thanks!
---------------->
MIT License
Copyright (c) 2012 [YOUR NAME or YOUR COMPANY'S NAME]. All Rights Reserved.
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.
The docs at https://www.npmjs.com/package/cookie refer to RFC 6266, but the actual RFC for "HTTP State Management Mechanism" is RFC 6265.
Hello!
My system:
I'm using your library and I think there might be an issue with the method "cookie.serialize" - it returns a string, that is not a valid HTTP header value and is not accepted by the browser.
How to reproduce:
"name", "value", {path:"/",maxAge: 86400000,domain:"localhost",secure:true,sameSite:true}
,During debugging I've found that in the "serialize()" the method "encodeURIComponent()" is applied only to the "value" component (please see the screenshot below)
what in turn results in impossibility of setting that cookie in the document (I've tested in Safari 13.0.4 as well). So the browser simply ignores the returned cookie and sets it as "" (empty string).
But when I apply the "encodeURIComponent()" at the end on the resulting string (name + value + options) - browser accepts it.
Thank you!
Sincerely,
Konstantin
I am using cookie
as an underlying module to handle cookies for session handling. Specifically express-session
and connect-redis
as a store.
When running the app locally (Mac OSX, nodemon) everything works fantastically.
When running the app on a test environment (Ubuntu, nginx) the cookie isn't getting url decoded somewhere down the line. I'm not sure if this is up to the browser to decode, or if the server needs to decode the Set-Cookie header before sending. So, sessions typically will be prefixed with s:
which is the result when running locally. In the test environment it is s%3A
. On the server side, everything seems to work just fine, but I am trying to do some cors requests with credentials and nothing is working because it is expecting the cookie to start with s: and not s%3A.
I can't figure out where in the process this is happening, so it is entirely possible that I am creating this issue on the wrong repo, but I did notice other url encoding issues here, so maybe someone has had a similar problem and can share some knowledge.
note: I am looking at the cookie value in the browser using Chrome's resources tab.
My library galette relied on treatment of maxAge: null
as implemented by 0.1.0 and before, i.e. not serializing it. Changes in #20 broke this by inserting Max-Age: 0
where it wasn't intended: instead of a non-persistent cookie I get one that is immediately dropped. I can adapt to new behavior but would like a clarification whether it will now be standardized upon.
The reason why I was using null
to begin with was that I wanted to mask a non-null maxAge
in the prototype of the dictionary being serialized.
var cookies = cookie.parse(res.headers['set-cookie']);
where res.headers['set-cookie'] = ['connect.sid=s%3AShj6dDkQPM2nsecMA1UkbXWF.7YklRM%2FVFwIT7vsVWrUcPUuNO7fErA%2BjiL%2FW%2B7F2RXg; Path=/; HttpOnly' ]
fails to parse. The error is
TypeError: Object connect.sid=s%3AdJxdMsxBm2pqB3LTa2YwURDa.hxJMI%2FHAG6Za7F6oGhU1iExPYCLRTqKOJ%2BX%2BTFwSHCY; Path=/; HttpOnly has no method 'split'
Am I doing something wrong or it can only parse key=value pairs? However this is a pretty standard cookie header.
Hi @defunctzombie , would you be willing to add myself and @jonathanong to the module owners on npm for cookie
?
With Google's announcement of Chrome 80 defaulting to SameSite=Lax
, the support for SameSite=None
is much needed.
I can see there have been some work on it. Kindly consider releasing it.
I'm building a cookie that uses HttpOnly, but cookie
is not outputting the HttpOnly attribute.
cookie.parse("mytoken=test; Domain=.example.com; Path=/; Expires=Thu, 25 Jan 2018 17:21:33 GMT; HttpOnly")
{ mytoken: 'test',
Domain: '.example.com',
Path: '/',
Expires: 'Thu, 25 Jan 2018 17:21:33 GMT' }
In some cases SameSite=None will be required for devs since Chrome 80.
https://blog.chromium.org/2019/10/developers-get-ready-for-new.html
Currently cookie-parser has dependency to cookie with version 0.3.1.
Version 0.4 introduced support for SameSite=None.
export function setCookie(ctx = {}, name, value, options = {}) {
if (ctx && ctx.res) {
ctx.res.setHeader('Set-Cookie', cookie.serialize(name, value, options))
}
if (process.browser) {
document.cookie = cookie.serialize(name, value, options)
}
return {}
}
https://github.com/senchalabs/connect/blob/master/lib/middleware/cookieParser.js#L49
https://github.com/shtylman/node-cookie/blob/master/index.js#L46
This line uses the parse function from the cookie module. When the cookie value cannot be decoded properly this function throws (since the decodeURIComponent function throws). My concern is that this appears as a system error (plain error object) which usually results in the server responding with a 5xx error response versus a bad request or possibly not parsing the given value.
Now, I could wrap the decode call in the cookie module and just set the value to the raw value versus the decoded one. I am thinking this would be the proper thing to do (as I don't think failing with unable to decode URI component is good behavior here) but I wanted to first get some feedback since it would technically be a change in behavior.
Issue senchalabs/connect#652 is related.
/ping @visionmedia
Hi,
When parsing a cookie with HttpOnly
and/or Secure
which don't have values, they are directly ignored.
require('cookie').parse('SessionId=asdf2312fasdf; path=/; HttpOnly')
{ 'SessionId': 'asdf2312fasdf', path: '/' }
Would it be possible to make these attributes accessible?
This package will check if it is a Date
object when serializing options.expires
.
But the result of cookie.parse()
won't return a Date
object.
So that situation will crash:
header:
...,
"set-cookie": [
"__cfduid=d9bd5542019f8c0f082ddfebd222d5f651480319196; expires=Tue, 28-Nov-17 07:46:36 GMT; path=/; domain=.whoishostingthis.com; HttpOnly"
],
code:
...
foo.map(c => cookie.parse(););
...
foo.serialize(c => cookie.serialize());
"Same-site cookies allow servers to mitigate the risk of CSRF and information leakage attacks by asserting that a particular cookie should only be sent with requests initiated from the same registrable domain."
https://tools.ietf.org/html/draft-west-first-party-cookies-06
https://www.chromestatus.com/feature/4672634709082112
Hi, is Maxage definitely in milliseconds or in seconds? The example in the docs seems to indicate that it is in seconds... maxAge: 60 * 60 * 24 * 7 // 1 week
this would be in seconds, not milliseconds.
Comma separated cookie values are not common but they are a valid http header. Right now they are not handled by the parse function.
I got this lovely one today
var cookie = require("cookie");
node_modules/cookie/index.js:38 var pairs = str.split(/; */);
^ TypeError: Cannot read property 'split' of undefined
it occurred inside of this socket.io handshake hook
io.use(function (socket, next) {
var handshakeData = socket.request;
if (handshakeData.headers.cookie) {
handshakeData.cookie = cookie.parse(handshakeData.headers.cookie); //error here
handshakeData.sessionID = cookie.parse(handshakeData.cookie['express.sid'], 'foo'); //error here
if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) {
return next('Cookie is invalid.', false);
}
} else {
return next('No cookie transmitted.', false);
}
console.log('user with socket.id=',socket.id,'has authenticated successfully.');
return next(null, true);
});
Hi everyone,
I want report an inconsistency on documentation between npm https://www.npmjs.com/package/cookie and gitbuh repo.
On the github repo is psecioficed that the value of maxAge
option need to be specified in milliseconds while on npm is specified that this value have to be set in seconds
I tried and found that the maxAge
value need to be expressed in milliseconds
It seems cookie
doesn't currently support parsing flags.
var cookie = require('cookie');
var setCookie = cookie.serialize('foo', 'bar', {secure: true});
// 'foo=bar; Secure'
var cookies = cookie.parse(setCookie);
// {foo: 'bar'}
Is this the expected behaviour?
On line 46, +
are substituted for spaces. Digging through history it seem to have been introduced in senchalabs/connect@ee698b1 (and modified quite a bit in senchalabs/connect@f297e87) with no particular explanation given.
Case in point: I get Base64-coded cookies from a 3rd party system, which contain a +
every now and then, which are then turned into invalid Base64...
'=' converts into %3b which completely violates rfc
Why are the HttpOnly and Secure flags missing? ((See test))[https://github.com/jshttp/cookie/blob/master/test/parse.js#L36]
I would have expected:
{ foo: '%1', bar: 'bar', Secure: true, HttpOnly: true}
I haven't read the RFC so I don't know the details, but those two flags are useful when building a HTTP Agent
Line 56 in ddb7bbd
From RFC:
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
So a value may be wrapped in quotes. If so, this parser will handle the quotes as part of the value.
Small thing, but it would be better to fix this, improving reliability, and to mention the RFC's this code is compliant with in the inline comments. Better, rename 'parse()' to 'parse_rfc6265()' or something.
Nevertheless, thanks for writing this in the first place, makes all of our lives a bit easier 👍
Have you considered using semver? bump it to 1.0 ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.