Skip to content
This repository

with v1.8.3 there is a parseCookie in utils but with v2, what it becomes? #588

Closed
crapthings opened this Issue June 08, 2012 · 43 comments
crapthings

parseCookie = parseSignedCookie ?

Hongbo LU

the only way I found is:

var cookie = require('cookie');
var yourCookiesObject = connect.utils.parseSignedCookies(cookie.parse(req.headers.cookie),'your cookie secret');

bigal488

connect.utils.parseCookie is no longer present in utils.js???

Hongbo LU

not any more... as far as I can see

TJ Holowaychuk
Collaborator

we're slowly moving some utils out into additional modules. For socket.io integration (assuming that's what you're doing here ;) ) you'll just require a module to unsign the cookies instead of using connect's utils

Hongbo LU

it's exactly what I'm doing... I'm so glad to hear that you are trying to work with socket.io ^^

Vaughan Rouesnel
vjpr commented June 27, 2012

So is @gitawego 's solution the way to go for now?

Hongbo LU

a little notice:
in the latest version of connect, the cookie string is escaped, but parseSignedCookies trys to match unescaped string, such as "s:" instead of "s%3A". so to ensure it:

var cookie = require('cookie');
var yourCookiesObject = connect.utils.parseSignedCookies(cookie.parse(decodeURIComponent(req.headers.cookie)),'your cookie secret');

TJ Holowaychuk visionmedia closed this June 27, 2012
Nick Baugh

shouldn't we throw an error about this or something since a lot of people are using this with socket.io? almost every tutorial out there has usage of parseCookie.

TJ Holowaychuk
Collaborator

they were private apis in the first place

Fabian Kochem
vortec commented July 29, 2012

@visionmedia : Considering how many people and tutorials were using this, don't you think it would be a good idea to revise that decision?

connect.utils.parseCookie()
vs.
connect.utils.parseSignedCookies(cookie.parse(decodeURIComponent(req.headers.cookie)),'secret');

TJ Holowaychuk
Collaborator

they shouldn't use them though, I've seen people have this problem so often im still really surprised that no one has abstracted it out into a module so this sort of breakage can at least be taken care of at a single point

TJ Holowaychuk
Collaborator

It'll be a bit easier once the rest of the connect related utils are npm modules

bgSosh
bgSosh commented July 31, 2012

Hmm, so that's why parseCookie is not working - I need something like this for websockets, but I'm not using socket.io, so the fact that it's being offloaded there is a little annoying. Pity it was taken out...

TJ Holowaychuk
Collaborator

these are not public

bgSosh

But the fact remains that everybody is using it like this (because there is no alternative). Look at any answer related to this on Stackoverflow for instance. Public/private aside, you say you're moving the utils out into additional modules - which is fine, but wouldn't it be less disruptive to wait until the alternative module exists before pulling them?

Fabian Kochem

I don't understand. All functions in utils are documented fully on your homepage, and they're not flagged as private: http://www.senchalabs.org/connect/utils.html

How should people know that they're private without looking at the code?

Am I missing something or are the only indicators for private functions code comments like this:
https://github.com/senchalabs/connect/blob/master/lib/utils.js#L24
?

bigal488

I really think this needs to be re-instated. Given that it is in use by SO many people and is on, just about, every socket.io tutorial (and will continue to be for years to come), is it really so much of a problem to re-instate and keep everyone happy?

TJ Holowaychuk
Collaborator

yes but if you're copy / pasting the same chunk of code around that's not the right way to have maintainable code, someone needs to make this same thing a module so it even if it does break, that it's easier to fix and everyone can benefit. We do need to move some of these into npm so things are easier

TJ Holowaychuk
Collaborator

@vortec yes, and it's reasonably obvious since connect is not a mixed bag of utils, that's not its purpose, it's middleware. we simply need to move more of these into npm to make them more convenient, moving them all back into connect is not the right way to go

blevine

This is really surprising. You've removed a widely-used function without any warning and without providing any alternatives. You assert that these were private functions, but there is absolutely no way for a developer to know that. This change breaks all kinds of existing code. Please reconsider this decision.

TJ Holowaychuk
Collaborator

It's not my fault that someone choose to blog about it, using private utilities. We've made progress moving things out of Connect so that in the future more people / frameworks can use these, I dont want to go back on that progress. It's very unfortunate that so many people copy/pasted this code instead of consolidating it but that's all I can say about that, someone should be encapsulating this behaviour

blevine

IMHO, you removed functionality that many people were using and so you should have ensured that it was encapsulated elsewhere if that's the right thing to do. The point here is that you aren't "moving" these utilities, you're simply deleting them. So that this doesn't happen again, could you explain how we should determine the difference between public and private utilities?

blevine

And while we're on the subject of private vs public. I've implemented @gitawego 's solution (Thank you!) which works fine. I just want to make sure that it's OK to use parseSignedCookies and that this doesn't fall into the private category.

Fabian Kochem

@blevine They mention it in the code documentation:
https://github.com/senchalabs/connect/blob/master/lib/utils.js#L18

"@api private"

If there are other ways, I'd like to know too.

Fabian Kochem

@blevine it is private as well.

blevine

@vortec. Fair enough. But as you pointed out earlier, all of these functions are in the documentation and are not marked as private. Don't get me wrong. I'm grateful that there's good documentation. However, it really seems that private functions should either not be included in the documentation or the documentation should make it clear that these functions are private.

TJ Holowaychuk
Collaborator

yeah they should mention that in the docs, I figured "internals" kinda implied that but you're right there

Aaron Yoshitake

