Skip to content
Snippets Groups Projects
Commit 435342c0 authored by Lloyd Hilaiel's avatar Lloyd Hilaiel
Browse files

move off in-tree cookie-sessions now that upstream accepted our patches

parent fd1ea892
No related branches found
No related tags found
No related merge requests found
......@@ -10,7 +10,7 @@ All of the servers here are based on node.js, and some number of 3rd party node
* xml2js (>= 0.1.5)
* sqlite (>= 1.0.3)
* mustache (>= 0.3.1)
* cookie-sessions (patched version included in-tree, nothing to be done)
* cookie-sessions (>= 0.0.2)
## Getting started:
......
Here live first and third party re-usable modules for node.
* cookie-sessions - encrypted cookie based session storage (will a less stateful
server make), forked and improved, thus included inline here. Original work:
https://github.com/caolan/cookie-sessions
[submodule "deps/nodeunit"]
path = deps/nodeunit
url = git://github.com/caolan/nodeunit.git
Copyright (c) 2010 Caolan McMahon
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.
# Cookie-Sessions
Secure cookie-based session middleware for
[Connect](http://github.com/senchalabs/connect). This is a new module and I
wouldn't recommend for production use just yet.
Session data is stored on the request object in the 'session' property:
var connect = require('connect'),
sessions = require('cookie-sessions');
Connect.createServer(
sessions({secret: '123abc'}),
function(req, res, next){
req.session = {'hello':'world'};
res.writeHead(200, {'Content-Type':'text/plain'});
res.end('session data updated');
}
).listen(8080);
The session data is JSON.stringified, encrypted and timestamped, then a HMAC
signature is attached to test for tampering. The main function accepts a
number of options:
* secret -- The secret to encrypt the session data with
* timeout -- The amount of time in miliseconds before the cookie expires
(default: 24 hours)
* session_key -- The cookie key name to store the session data in
(default: _node)
## Why store session data in cookies?
* Its fast, you don't need to hit the filesystem or a database to look up
session data
* It scales easily. You don't need to worry about sticky-sessions when
load-balancing across multiple nodes.
* No server-side persistence requirements
## Caveats
* You can only store 4k of data in a cookie
* Higher-bandwidth requirements, since the cookie is sent to the server with
every request.
__In summary:__ don't use cookie storage if you keep a lot of data in your
sessions!
// This file is just added for convenience so this repository can be
// directly checked out into a project's deps folder
module.exports = require('./lib/cookie-sessions');
var crypto = require('crypto');
var url = require('url');
var exports = module.exports = function(settings){
var default_settings = {
// don't set a default cookie secret, must be explicitly defined
session_key: '_node',
timeout: 1000 * 60 * 60 * 24, // 24 hours
path: '/'
};
var s = extend(default_settings, settings);
if(!s.secret) throw new Error('No secret set in cookie-session settings');
if(typeof s.path !== 'string' || s.path.indexOf('/') != 0)
throw new Error('invalid cookie path, must start with "/"');
return function(req, res, next){
// if the request is not under the specified path, do nothing.
if (url.parse(req.url).pathname.indexOf(s.path) != 0) {
next();
return;
}
// Read session data from a request and store it in req.session
var bad_cookie = false;
try {
req.session = exports.readSession(
s.session_key, s.secret, s.timeout, req);
} catch(e) {
console.log("bad cookie: " + e);
bad_cookie = true;
}
// proxy writeHead to add cookie to response
var _writeHead = res.writeHead;
res.writeHead = function(statusCode){
var reasonPhrase, headers;
if (typeof arguments[1] === 'string') {
reasonPhrase = arguments[1];
headers = arguments[2] || {};
}
else {
headers = arguments[1] || {};
}
// Add a Set-Cookie header to all responses with the session data
// and the current timestamp. The cookie needs to be set on every
// response so that the timestamp is up to date, and the session
// does not expire unless the user is inactive.
var cookiestr;
if (req.session === undefined) {
if ("cookie" in req.headers) {
cookiestr = escape(s.session_key) + '='
+ '; expires=' + exports.expires(0)
+ '; path=' + s.path;
}
} else {
cookiestr = escape(s.session_key) + '='
+ escape(exports.serialize(s.secret, req.session))
+ '; expires=' + exports.expires(s.timeout)
+ '; path=' + s.path;
}
if (cookiestr !== undefined) {
if(Array.isArray(headers)) headers.push(['Set-Cookie', cookiestr]);
else {
// if a Set-Cookie header already exists, convert headers to
// array so we can send multiple Set-Cookie headers.
if(headers['Set-Cookie'] !== undefined){
headers = exports.headersToArray(headers);
headers.push(['Set-Cookie', cookiestr]);
}
// if no Set-Cookie header exists, leave the headers as an
// object, and add a Set-Cookie property
else {
headers['Set-Cookie'] = cookiestr;
}
}
}
var args = [statusCode, reasonPhrase, headers];
if (!args[1]) {
args.splice(1, 1);
}
// call the original writeHead on the request
return _writeHead.apply(res, args);
}
next();
};
};
exports.headersToArray = function(headers){
if(Array.isArray(headers)) return headers;
return Object.keys(headers).reduce(function(arr, k){
arr.push([k, headers[k]]);
return arr;
}, []);
};
// Extend a given object with all the properties in passed-in object(s).
// From underscore.js (http://documentcloud.github.com/underscore/)
function extend(obj) {
Array.prototype.slice.call(arguments).forEach(function(source) {
for (var prop in source) obj[prop] = source[prop];
});
return obj;
};
exports.deserialize = function(secret, timeout, str){
// Parses a secure cookie string, returning the object stored within it.
// Throws an exception if the secure cookie string does not validate.
if(!exports.valid(secret, timeout, str)){
throw new Error('invalid cookie');
}
var data = exports.decrypt(secret, exports.split(str).data_blob);
return JSON.parse(data);
};
exports.serialize = function(secret, data){
// Turns a JSON-compatibile object literal into a secure cookie string
var data_str = JSON.stringify(data);
var data_enc = exports.encrypt(secret, data_str);
var timestamp = (new Date()).getTime();
var hmac_sig = exports.hmac_signature(secret, timestamp, data_enc);
var result = hmac_sig + timestamp + data_enc;
if(!exports.checkLength(result)){
throw new Error('data too long to store in a cookie');
}
return result;
};
exports.split = function(str){
// Splits a cookie string into hmac signature, timestamp and data blob.
return {
hmac_signature: str.slice(0,40),
timestamp: parseInt(str.slice(40, 53), 10),
data_blob: str.slice(53)
};
};
exports.hmac_signature = function(secret, timestamp, data){
// Generates a HMAC for the timestamped data, returning the
// hex digest for the signature.
var hmac = crypto.createHmac('sha1', secret);
hmac.update(timestamp + data);
return hmac.digest('hex');
};
exports.valid = function(secret, timeout, str){
// Tests the validity of a cookie string. Returns true if the HMAC
// signature of the secret, timestamp and data blob matches the HMAC in the
// cookie string, and the cookie's age is less than the timeout value.
var parts = exports.split(str);
var hmac_sig = exports.hmac_signature(
secret, parts.timestamp, parts.data_blob
);
return (
parts.hmac_signature === hmac_sig &&
parts.timestamp + timeout > new Date().getTime()
);
};
exports.decrypt = function(secret, str){
// Decrypt the aes192 encoded str using secret.
var decipher = crypto.createDecipher("aes192", secret);
return decipher.update(str, 'hex', 'utf8') + decipher.final('utf8');
};
exports.encrypt = function(secret, str){
// Encrypt the str with aes192 using secret.
var cipher = crypto.createCipher("aes192", secret);
return cipher.update(str, 'utf8', 'hex') + cipher.final('hex');
};
exports.checkLength = function(str){
// Test if a string is within the maximum length allowed for a cookie.
return str.length <= 4096;
};
exports.readCookies = function(req){
// if "cookieDecoder" is in use, then req.cookies
// will already contain the parsed cookies
if (req.cookies) {
return req.cookies;
}
else {
// Extracts the cookies from a request object.
var cookie = req.headers.cookie;
if(!cookie){
return {};
}
var parts = cookie.split(/\s*;\s*/g).map(function(x){
return x.split('=');
});
return parts.reduce(function(a, x){
a[unescape(x[0])] = unescape(x[1]);
return a;
}, {});
}
};
exports.readSession = function(key, secret, timeout, req){
// Reads the session data stored in the cookie named 'key' if it validates,
// otherwise returns an empty object.
var cookies = exports.readCookies(req);
if(cookies[key]){
return exports.deserialize(secret, timeout, cookies[key]);
}
return undefined;
};
exports.expires = function(timeout){
return (new Date(new Date().getTime() + (timeout))).toUTCString();
};
{ "name": "cookie-sessions"
, "description": "Secure cookie-based session middleware for Connect"
, "main": "./index"
, "author": "Caolan McMahon"
, "version": "0.0.3"
, "repository" :
{ "type" : "git"
, "url" : "http://github.com/caolan/cookie-sessions.git"
}
, "bugs" : { "web" : "http://github.com/caolan/cookie-sessions/issues" }
, "licenses" :
[ { "type" : "MIT"
, "url" : "http://github.com/caolan/cookie-sessions/raw/master/LICENSE"
}
]
}
#!/usr/local/bin/node
require.paths.push(__dirname);
require.paths.push(__dirname + '/deps');
require.paths.push(__dirname + '/lib');
try {
var testrunner = require('nodeunit').testrunner;
}
catch(e) {
var sys = require('sys');
sys.puts("Cannot find nodeunit module.");
sys.puts("You can download submodules for this project by doing:");
sys.puts("");
sys.puts(" git submodule init");
sys.puts(" git submodule update");
sys.puts("");
process.exit();
}
process.chdir(__dirname);
testrunner.run(['test']);
var sessions = require('cookie-sessions');
exports['split'] = function(test){
var hmac_sig = 'c82d1eacb4adb15a3250a6df7c8f190b586ab6b9',
timestamp = 1264710287440,
data_blob = 'somedata';
var serialized_cookie = hmac_sig + timestamp + data_blob;
test.same(
sessions.split(serialized_cookie),
{hmac_signature: hmac_sig, timestamp: timestamp, data_blob: data_blob},
'split correctly seperates sig, timestamp and data blob'
);
test.done();
};
exports['valid'] = function(test){
var secret = 'secret';
current_valid_sig = '5eaaa22480acefd8b18d67bb194573dc1b75d9db',
expired_valid_sig = '9c7ad86913ceeced1f6f249ba52868006c8dfdab',
invalid_sig = '51a2a32485a6e7d8b9810711112513d14b15d16b',
expired_timestamp = 1264700000000,
current_timestamp = 1264710287440,
session_timeout = 54000,
data_blob = 'somedata';
var Date_copy = global.Date;
global.Date = function(){this.getTime = function(){return 1264710287000}};
test.ok(
sessions.valid(
secret, session_timeout,
current_valid_sig + current_timestamp + data_blob
) === true,
'returns true for valid hmac sig within timeout'
);
test.ok(
sessions.valid(
secret, session_timeout,
expired_valid_sig + expired_timestamp + data_blob
) === false,
'returns false for valid hmac sig past timeout'
);
test.ok(
sessions.valid(
secret, session_timeout,
invalid_sig + current_timestamp + data_blob
) === false,
'returns false for invalid hmac sig within timeout'
);
test.ok(
sessions.valid(
secret, session_timeout,
invalid_sig + expired_timestamp + data_blob
) === false,
'returns false for invalid hmac sig past timeout'
);
// restore Date
global.Date = Date_copy;
test.done();
};
exports['decrypt'] = function(test){
var r = sessions.decrypt(
'secret', '686734eb9e0fff9adea53983210825ef'
);
test.same(r, 'somedata', 'decrypt sucessfully returns decrypted data');
test.done();
};
exports['encrypt'] = function(test){
var r = sessions.encrypt('secret', 'somedata');
test.same(
r, '686734eb9e0fff9adea53983210825ef',
'encrypt sucessfully returns encrypted data'
);
test.done();
};
exports['deserialize valid cookie'] = function(test){
test.expect(8);
// copy some functions
var valid = sessions.valid;
var decrypt = sessions.decrypt;
var parse = JSON.parse;
sessions.valid = function(secret, timeout, str){
test.equals(secret, 'secret', 'valid called with secret');
test.equals(timeout, 123, 'valid called with timeout');
test.equals(str, 'cookiestring', 'valid called with cookie string');
return true;
};
sessions.split = function(str){
test.equals(str, 'cookiestring', 'split called with cookie string');
return {data_blob: 'datastr'};
};
sessions.decrypt = function(secret, str){
test.equals(secret, 'secret', 'decrypt called with secret');
test.equals(str, 'datastr', 'decrypt called with data string');
return 'decrypted_data';
};
JSON.parse = function(str){
test.equals(
str, 'decrypted_data', 'JSON.parse called with decrypted data'
);
return {test:'test'};
};
var r = sessions.deserialize('secret', 123, 'cookiestring');
test.same(r, {test:'test'}, 'deserialize returns parsed json data');
// restore copied functions:
sessions.valid = valid;
sessions.decrypt = decrypt;
JSON.parse = parse;
test.done();
};
exports['deserialize invalid cookie'] = function(test){
test.expect(1);
// copy some functions
var valid = sessions.valid;
var decrypt = sessions.decrypt;
var parse = JSON.parse;
sessions.valid = function(secret, timeout, str){
return false;
};
sessions.decrypt = function(secret, str){
test.ok(false, 'should not attempt to decrypt invalid cookie');
};
JSON.parse = function(str){
test.ok(false, 'should not attempt to parse invalid cookie');
};
try {
sessions.deserialize('secret', 123, 'cookiestring');
}
catch(e){
test.ok(true, 'throw exception on invalid cookie');
}
// restore copied functions:
sessions.valid = valid;
sessions.decrypt = decrypt;
JSON.parse = parse;
test.done();
};
exports['serialize'] = function(test){
test.expect(7);
// copy some functions
var encrypt = sessions.encrypt;
var hmac_signature = sessions.hmac_signature;
var stringify= JSON.stringify;
var Date_copy = global.Date;
global.Date = function(){this.getTime = function(){return 1234;}};
JSON.stringify = function(obj){
test.same(
obj, {test:'test'}, 'JSON.stringify called with cookie data obj'
);
return 'data';
};
sessions.encrypt = function(secret, str){
test.equals(secret, 'secret', 'encrypt called with secret');
test.equals(str, 'data', 'encrypt called with stringified data');
return 'encrypted_data';
};
sessions.hmac_signature = function(secret, timestamp, data_str){
test.equals(secret, 'secret', 'hmac_signature called with secret');
test.equals(timestamp, 1234, 'hmac_signature called with timestamp');
test.equals(
data_str, 'encrypted_data',
'hmac_signature called with encrypted data string'
);
return 'hmac';
};
var r = sessions.serialize('secret', {test:'test'});
test.equals(
r, 'hmac1234encrypted_data', 'serialize returns correct string'
);
// restore copied functions:
sessions.encrypt = encrypt;
sessions.hmac_signature = hmac_signature;
JSON.stringify = stringify;
global.Date = Date_copy;
test.done();
};
exports['serialize data over 4096 chars'] = function(test){
test.expect(1);
// copy some functions
var encrypt = sessions.encrypt;
var hmac_signature = sessions.hmac_signature;
var stringify= JSON.stringify;
var Date_copy = global.Date;
global.Date = function(){this.getTime = function(){return 1234;}};
JSON.stringify = function(obj){
return 'data';
};
sessions.encrypt = function(secret, str){
// lets make this too long!
var r = '';
for(var i=0; i<4089; i++){
r = r + 'x';
};
return r;
};
sessions.hmac_signature = function(secret, timestamp, data_str){
return 'hmac';
};
try {
var r = sessions.serialize('secret', {test:'test'});
}
catch(e){
test.ok(
true, 'serializing a cookie over 4096 chars throws an exception'
);
}
// restore copied functions:
sessions.encrypt = encrypt;
sessions.hmac_signature = hmac_signature;
JSON.stringify = stringify;
global.Date = Date_copy;
test.done();
};
exports['readCookies'] = function(test){
var req = {headers: {cookie: "name1=data1; test=\"abcXYZ%20123\""}};
var r = sessions.readCookies(req);
test.same(r, {name1: 'data1', test: '"abcXYZ 123"'}, 'test header read ok');
test.done();
};
exports['readCookies alternate format'] = function(test){
var req = {headers: {cookie: "name1=data1;test=\"abcXYZ%20123\""}};
var r = sessions.readCookies(req);
test.same(r, {name1: 'data1', test: '"abcXYZ 123"'}, 'test header read ok');
test.done();
};
exports['readCookies no cookie in headers'] = function(test){
var req = {headers: {}};
var r = sessions.readCookies(req);
test.same(r, {}, 'returns empty object');
test.done();
};
exports['readCookies from Connect cookieDecoder'] = function(test){
var req = {headers: {}, cookies: {'test':'cookie'}};
test.same(sessions.readCookies(req), {'test': 'cookie'});
test.done();
};
exports['readSession'] = function(test){
test.expect(5);
var readCookies = sessions.readCookies;
var deserialize = sessions.deserialize;
sessions.readCookies = function(r){
test.equals(r, 'request_obj', 'readCookies called with request object');
return {'node_session': 'cookie_data'};
};
sessions.deserialize = function(secret, timeout, str){
test.equals(secret, 'secret', 'readCookies called with secret');
test.equals(timeout, 12, 'readCookies called with timeout');
test.equals(str, 'cookie_data', 'readCookies called with cookie data');
return {test: 'test'};
};
var r = sessions.readSession(
'node_session', 'secret', 12, 'request_obj'
);
test.same(r, {test: 'test'}, 'session with key node_session read ok');
// restore copied functions
sessions.readCookies = readCookies;
sessions.deserialize = deserialize;
test.done();
};
exports['readSession no cookie'] = function(test){
test.expect(2);
var readCookies = sessions.readCookies;
var deserialize = sessions.deserialize;
sessions.readCookies = function(r){
test.equals(r, 'request_obj', 'readCookies called with request object');
return {};
};
sessions.deserialize = function(secret, timeout, str){
test.ok(false, 'should not call deserialize');
};
var r = sessions.readSession(
'node_session', 'secret', 12, 'request_obj'
);
test.same(r, undefined, 'return empty session');
// restore copied functions
sessions.readCookies = readCookies;
sessions.deserialize = deserialize;
test.done();
};
exports['onRequest'] = function(test){
test.expect(5);
var readSession = sessions.readSession;
var s = {
session_key:'_node',
secret: 'secret',
timeout: 86400
};
var req = {};
sessions.readSession = function(key, secret, timeout, req){
test.equals(key, '_node', 'readSession called with session key');
test.equals(secret, 'secret', 'readSession called with secret');
test.equals(timeout, 86400, 'readSession called with timeout');
return 'testsession';
};
var next = function(){
test.ok(true, 'chain.next called');
test.equals(
req.session, 'testsession', 'req.session equals session data'
);
};
sessions(s)(req, 'res', next);
// restore copied functions
sessions.readSession = readSession;
test.done();
};
exports['writeHead'] = function(test){
test.expect(6);
var s = {
session_key:'_node',
secret: 'secret',
timeout: 86400
};
var req = {headers: {cookie: "_node="}};
var res = {
writeHead: function(code, headers){
test.equals(
headers['Set-Cookie'],
'_node=serialized_session; ' +
'expires=expiry_date; ' +
'path=/'
);
test.equals(headers['original'], 'header');
}
};
var serialize = sessions.serialize;
sessions.serialize = function(secret, data){
test.equals(secret, 'secret', 'serialize called with secret');
test.same(data, {test:'test'}, 'serialize called with session data');
return 'serialized_session';
};
var expires = sessions.expires;
sessions.expires = function(timeout){
test.equals(timeout, s.timeout);
return 'expiry_date';
};
var next = function(){
test.ok(true, 'chain.next called');
req.session = {test:'test'};
res.writeHead(200, {'original':'header'});
// restore copied functions
sessions.serialize = serialize;
sessions.expires = expires;
test.done();
};
sessions(s)(req, res, next);
};
exports['writeHead doesnt write cookie if none exists and session is undefined'] = function(test){
test.expect(3);
var s = {
session_key:'_node',
secret: 'secret',
timeout: 86400
};
var req = {headers: {}};
var res = {
writeHead: function(code, headers){
test.ok(!("Set-Cookie" in headers));
test.equals(headers['original'], 'header');
}
};
var next = function(){
test.ok(true, 'chain.next called');
req.session = undefined;
res.writeHead(200, {'original':'header'});
test.done();
};
sessions(s)(req, res, next);
};
exports['writeHead writes empty cookie with immediate expiration if session is undefined'] = function(test){
test.expect(4);
var s = {
session_key:'_node',
secret: 'secret',
timeout: 86400
};
var req = {headers: {cookie: "_node=Blah"}};
var res = {
writeHead: function(code, headers){
test.equals(
headers['Set-Cookie'],
'_node=; ' +
'expires=now; ' +
'path=/'
);
test.equals(headers['original'], 'header');
}
};
var expires = sessions.expires;
sessions.expires = function(timeout){
test.equals(timeout, 0);
return 'now';
};
var readSession = sessions.readSession;
sessions.readSession = function(key, secret, timeout, req) {
return {"username": "Bob"};
};
var next = function(){
test.ok(true, 'chain.next called');
req.session = undefined;
res.writeHead(200, {'original':'header'});
// restore copied functions
sessions.expires = expires;
sessions.readSession = readSession;
test.done();
};
sessions(s)(req, res, next);
};
exports['onInit secret set'] = function(test){
test.expect(0);
var s = {secret: 'secret'};
try {
sessions({secret: 'secret'});
}
catch(e){
test.ok(false, 'do nothing if secret set in server settings');
}
test.done();
};
exports['onInit no secret set'] = function(test){
test.expect(1);
try {
sessions({});
}
catch(e){
test.ok(true, 'throw exception if no secret set in server settings');
}
test.done();
};
exports['set multiple cookies'] = function(test){
test.expect(3);
var _serialize = sessions.serialize;
sessions.serialize = function(){
return 'session_data';
};
var _expires = sessions.expires;
sessions.expires = function(timeout){
test.equals(timeout, 12345);
return 'expiry_date';
};
var req = {headers: {cookie:''}};
var res = {writeHead: function(statusCode, headers){
test.equals(statusCode, 200);
test.same(headers, [
['other_header', 'val'],
['Set-Cookie', 'testcookie=testvalue'],
['Set-Cookie', '_node=session_data; ' +
'expires=expiry_date; ' +
'path=/']
]);
sessions.serialize = _serialize;
sessions.expires = _expires;
test.done();
}};
sessions({secret: 'secret', timeout: 12345})(req, res, function(){
req.session = {test: 'test'};
res.writeHead(200, {
'other_header': 'val',
'Set-Cookie':'testcookie=testvalue'
});
});
};
exports['set single cookie'] = function(test){
test.expect(3);
var _serialize = sessions.serialize;
sessions.serialize = function(){
return 'session_data';
};
var _expires = sessions.expires;
sessions.expires = function(timeout){
test.equals(timeout, 12345);
return 'expiry_date';
};
var req = {headers: {cookie:''}};
var res = {writeHead: function(statusCode, headers){
test.equals(statusCode, 200);
test.same(headers, {
'other_header': 'val',
'Set-Cookie': '_node=session_data; ' +
'expires=expiry_date; ' +
'path=/'
});
sessions.serialize = _serialize;
sessions.expires = _expires;
test.done();
}};
sessions({secret: 'secret', timeout: 12345})(req, res, function(){
req.session = {test: 'test'};
res.writeHead(200, {'other_header': 'val'});
});
};
exports['handle headers as array'] = function(test){
test.expect(3);
var _serialize = sessions.serialize;
sessions.serialize = function(){
return 'session_data';
};
var _expires = sessions.expires;
sessions.expires = function(timeout){
test.equals(timeout, 12345);
return 'expiry_date';
};
var req = {headers: {cookie:''}};
var res = {writeHead: function(statusCode, headers){
test.equals(statusCode, 200);
test.same(headers, [
['header1', 'val1'],
['header2', 'val2'],
['Set-Cookie', '_node=session_data; ' +
'expires=expiry_date; ' +
'path=/']
]);
sessions.serialize = _serialize;
test.done();
}};
sessions({secret: 'secret', timeout: 12345})(req, res, function(){
req.session = {test: 'test'};
res.writeHead(200, [['header1', 'val1'],['header2', 'val2']]);
});
};
exports['convert headers to array'] = function(test){
test.same(
sessions.headersToArray({'key1':'val1','key2':'val2'}),
[['key1','val1'],['key2','val2']]
);
test.same(
sessions.headersToArray([['key1','val1'],['key2','val2']]),
[['key1','val1'],['key2','val2']]
);
test.done();
};
exports['send cookies even if there are no headers'] = function (test) {
test.expect(2);
var req = {headers: {cookie:''}};
var res = {
writeHead: function (code, headers) {
test.equal(code, 200);
test.ok(headers['Set-Cookie']);
test.done();
}
};
sessions({secret: 'secret', timeout: 12345})(req, res, function () {
req.session = {test: 'test'};
res.writeHead(200);
});
};
exports['send cookies when no headers but reason_phrase'] = function (test) {
test.expect(3);
var req = {headers: {cookie:''}};
var res = {
writeHead: function (code, reason_phrase, headers) {
test.equal(code, 200);
test.equal(reason_phrase, 'reason');
test.ok(headers['Set-Cookie']);
test.done();
}
};
sessions({secret: 'secret', timeout: 12345})(req, res, function () {
req.session = {test: 'test'};
res.writeHead(200, 'reason');
});
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment