Skip to content

Instantly share code, notes, and snippets.

@craigyk
Created October 4, 2012 06:31
Show Gist options
  • Save craigyk/3831786 to your computer and use it in GitHub Desktop.
Save craigyk/3831786 to your computer and use it in GitHub Desktop.
connect-session implementation
crypto = require 'crypto'
connectionSecure = (req,trust_proxy=true) ->
secure_proxy = ( req.headers['x-forwarded-proto'] or '' ).toLowerCase() == 'https'
req.connection.encrypted or ( trust_proxy and secure_proxy )
createID = (len) -> crypto.randomBytes(Math.ceil(len*3/4)).toString('base64').slice(0,len)
# not implemented yet
signId = (unsignedid,secret) -> unsignedid
unsignId = (signedid,secret) -> signedid
expiresAfter = (age) ->
if age?
new Date Date.now() + age
else null
class MemoryStore
constructor : ->
@store = {}
get : (sid,next) ->
# maybe I should move all these to nextTick?
# just in case someone expects them to be asynchronous
next null, @store[sid] ? {}
set : (sid,session,next) ->
next null, @store[sid] = session
destroy : (sid,next) ->
next null, delete @store[sid]
this.session = (options) ->
secret = options.secret
store = options.store or new MemoryStore
key = options.key or 'sessionid'
if not secret
throw new Error 'a secret is required for sessions'
# well no, not yet, but soon
(req,res,next) ->
if req.session
return do next
if not req.cookies[key] or req.cookies[key] == 'undefined'
req.sessionid = createID 128
else req.sessionid = unsignId req.cookies[key], secret
res.on 'header', ->
if not req.session then return
if req.cookies.expires == null
if req.cookies[key] == signId req.sessionid, secret
return console.log "not resending session id cookie"
if req.cookies.secure
if not connectionSecure req, options.trust_proxy
return console.log "skipped setting session, non-secure connection with secure cookie"
# co-opt cookies to keep them all server-side?
req.session.cookies = req.cookies
res.cookie key, ( signId req.sessionid, secret ),
httpOnly : options.httpOnly ? true
secure : options.secure ? false
expires : expiresAfter options.max_age
path : options.path ? '/'
end = res.end
res.end = (data, encoding) ->
res.end = end
if not req.session
return res.end data, encoding
store.set req.sessionid, req.session, (e) ->
res.end data, encoding
do req.pause
store.get req.sessionid, (err,session) ->
req.session = session or {}
req.cookies = req.session.cookies or {}
do req.resume # <- is order important here?
next err #
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment