Force share.js use the same express session data

257 views Asked by At

I have a simple express app that use session middleware together with passport-local middleware. Then I use share.js with browserchannel to stream data to server via share.listen(stream). All in align with documentation here.

My problem is that I cannot access session data (modified by passport-local and containing userID that was logged in) within stream. I need it to be able to restrict/grant access within client.on('message', function(data) {..}); based on some logic, but what of first importance is to check that the message came from logged in user. There, if I try to read ID it will be different from what potencialy is inside req.user._id. It seems that there share.js or browserchannel uses some different session, maybe?..

Here's the code:

var app = express();
var express = require('express');
...

// SETUP AND INIT
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true,
    limit:    1024 * 1024 * 10
}));
app.use(methodOverride());
app.use(session({
    secret:             global.CONFIG.session.secret,
    maxAge:             new Date(Date.now() + 1000 * 60 * 60 * 24 * 2),
    store:              new MongoStore(global.CONFIG.mongo),
    resave:             true,
  saveUninitialized:  true
}));
app.use(express.static(__dirname + '/build')); 
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());


// Create the sharejs server instance.
var backend = livedb.client(livedbMongo(global.CONFIG.mongo.url, false));
var share = sharejs.server.createClient({
  db: backend
});
app.use(browserChannel(function(client) {
  var stream = new Duplex({objectMode: true});

  stream._write = function(chunk, encoding, callback) {
    if (client.state !== 'closed') {
      client.send(chunk);
    }
    callback();
  };

  stream._read = function() {
  };

  stream.headers = client.headers;
  stream.remoteAddress = stream.address;

  client.on('message', function(data) {
    console.log(client.id) // <- I wish it was the same as in req.user._id..
    stream.push(data);
  });
  stream.on('error', function(msg) {
    client.stop();
  });
  client.on('close', function(reason) {
    stream.emit('close');
    stream.emit('end');
    stream.end();
  });

  // Actually pass the stream to ShareJS
  share.listen(stream);
}));
3

There are 3 answers

0
kaytrance On BEST ANSWER

After several days of inspecting the code I have found a solution. If we look at this line in browserchannel/dist/server.js we can see that the session is being created using some information from initial request. We can modify this part of code by adding

session = createSession(req.connection.remoteAddress, query, req.headers);
// ----------- we add this ------------
session.user = {};
if( req.user )
   session.user = req.user;
// ------------------------------------

This will add user session details from initial request to the session variable.

0
robertklep On

It seems to me, from looking at the code, that there might be a solution that won't require hacking the module:

var browserChannel = require('browserchannel').server;

var middleware = browserChannel(options, function(session, req) {
  if (req.user) {
    session.user = req.user;
  }
});

app.use(middleware);

See here.

0
Marcello Del Buono On

I have the same problem and I solved it by wrapping the browserchannel middleware constructor in a custom constructor:

function myMiddlewareConstructor () {

    var request;

    var bcMiddleware = browserChannel(function (client) {
        //here you see the request
    });

    return function (req,res,next) {
        request = req;
        bcMiddleware(req,res,next);
    }

}

app.use(myMiddlewareConstructor());

It avoids having to change the browserchannel code.