🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

connect-memcached

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

connect-memcached - npm Package Compare versions

Comparing version

to
0.2.0

tests/test_encrypt.js

276

lib/connect-memcached.js

@@ -9,5 +9,5 @@ /*!

function ensureCallback(fn) {
return function() {
fn && fn.apply(null, arguments);
};
return function() {
fn && fn.apply(null, arguments);
};
}

@@ -23,63 +23,137 @@

module.exports = function(session) {
var Store = session.Store;
var Store = session.Store;
/**
* Initialize MemcachedStore with the given `options`.
*
* @param {Object} options
* @api public
*/
function MemcachedStore(options) {
options = options || {};
Store.call(this, options);
/**
* Initialize MemcachedStore with the given `options`.
*
* @param {Object} options
* @api public
*/
function MemcachedStore(options) {
options = options || {};
Store.call(this, options);
this.prefix = options.prefix || '';
if (!options.client) {
if (!options.hosts) {
options.hosts = '127.0.0.1:11211';
}
this.prefix = options.prefix || '';
this.ttl = options.ttl;
if (!options.client) {
if (!options.hosts) {
options.hosts = '127.0.0.1:11211';
}
if (options.secret) {
this.crypto = require('crypto'),
this.secret = options.secret;
}
if (options.algorithm) {
this.algorithm = options.algorithm;
}
options.client = new Memcached(options.hosts, options);
}
options.client = new Memcached(options.hosts, options);
}
this.client = options.client;
}
this.client = options.client;
}
MemcachedStore.prototype.__proto__ = Store.prototype;
MemcachedStore.prototype.__proto__ = Store.prototype;
/**
* Translates the given `sid` into a memcached key, optionally with prefix.
*
* @param {String} sid
* @api private
*/
MemcachedStore.prototype.getKey = function getKey(sid) {
return this.prefix + sid;
};
/**
* Translates the given `sid` into a memcached key, optionally with prefix.
*
* @param {String} sid
* @api private
*/
MemcachedStore.prototype.getKey = function getKey(sid) {
return this.prefix + sid;
};
/**
* Attempt to fetch session by the given `sid`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.get = function(sid, fn) {
sid = this.getKey(sid);
/**
* Attempt to fetch session by the given `sid`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.get = function(sid, fn) {
secret = this.secret, self = this, sid = this.getKey(sid);
this.client.get(sid, function(err, data) {
if (err) { return fn(err, {}); }
try {
if (!data) {
return fn();
}
fn(null, JSON.parse(data.toString()));
} catch (e) {
fn(e);
}
});
};
this.client.get(sid, function(err, data) {
if (err) {
return fn(err, {});
}
try {
if (!data) {
return fn();
}
if (secret) {
parseable_string = decryptData.call(self, data.toString());
}
else {
parseable_string = data.toString();
}
fn(null, JSON.parse(parseable_string));
} catch (e) {
fn(e);
}
});
};
/**
* Commit the given `sess` object associated with the given `sid`.
*
* @param {String} sid
* @param {Session} sess
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.set = function(sid, sess, fn) {
sid = this.getKey(sid);
try {
var maxAge = sess.cookie.maxAge;
var ttl = this.ttl || ('number' == typeof maxAge ? maxAge / 1000 | 0 : oneDay);
var sess = JSON.stringify((this.secret) ?
encryptData.call(this, JSON.stringify(sess),
this.secret, this.algorithm) :
sess);
this.client.set(sid, sess, ttl, ensureCallback(fn));
} catch (err) {
fn && fn(err);
}
};
/**
* Destroy the session associated with the given `sid`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.destroy = function(sid, fn) {
sid = this.getKey(sid);
this.client.del(sid, ensureCallback(fn));
};
/**
* Fetch number of sessions.
*
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.length = function(fn) {
this.client.items(ensureCallback(fn));
};
/**
* Clear all sessions.
*
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.clear = function(fn) {
this.client.flush(ensureCallback(fn));
};
/**
* Commit the given `sess` object associated with the given `sid`.
* Refresh the time-to-live for the session with the given `sid`.
*

@@ -90,50 +164,60 @@ * @param {String} sid

* @api public
*/
MemcachedStore.prototype.set = function(sid, sess, fn) {
sid = this.getKey(sid);
*/
try {
var maxAge = sess.cookie.maxAge;
var ttl = 'number' == typeof maxAge ? maxAge / 1000 | 0 : oneDay;
var sess = JSON.stringify(sess);
MemcachedStore.prototype.touch = function (sid, sess, fn) {
this.set(sid, sess, fn);
}
this.client.set(sid, sess, ttl, ensureCallback(fn));
} catch (err) {
fn && fn(err);
}
};
/**
* Destroy the session associated with the given `sid`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.destroy = function(sid, fn) {
sid = this.getKey(sid);
this.client.del(sid, ensureCallback(fn));
};
function encryptData(plaintext){
var pt = encrypt.call(this, this.secret, plaintext, this.algo)
, hmac = digest.call(this, this.secret, pt);
/**
* Fetch number of sessions.
*
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.length = function(fn) {
this.client.items(ensureCallback(fn));
};
return {
ct: pt,
mac: hmac
};
}
/**
* Clear all sessions.
*
* @param {Function} fn
* @api public
*/
MemcachedStore.prototype.clear = function(fn) {
this.client.flush(ensureCallback(fn));
};
function decryptData(ciphertext){
ciphertext = JSON.parse(ciphertext)
var hmac = digest.call(this, this.secret, ciphertext.ct);
return MemcachedStore;
if (hmac != ciphertext.mac) {
throw 'Encrypted session was tampered with!';
}
return decrypt.call(this, this.secret, ciphertext.ct, this.algo);
}
function digest(key, obj) {
var hmac = this.crypto.createHmac('sha512', key);
hmac.setEncoding('hex');
hmac.write(obj);
hmac.end();
return hmac.read();
}
function encrypt(key, pt, algo) {
algo = algo || 'aes-256-ctr';
pt = (Buffer.isBuffer(pt)) ? pt : new Buffer(pt);
var cipher = this.crypto.createCipher(algo, key), ct = [];
ct.push(cipher.update(pt, 'buffer', 'hex'));
ct.push(cipher.final('hex'));
return ct.join('');
}
function decrypt(key, ct, algo) {
algo = algo || 'aes-256-ctr';
var cipher = this.crypto.createDecipher(algo, key), pt = [];
pt.push(cipher.update(ct, 'hex', 'utf8'));
pt.push(cipher.final('utf8'));
return pt.join('');
}
return MemcachedStore;
};
{
"name": "connect-memcached"
, "version": "0.1.0"
, "version": "0.2.0"
, "description": "Memcached session store for Connect"

@@ -11,3 +11,3 @@ , "keywords": ["memcached", "connection", "session", "store", "cache"]

}
, "dependencies": { "memcached": "0.2.x" }
, "dependencies": { "memcached": "2.2.x" }
, "engines": { "node": ">=0.4.7" }

@@ -14,0 +14,0 @@ , "license": "MIT"

@@ -28,3 +28,4 @@ # connect-memcached

, store : new MemcachedStore({
hosts: ['127.0.0.1:11211']
hosts: ['127.0.0.1:11211'],
secret: '123, easy as ABC. ABC, easy as 123' // Optionally use transparent encryption for memcache session data
})

@@ -48,4 +49,7 @@ }));

## Options
- `hosts` Memcached servers locations, can by string, array, hash.
- `hosts` Memcached servers locations, can be string, array, hash.
- `prefix` An optional prefix for each memcache key, in case you are sharing your memcached servers with something generating its own keys.
- `ttl` An optional parameter used for setting the default TTL
- `secret` An optional secret can be used to encrypt/decrypt session contents.
- `algorithm` An optional algorithm parameter may be used, but must be valid based on returned `crypto.getCiphers()`. The current default is `aes-256-ctr` and was chosen based on the following [information](http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html)
- ... Rest of given option will be passed directly to the node-memcached constructor.

@@ -52,0 +56,0 @@