I just want to thank everyone involved for this discussion, I've learned a lot, but most valuable is the solution to this issue, which gitawego posted: #588 (comment)
I've posted a link to this workaround on the blog I was following, so hopefully others will find this solution when they run into this same problem.
I'd also like to echo blevine's complaint that parseCookie wasn't marked as private in the documentation, and his/her desire to not have to refactor our use of parseSignedCookie in a future version of connect.

@airandfingers parseSignedCookie is a private api too, posting it on blogs and SO is exactly how this situation started in the first place.

Aaron Yoshitake

I understand that parseSignedCookie is private, but I think that whoever decides these things should factor in widespread usage when determining which parts of the API will be private or public.

Also, I think it's worth noting that Socket.IO's Github wiki itself points at the article in question: https://github.com/learnboost/socket.io/wiki/ (Articles and Recipes, Socket.IO Express and Sessions). That's how I found out about parseCookie, and maybe a dialog between Connect's and Socket.IO's developers needs to be taking place.

TJ Holowaychuk
Collaborator

it's like a lot of things in node's core even, .binding() for example was never public, but many people used it. naturally when things like this are removed people complain, eventually someone does it the "correct" way and life goes on. To make them public and to revert changes would be a regression, we need to move forward and make socket.io integration easier by moving more of these utilities into npm.

jugglinmike

I have a similar need (my specific use case is sharing session data between socket.io and express). I'm experimenting with a solution using only public methods, and I'm wondering what the consensus is regarding this approach:

var sessionSecret = "super secret";
// Connect's session middleware expects to receive the secret, so the
// cookieParser instance used by your application likely is not aware
// of it.
var sioCookieParser = express.cookieParser(sessionSecret);

// Connect app
var app = connect()
  .use(connect.cookieParser())
  .use(connect.session({ secret: sessionSecret }))
  .use(function(req, res) {
    res.end("hello world\n");
  })
 .listen(3000);

// Socket.io app
io.sockets.on("connection", function(socket) {

  sioCookieParser(socket.handshake, {}, function(err) {
    // Parsed cookies are now in socket.handshake.cookies and
    // socket.handshake.securecookies
  });
});
TJ Holowaychuk
Collaborator

@jugglinmike yeah if that works fine for you nothing wrong with that

Fabian Kochem

@jugglinmike and how exactly do you access the session object?

jugglinmike

@vortec I'll extend the above example with Express and RedisStore to show how you might do that:

var express = require("express");
var RedisStore = require("connect-redis")(express);
var sessionSecret = "super secret";
var store = new RedisStore();
var sioCookieParser = express.cookieParser(sessionSecret);

// Express app
var app = express()
  .use(connect.cookieParser())
  .use(connect.session({ store: store, secret: sessionSecret }))
  .use(function(req, res) {
    res.end("hello world\n");
  })
 .listen(3000);

// Socket.io app
io.sockets.on("connection", function(socket) {

  sioCookieParser(socket.handshake, {}, function(err) {
    store.get(socket.handshake.secureCookies["connect.sid"], function(err, sessionData) {
      // session data available here
    });
  });
});
Fabian Kochem

@jugglinmike thank you, seems to be a really neat way to connect express + socket.io + sessions. I was close to writing a library doing just that.

TJ Holowaychuk
Collaborator

@vortec doooo it, haha, if someone abstracts this out into a declarative module we can all rest in peace and people can stop copy/pasting blog posts

Wagner Camarao

hey first thing thank you all, I just abstracted this out into a module and would like to know if it works for you guys: https://github.com/functioncallback/session.socket.io

Nick Hagianis

Thank you @functioncallback your module is simple and effective.

kcaffrey

Thanks for the code examples @functioncallback. The one problem is that it seems preferable to do the session parsing in the Socket.IO Authorizing and handshake step, so that if the session is not present or valid the connection itself is refused.

Here is the code (adapted from your code) that I used to do this:

var express = require('express');
var http = require('http');
var connect = require('express/node_modules/connect');
var secret = 'some secret';
var sessionKey = 'express.sid';
var cookieParser = express.cookieParser(secret);
var sessionStore = new connect.middleware.session.MemoryStore();
var app = express();

app.configure(function() {
  ...
  app.use(cookieParser);
  app.use(express.session({ store: sessionStore, key: sessionKey });
  ...
});

var server = http.createServer(app);
var io = require('socket.io').listen(server);

io.set('authorization', function(data, accept) {
  cookieParser(data, {}, function(err) {
    if (err) {
      accept(err, false);
    } else {
      sessionStore.get(data.signedCookies[sessionKey], function(err, session) {
        if (err || !session) {
          accept('Session error', false);
        } else {
          data.session = session;
          accept(null, true);
        }
      });
    }
  });
});

io.sockets.on('connection', function(socket) {
  socket.session = socket.handshake.session;
  // Now you can put Socket.IO code here as normal using socket.session.
});

I think a general solution could be put into a module that provided the function(data, accept) {} handler, so that the user would just have to do something like:

io.set('authorization', require('session.socket.io').authorize(cookieParser, sessionStore, sessionKey));
Wagner Camarao

I see your point @kcaffrey, but I can't agree for a couple reasons: refusing a connection if the session is not found/valid and changing the socket object to add the session.

Wagner Camarao wcamarao referenced this issue in wcamarao/session.socket.io November 18, 2012
Closed

Example with socket authorization #6

eephillip eephillip referenced this issue in wcamarao/session.socket.io December 31, 2012
Closed

Question about using the socket.io authorization setup #10

gizmo_tronic

@jugglinmike your solution was exactly what the doctor ordered - clean and effective. Thanks!

jugglinmike

@gizmotronic Glad to hear it :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.