pillarjs / cookies Goto Github PK
View Code? Open in Web Editor NEWSigned and unsigned cookies based on Keygrip
License: MIT License
Signed and unsigned cookies based on Keygrip
License: MIT License
In the getPattern() method there is a call to String.replace that appears to be escaping the cookie name. The cookie names that are tested do not appear to exercise this code. e.g.
"signed".replace( /[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&" ) returns "signed"
as you may know, we are removing connect's cookie utilities and encouraging users to use this mighty module instead. however, i don't like how the user has to cookies.connect(new KeyGrip(['a', 'b']))
. how do you feel about allowing:
app.use(cookies.connect(['secret 1', 'secret 2'])
you are probably avoiding using keygrip
as a direct dependency, so i'm thinking to add keygrip
as a peer dependency. this will require the end user to install keygrip
themselves. we'll also throw a helpful message when keygrip
is not installed and the user tries to set keys
It'd be nice if cookies didn't try to sign things when no keygrip is supplied, or if {signed:true}
were the default when keys are present.
That way, you could have code that just passes in {signed:true} all the time, or never, and if keys are there or are not there, it will work as good as it can.
Right now, the 'session' connect middleware uses a cookie to idenfity the session, and it expects the cookies to be accessible via a plain dictionary on req.cookies, as parsed by it's the connect cookieParser middleware.
Since this libarary is also using 'cookies' to store the dictionary, we end up with an incompatibility between the two middlewares. Thoughts on changing the name of the attribute on which the middleware stores itself?
hi.
I have a problem with line 49 in lib/cookies.js:
if (!secure && opts && opts.secure) throw new Error("Cannot send secure cookie over unencrypted socket")
my node workers run in http mode because i handle SSL with stunnel before the requests enter haproxy where they are routed to my machines.
Are you happy with an option called secureProxy or something like this?
Hi,
Could you please specify whether the license is MIT, BSD or Apache in the license file?
Thanks,
-- Tito
Hi,
It would be great if you could restructure the functions to be used in a client. Currently, the assumption is that you're the one setting the cookies at the server end, and reading them from the client.
What would be desirable, is if you could use the get/set methods so that you could get any cookies which originate from the server, and set them when sending a request to the server. (Basically the opposite of what is currently occurring).
Thanks!
I have just tested this plugin and I have successfully set a cookie in my sails.js application with following code:
Cookies = require("cookies"),
Keygrip = require("keygrip"),
keys = Keygrip(["SEKRIT2", "SEKRIT1"], 'sha256'),
...
var cookies = new Cookies( req, res, keys );
cookies.set("username", username, {signed: true});
and I can see this cookie using "Edit this cookie" chrome dev plugin but I cannot read it using jquery
console.log( JSON.stringify($.cookie()) );
var username = $.cookie("username");
$.cookie()
is empty and $.cookie("username")
is undefined.
Today I use this module set a cookie to be found when the writing is Chinese,
it will error "TypeError: argument value is invalid".
Later I discovered that such a line of code,
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
So I think that this module does not support the direct use of Chinese were cookies.set.
The Chinese need to escape to the corresponding unicode coding can write a cookie.
(先把中文转义为Unicode字符,然后再使用cookies写入cookie即可) just like
cookies.set("userName", encodeURI('中文名字'), {..});
Right now has to manually do
res.clearCookie("user")
res.clearCookie("user.sig")
This exposes the .sig convention. It is desirable to have a method clearCookie to hide the implementation. Thanks!
Couldn't you help those who don't use npm? keygrip as submodule, plus Makefile to perform installation, e.g. to generate defaultKeys?
TIA,
--Vladimir++
i think setting the options every time you .get()
or .set()
the cookies is pretty annoying. we should able to use default options passed to the constructor.
If https terminates at the load balancer, and thus node is not running https, I can't use secure cookies. Would you accept a PR to enable an option to override https://github.com/expressjs/cookies/blob/master/lib/cookies.js#L60?
I'm using Koajs, but I saw this is the middleware they use to handle cookies, so I'm posting the issue here. I tried tracing the issue, but to no avail. I'm not sure if this is intended, but it most likely seems like it shouldn't be creating 2 cookies.
This is the code I use to set a cookie.
this.cookies.set('auth', cookieValue, {
signed: true,
httpOnly: true,
maxAge: 1000 * 60 * 3
});
But then when I check my browser's resource cache there are 2 cookies set - one of them is even unsigned.
Because my nodejs app behind an nginx.
Browser == https ==> nginx == http ==> nodejs app
So req.protocol
always be http
, then I cookies.set(name, value, {secure: true}
it throw Cannot send secure cookie over unencrypted connection
Error.
which parses would be pretty sweet
hello,
I'm testing my node.js backend with superagent, and getPattern fails to parse a signed cookie, i.e. this one:
express:sess=eyJwYXNzcG9ydCI6eyJ1c2VyIjoiNTNjNjg4OWFiOTc0NjYyMTM2MGVmZTAyIn19; path=/; httponly, express:sess.sig=N-FXNwh7O7zoCJhfJ8pv-6RerH0; path=/; httponly
replacing line 119:
return cache[name] = new RegExp(
"(?:^|;) *" +
name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") +
"=([^;]*)"
)
with:
return cache[name] = new RegExp(
"(?:^|;)*" +
name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") +
"=([^;]*)"
)
seems to solve, don't know why
With last update I can only set one cookie at a time :
This :
var cookies = new Cookies( req, res, null );
cookies.set( "user", user, { httpOnly: true } )
cookies.set( "session", session, { httpOnly: true } );
res.json({status : "ok"});
work with previous version but not by the last one.
Only the last (session one) set works ...
A utility method to expire a cookie immediately and get rid of the signature cookie in the case of a signed cookie would be nice.
yo, some express collabs want encrypted cookies. i don't think it's too crazy of an idea. want to move this and keygrip to the expressjs org so we can get the entire express team collaborating on this? i'll add you as owner to the org so you can transfer it
aside from the other issues listed:
Cookies([options])
. this means that doing .set()
without any options doesn't mean to signed: false
, and .set()
with an empty option doesn't default to signed: !!this.keys
. this is super confusing.overwrite
defaults to true
Quoted from the documentation:
If the signature cookie hash matches any other key, the original cookie value is
returned AND an outbound header is set to update the signature cookie's value to the
hash of the first key. This enables automatic freshening of signature cookies that
have become stale due to key rotation.
This is very ill advised. If an application uses more than one cookie, then I can forge an arbitrary cookie, because:
TypeError: Cannot read property 'connect.sid' of undefined at Object.session [as handle]
Add: i use it as middleware
Maybe add method .all()
?
Is this class for node servers only? I attempted to use it in conjunction with http.request() and got an error reading from an undefined value.
/Apache/www/api_unit_tests/node_modules/cookies/lib/cookies.js:14
header = this.request.headers[ "cookie" ]
TypeError: Cannot read property 'cookie' of undefined
at Object.get (/Apache/www/api_unit_tests/node_modules/cookies/lib/cookies.js:14:34)
at IncomingMessage.<anonymous> (/Apache/www/api_unit_tests/tests/00007 auth-get-session.js:30:23)
at IncomingMessage.emit (events.js:67:17)
at HTTPParser.onBody (http.js:113:42)
at Socket.ondata (http.js:1124:24)
at TCP.onread (net.js:336:27)
If not, is there another node library that does work for requests?
Here it seems that maxAge is expected to be set in milliseconds but browsers expect it in seconds. Bug?
if (this.maxAge) this.expires = new Date(Date.now() + this.maxAge);
In the past I had used the secureProxy setting to allow the cookies module to write secure cookies when running behind a load balancer that was handling SSL. Now that the option is removed I am getting an error indicating that I can't set secure cookies on an insecure connection.
Is there some way to work around that now?
Had a user (Firefox 38 on Linux) point out that my "remember me?" function wasn't working for them upon logging into my website. Every once in a while, someone points out that it doesn't work on some device/OS/browser combination, but finally I decide to seriously look into the issue if there is one.
My server implements "remember me?" by setting the sessionId
cookie's Expires header for 1 year in the future. However, this user was seeing an ephemeral session cookie in their browser, not this far-future cookie.
I curled my own login endpoint to examine the expires header in the response:
Set-Cookie: __cfduid=xxxx; expires=Wed, 06-Jul-16 02:19:47 GMT; ...
Set-Cookie: sessionId=xxxx; expires=Wed, 06 Jul 2016 02:19:47 GMT; ...
The user reports that the __cfduid
(Cloudflare) cookie was correctly expiring in 1 year while my site's sessionId
cookie wasn't. What's the obvious difference? It's that my cookie's expires doesn't have dashes.
And it's because this library simply calls this.expires.toUTCString()
which returns a string without dashes. (Source)
So I steal a function off Stack Overflow that prints the UTC string with dashes:
exports.cookieDate = function(date) {
var padNum = function(n) {
return n < 10 ? '0' + n : n;
};
var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var outString = '' +
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getUTCDay()] + ', ' +
padNum(date.getUTCDate()) + '-' +
months[date.getUTCMonth()] + '-' +
date.getUTCFullYear() + ' ' +
padNum(date.getUTCHours()) + ':' +
padNum(date.getUTCMinutes()) + ':' +
padNum(date.getUTCSeconds()) + ' GMT';
return outString;
};
and I pass an object { toUTCString: function() { return cookieDate(date); }
into this cookie library so that it sets the cookie with my patched UTC string.
Now my curl looks like this:
Set-Cookie: __cfduid=xxxx; expires=Wed, 06-Jul-16 02:19:47 GMT; ...
Set-Cookie: sessionId=xxxx; expires=Wed, 06-Jul-2016 02:19:47 GMT; ...
Dashes, now.
User reports that all is good. Firefox 38 on Linux is now correctly parsing the Expires for my site's sessionId
cookie and expiring it in a year.
I see that every big website I curl has dashes in its cookie expires header and http://curl.haxx.se/rfc/cookie_spec.html says "the only legal time zone is GMT and the separators between the elements of the date must be dashes". (I couldn't actually make sense of the date grammar in the RFC itself)
What do yall think?
expose a method in the API to clear/expire a cookie
like how they do here
http://expressjs.com/api.html#res.clearCookie
When the .sig
cookie is set the first time, you have all the 'opts' from the base cookie, and they propagate into the .sig
cookie. But when re-signing due to expired key, the 'opts' simply aren't available, because all you have is the name=value
that the client browser sends back.
Specifically… starting at Line 54 – we push the base cookie, then update the same object to become a signature, and push it. This should make both cookies share all the same options:
headers = pushCookie(headers, cookie)
if (opts && signed) {
cookie.value = this.keys.sign(cookie.toString())
cookie.name += ".sig"
headers = pushCookie(headers, cookie)
}
But up in the ‘get’ method, if we detect the signing key index was not zero on Line 34:
index && this.set(sigName, this.keys.sign(data), { signed: false })
here all we have is name and value. The cookie we’re looking at could have been configured months ago, all the domain/path/expires/etc. settings are long gone from the server.
The largest impact I think is for persistent signed cookies. If the persistent cookie is re-signed due to a new key, the signature will always expire the next time the user closes their browser. since no ‘expire’ is set. Then next time we do a ‘get’ on the base cookie, the signature will be gone completely, and it will come back as having a invalid signature.
In Cookie.prototype.set
(https://github.com/expressjs/cookies/blob/2dcb71f130a7eaafd16e71b9af70debe11d4c93f/lib/cookies.js#L69), the signed
variable is true if opts.signed
or this.keys
is truthy. However, the check for whether to sign keys or not also checks if opts
exists.
This means that if this.keys
is truthy, but opts
is undefined, the signed
variable will be true
but the key still won't be signed. My expectation is they key should be signed if signed == true
, and it shouldn't depend on the existence of opts
.
hi,
i wanted to make a signed cookie , but throws this exception
this.keys.sign is not a function at Cookies.set , \node_modules\cookies\lib\cookies.js:94:30)
The Used code :
var co = new Cookies(request,response , {keys:"somekeys" });
co.set("access","allowed",{signed:true});
So maybe you can help me. This has been driving me crazy for days. I've got a Node project I'm trying to use this library in. For some reason, the cookies this library sends out aren't being retained by the client's browser (Mac/Chrome and Firefox). Oh, I can see the Set-Cookie
header come in -- but it isn't accessible to JavaScript (even though httpOnly
is set to false
) and the cookie isn't recognized by the library on the next request, even though by all rights it should be there.
I wrote up a test case. Here it is:
var http = require('http'),
Cookies = require('cookies'),
getIpAddress = require('ipware')().get_ip;
function getExpireDate(created) {
var expired = new Date();
expired.setTime(created.getTime() + 82800000);
return expired;
}
function parseCookie(rawCookie) {
var split = rawCookie.split("$");
return {
'ip': split[0],
'time': split[1]
};
}
var server = http.createServer(function(request, response) {
var cookieManager = new Cookies(request, response),
cookie = cookieManager.get("token"),
userIp = getIpAddress(request),
currentTime = new Date();
if (!cookie) {
console.log("Cookie is null, creating a new one");
cookie = encodeURIComponent(userIp.clientIp + "$" + currentTime.getTime());
var expired = getExpireDate(currentTime);
cookieManager.set("token", cookie, {
'maxAge': 82800000,
'expires': expired,
'domain': '*',
'path': '/',
'httpOnly': false,
'signed': false,
'overwrite': false,
'secure': false,
'secureProxy': false
});
} else {
var cookieInfo = parseCookie(decodeURIComponent(cookie)),
cookieCreated = new Date();
cookieCreated.setTime(cookieInfo.time);
console.log("Got cookie!");
console.log("Created for %s at %s", cookieInfo.ip, cookieCreated.toString());
}
// put together a json response
var json = {'success': true, 'response': { 'message': "well, did this work?"} },
data = JSON.stringify(json) + "\r\n";
// send a response
response.writeHead(200, {
'Connection': 'Keep-Alive',
'Keep-Alive': 'timeout=5, max=100',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
'Access-Control-Allow-Origin': '*',
'Content-Type': "application/json",
'Content-Length': data.length
});
response.end(data, 'utf8');
});
server.listen(8008);
When I start this server and hit it in my browser, "Cookie is null, creating a new one" comes up on the console screen. Every single time.
Any idea what's going on here? Is there anything I'm doing wrong that you can see? I would appreciate the help.
Thank you for your time.
Really wish you would support that spelling since that is what express uses. This spelling is also leaking into cookie-session
https://github.com/expressjs/cookie-session#cookie-options
Express docs : http://expressjs.com/4x/api.html#res.cookie
Hi,
I think the example in the readme should include the require statement because it looks like it's not being used like the typical module, e,g; fs=require('fs'); fs.[useful function].
It be good for people first looking at it to see how all the pieces fall into place.
This library is wonderful for getting and setting individual cookies. I have a case where I need to get all cookies though.
It'd be nice to just re-use the get()
function without specifying a key:
var cookies = new Cookies(req, res, keys);
var allCookies = cookies.get();
Thanks for your hard work!
currently .get is getting from request. It would be awesome if it can also take account of what has been set during the request on its response:
cookies = new Cookies(req, res);
cookies.set( "unsigned", "foo", { httpOnly: false } );
console.log cookies.get( "unsigned" );
this will log undefined
currently tests aren't web scale
process.exit()
correctly without control flow and either closing the server or manually exiting the processif anyone wants to add tests... i like mocha but i don't discriminate
Hello Sir
Thank you for taking the effort to create cookies (module).
I would like to point out that the example in the README is fine but it doesn't works if a user copy pastes them and tries to run the server.
These are the issues :
The solutions:
npm install keygrip
var keygrip = require("keygrip")
var keys = keygrip(["SEKRIT2", "SEKRIT1"], 'sha256', 'hex')
var assert = require("assert")
<Copying pasting the code here will make this too long>
}).listen(3000);
<Copying pasting the code here will make this too long>
If you think that these changes are important, then please add them to the README or in a separate Example folder.
If you allow I will be more than happy to post a Pull Request for the same, with whatever you want (README changes, Example folder anything else).
to avoid issues with cookie strings with ;
and stuff.
I've got a node.js server and wrote a cookie in client, but i don't know how do i read it without node.js, can i read it by javascript? how do i do that?
With sessions, actual expiration date is backed up in server and therefore clients can't change them to forever; but signed cookies have expiration dates exposed to clients.
To secure this, servers can sign a copy of the expiration date, and compare the dates prior to validation.
I have a client that sends cookies in version 1 format, $Version: "1"
I noticed that all cookies sent with version 1 are quoted i.e. name: "value"
.
Does this module parse them correctly as well ? I had some problems using version 1 cookies with mozilla/node-client-sessions, specifically, the session cookie was not being parsed correctly because of the quotation marks
The current tests in this module leaves a lot to be desired. They really need to be refactored and all code paths in the module accounted for in tests.
apparently semicolons, commas, and whitespace are not allowed in cookies... but JSON has been working for me so i don't know if this is necessary.
Hi Jed,
I was going to leave a question about where to find a client side library to do cookies, but instead (thanks to IRC #node.js@freenode) I'll leave a hint to anyone else.
If you are looking to do cookies client side you should use https://github.com/mikeal/request
Thanks, M.
the maxAge
option is misleading. It should translate to the max-age
cookie directive, not expires
with Date.now()
base.
Date.now
causes issues when maxAge
is low (a few hours), since it uses the server date, and the client date may be different due to timezones.
Do you plan on adding support for StirFry? There are currently no cookie processors for it. I'm not completely sure how your code works, but you probably will be able to do it just by removing next()
.
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.