UNPKG

session

Version:

Generic session manager (i.e. not depending on cookies or socket connection, etc.)

464 lines (410 loc) 8.62 kB
//TODO: add license /** * Imports */ var base = require('./storage/base'); var crypto = require('crypto'); /** * Constants */ SESSION_ID_MAX = 18446744073709551616;// 2<<64 SESSION_EXPIRATION = 60 * 60;// 1hours SESSION_CREATION_ATTEMPTS = 10000; /***************************************************************************************************************************************************** * Manager * * Usage : * * <code> * var manager = new Manager{ * storage :{ * type: SessionStorageMemory, //storage type * ... * }, * expiration: 100//time in seconds * secret: 'mySecretKey';//SID size * sessionCreationAttempts:10000 * }); * * //Request #1 * var session = manager.create(); * //send here session.getId() to the client * session.set('foo', 'bar').set('baz', 3); * session.save(); * * //Request #2 * var sid = ... //Get the sid from cookie, etc * var session = manager.open(sid); * console.log(session.get('foo'));//will print 'bar' * * </code> ****************************************************************************************************************************************************/ /** * Manager constructor * * @param options * @return */ function Manager(options) { options = options || {}; options.storage = options.storage || {}; this._expiration = (options.expiration || SESSION_EXPIRATION); this._secret = options.secret || ''; this._sessionCreationAttempts = options.sessionCreationAttempts || SESSION_CREATION_ATTEMPTS; // Generate storage this.setStorage(options.storage.type, options.storage); this.__defineGetter__('_currentTime', function() { return Math.floor((new Date()).getTime() / 1000); }); } Manager.prototype.getExpiration = function() { return this._expiration; }; /** * Set the storage used for all sessions * * @param type * @param options * @return this */ Manager.prototype.setStorage = function(type, options) { if (type == undefined) { type = require('./storage/memory').Storage; } if (typeof (type) == 'string') { type = require('./storage/' + type).Storage; } if (type instanceof Function) { type = new type(options); } if (typeof (type) == 'object') { type._manager = this; this._storage = type; return this; } throw new Error(); }; /** * Return the manager storage * * @return SessionStorage */ Manager.prototype.getStorage = function() { return this._storage; }; /** * Return a random generated SID * * @return string */ Manager.prototype.generateId = function() { var sessionKeyMax = SESSION_ID_MAX; var secretKey = this._secret; var seed = '' + (Math.random() * sessionKeyMax); seed += process.pid; seed += this._currentTime; seed += secretKey; var hash = crypto.createHash('md5').update(seed).digest('hex'); return hash; }; /** * Return true if Session with sid exists * * @param sid * @return boolean */ Manager.prototype.exist = function(sid) { return this._storage.exist(sid); }; /** * Return new Session object with new SID * * @return Session */ Manager.prototype.create = function() { for ( var tryCount = 0; tryCount < this._sessionCreationAttempts; tryCount++) { try { var sessionNew = new Session( { manager : this }); sessionNew.save(); break; } catch (e) { throw e; } } return sessionNew; }; /** * Return new Session object with * * @param sid * @return */ Manager.prototype.open = function(sid) { var sessionOpened = new Session( { manager : this, id : sid }); return sessionOpened; }; /** * Destroy * * @param session * @return */ Manager.prototype.destroy = function(session) { this._storage.destroy(session); return this; }; /** * Destroy all sessions * * @return */ Manager.prototype.flush = function() { this._storage.flush(); return this; }; /** * Destroy all expired sessions * * @return this */ Manager.prototype.clean = function() { this._storage.clean(); return this; }; /** * Session constructor * * @param options * @return */ function Session(options) { options = options || {}; this._manager = options.manager; this.id = options.id; this._data = options.data || {}; this.accessed = false; this.modified = false; this.__defineGetter__('_currentTime', function() { return this._manager._currentTime; }); // Created At this.__defineGetter__('createdAt', this.getCreatedAt); this.__defineSetter__('createdAt', this.setCreatedAt); this.createdAt = options.createdAt; // Accessed At this.__defineGetter__('accessedAt', this.getAccessedAt); this.__defineSetter__('accessedAt', this.setAccessedAt); this.accessedAt = options.accessedAt || options.createdAt; // Expired At this.__defineGetter__('expiredAt', this.getExpiredAt); this.__defineSetter__('expiredAt', this.setExpiredAt); this.expiredAt = options.expiredAt || Number.MAX_VALUE; } /** * Return the SID * * @return the id */ Session.prototype.getId = function() { return this.id; }; Session.prototype.getCreatedAt = function() { if (!this._createdAt) { this.read(); } return this._createdAt; }; Session.prototype.setCreatedAt = function(value) { this._createdAt = value; return this; }; Session.prototype.getAccessedAt = function() { if (!this._accessedAt) { this.read(); } return this._accessedAt; }; Session.prototype.setAccessedAt = function(value) { this._accessedAt = value; return this; }; Session.prototype.getExpiredAt = function() { if (!this._expiredAt) { this.read(); } return this._expiredAt; }; Session.prototype.setExpiredAt = function(value) { this._expiredAt = value; return this; }; /** * Return the session data * * @return an object {} */ Session.prototype._getData = function() { return this._data; }; /** * Set session data (overwrite it) * * @param data * @return this */ Session.prototype._setData = function(data) { this._data = data || {}; return this; }; /** * Return Array containing all keys * * @return Array */ Session.prototype.keys = function() { this.read(); var keys = []; for ( var key in this._data) { keys.push(key); } return keys; }; /** * Return Array containing all values * * @return Array */ Session.prototype.values = function() { this.read(); var values = []; for ( var key in this._data) { values.push(this._data[key]); } return values; }; /** * Return data[key] or defaultValue (and delete it) * * @param key * @param defaultValue * @return */ Session.prototype.pop = function(key, defaultValue) { this.read(); var value = this._data[key]; if (value != undefined) { this.modified = true; delete this._data[key]; return value; } else { return defaultValue; } }; /** * Return true if data[key] is set * * @param key * @return boolean */ Session.prototype.isset = function(key) { this.read(); return this._data[key] != undefined; }; /** * Return the data[key] value or defaultValue if not set * * @param key * @param defaultValue * @return mixed */ Session.prototype.get = function(key, defaultValue) { this.read(); var value = this._data[key]; return value == undefined ? defaultValue : value; }; /** * Set the data[key] to value * * @param key * @param value * @return this */ Session.prototype.set = function(key, value) { this.read(); if (typeof (key) == 'object') { for ( var property in key) { this._data[property] = key[property]; } } else { if (value != undefined) { this._data[key] = value; } else { delete this._data[key]; } } this.modified = true; return this; }; /** * Unset the data[key] * * @param key * @return this */ Session.prototype.unset = function(key) { this.pop(key); return this; }; /** * Read data from storage (can be done only once) * * @return this */ Session.prototype.read = function() { if (this.accessed == false) { this.accessed = true; if (this._manager && this._manager.getStorage()) { this._manager.getStorage().read(this); } } return this; }; /** * Save or create session into storage * * @return this */ Session.prototype.save = function() { if (this.id == undefined) { this._manager.getStorage().create(this); this.modified = false; } else { this._manager.getStorage().update(this); this.modified = false; } return this; }; /** * Destroy me * * TODO: check not to destroy twice? and block set/set, etc? * * @return */ Session.prototype.destroy = function() { if (this.id != undefined) { this._manager.getStorage().destroy(this); this.id = undefined; } return this; }; /** * Exports */ exports.Manager = Manager; exports.Session = Session;