couch-login
Advanced tools
Comparing version 0.1.20 to 1.0.0
@@ -55,3 +55,3 @@ var request = require('request') | ||
// replace these with client certificate and private key if required by | ||
// the server. Only relevant for HTTPS couches. These are passed to | ||
// the server. Only relevant for HTTPS couches. These are passed to | ||
// the request and then on to https and tls as-is. | ||
@@ -101,7 +101,7 @@ this.cert = null | ||
this.tokenSet = function (tok, cb) { | ||
session.set('couch_token', tok, cb || function () {}) | ||
session.set('couch_token', tok, cb) | ||
} | ||
this.tokenDel = function (cb) { | ||
session.del('couch_token', cb || function () {}) | ||
session.del('couch_token', cb) | ||
} | ||
@@ -164,3 +164,3 @@ } | ||
req.ca = this.ca | ||
if (this.cert) | ||
@@ -177,4 +177,3 @@ req.cert = this.cert | ||
if (er || res.statusCode !== 200) return cb(er, res, data) | ||
addToken.call(this, res) | ||
return cb.call(this, er, res, data) | ||
return addToken.call(this, res, data, cb) | ||
}.bind(this)) | ||
@@ -216,2 +215,3 @@ }} | ||
&& k !== 'password_sha' | ||
&& k !== 'derived_key' | ||
&& k !== 'salt' | ||
@@ -224,7 +224,11 @@ }).forEach(function (k) { | ||
, newPass = auth.password | ||
, newSha = sha(newPass + newSalt) | ||
, iterations = 10 | ||
, newKey = pbkdf2(newPass, newSalt, iterations) | ||
data.password_sha = newSha | ||
data.derived_key = newKey | ||
data.salt = newSalt | ||
data.password_scheme = 'pbkdf2' | ||
data.iterations = 10 | ||
data.date = new Date().toISOString() | ||
delete data.password_sha // delete password_sha, since we're doing pbkdf2 now | ||
@@ -285,3 +289,4 @@ this.put(u + '?rev=' + data._rev, data, function (er, res, data) { | ||
var newSalt = crypto.randomBytes(30).toString('hex') | ||
, newSha = sha(auth.password + newSalt) | ||
, iterations = 10 | ||
, newKey = pbkdf2(auth.password, newSalt, iterations) | ||
, user = { _id: 'org.couchdb.user:' + auth.name | ||
@@ -291,4 +296,6 @@ , name: auth.name | ||
, type: 'user' | ||
, password_sha: newSha | ||
, password_scheme: 'pbkdf2' | ||
, derived_key: newKey | ||
, salt: newSalt | ||
, iterations: iterations | ||
, date: new Date().toISOString() } | ||
@@ -317,11 +324,12 @@ | ||
function addToken (res) { | ||
function addToken (res, data, cb) { | ||
assert(this instanceof CouchLogin) | ||
// not doing the whole login session cookie thing. | ||
if (this.token === BASIC) | ||
return | ||
return process.nextTick(cb.bind(null, null, res, data)) | ||
// attach the token, if a new one was provided. | ||
var sc = res.headers['set-cookie'] | ||
if (!sc) return | ||
if (!sc) | ||
return process.nextTick(cb.bind(null, null, res, data)) | ||
if (!Array.isArray(sc)) sc = [sc] | ||
@@ -333,3 +341,4 @@ | ||
if (!sc.length) return | ||
if (!sc.length) | ||
return process.nextTick(cb.bind(null, null, res, data)) | ||
@@ -363,3 +372,8 @@ sc = sc.split(/\s*;\s*/).map(function (p) { | ||
this.token = sc | ||
if (this.tokenSet) this.tokenSet(this.token) | ||
if (this.tokenSet) | ||
this.tokenSet(this.token, function(er) { | ||
cb(er, res, data) | ||
}) | ||
else | ||
process.nextTick(cb.bind(null, null, res, data)) | ||
} | ||
@@ -408,4 +422,4 @@ | ||
function sha (s) { | ||
return crypto.createHash("sha1").update(s).digest("hex") | ||
function pbkdf2 (pass, salt, iterations) { | ||
return crypto.pbkdf2Sync(pass, salt, iterations, 20).toString('hex') | ||
} |
@@ -5,3 +5,3 @@ { | ||
"description": "A module for doing logged-in requests to a couchdb server", | ||
"version": "0.1.20", | ||
"version": "1.0.0", | ||
"repository": { | ||
@@ -8,0 +8,0 @@ "type": "git", |
@@ -134,3 +134,3 @@ # couch-login | ||
Takes a callback which should be called when the token is saved. | ||
Takes a callback which MUST be called when the token is saved. | ||
@@ -149,3 +149,3 @@ ### couch.tokenGet | ||
Related to tokenGet and tokenSet. Takes a callback which should be | ||
Related to tokenGet and tokenSet. Takes a callback which MUST be | ||
called when the token is deleted. | ||
@@ -152,0 +152,0 @@ |
@@ -88,2 +88,49 @@ // start the couchdb spinning as a detached child process. | ||
type: 'user', | ||
password_scheme: 'pbkdf2', | ||
derived_key: '091d26cd3a47164ff327314e267fe3c1fe425be1', | ||
salt: '9afd2ee9af3f6f2fd705bdab92d3b2c5d92835681ce26ba2e4c0318831d8', | ||
iterations: 10, | ||
date: '2014-04-03T18:41:45.174Z' | ||
}, | ||
json: true | ||
}, function (er, res, data) { | ||
if (er) | ||
throw er | ||
t.ok(data.ok, 'user created') | ||
t.end() | ||
}) | ||
} | ||
}) | ||
// create a sha user | ||
test('create testuser with sha', function (t) { | ||
var u = 'http://admin:admin@localhost:15985/_users/org.couchdb.user:testusersha' | ||
var rev | ||
request.get({ url: u, json: true }, function (er, res, data) { | ||
if (er) | ||
throw er | ||
rev = data._rev | ||
if (res.statusCode === 404) | ||
put() | ||
else | ||
del() | ||
}) | ||
function del () { | ||
request.del(u + '?rev=' + rev, function (er, res, data) { | ||
if (er) | ||
throw er | ||
put() | ||
}) | ||
} | ||
function put () { | ||
request.put({ | ||
url: u, | ||
body: { | ||
_id: 'org.couchdb.user:testusersha', | ||
name: 'testusersha', | ||
roles: [], | ||
type: 'user', | ||
password_sha: 'e23952b517695e6bb72ecf060e10bf1b35bf7e0b', | ||
@@ -90,0 +137,0 @@ salt: '83695c9b64d3b48b94c9dda0cd691e72', |
@@ -102,2 +102,5 @@ var tap = require('tap') | ||
} | ||
function pbkdf2 (pass, salt, iterations) { | ||
return crypto.pbkdf2Sync(pass, salt, iterations, 20).toString('hex') | ||
} | ||
@@ -108,6 +111,6 @@ tap.test('change password manually', function (t) { | ||
, newSalt = 'test-salt-two' | ||
, newSha = sha(newPass + newSalt) | ||
, newKey = pbkdf2(newPass, newSalt, parseInt(userRecord.iterations,10)) | ||
userRecord.salt = newSalt | ||
userRecord.password_sha = newSha | ||
userRecord.derived_key = newKey | ||
couch.put(revved, userRecord, function (er, res, data) { | ||
@@ -143,6 +146,6 @@ t.ifError(er) | ||
, newSalt = 'test-salt' | ||
, newSha = sha(newPass + newSalt) | ||
, newKey = pbkdf2(newPass, newSalt, parseInt(userRecord.iterations,10)) | ||
userRecord.salt = newSalt | ||
userRecord.password_sha = newSha | ||
userRecord.derived_key = newKey | ||
couch.put(revved, userRecord, function (er, res, data) { | ||
@@ -275,4 +278,7 @@ t.ifError(er) | ||
t.ok(data.date, 'date') | ||
t.ok(data.password_sha, 'hash') | ||
t.notOk(data.password_sha, 'sha_hash') | ||
t.ok(data.derived_key, 'derived_key') | ||
t.ok(data.password_scheme, 'password_scheme') | ||
t.ok(data.salt, 'salt') | ||
t.ok(data.iterations, 'iterations') | ||
t.ok(couch.token, 'token') | ||
@@ -303,1 +309,57 @@ // now delete account | ||
}) | ||
var shaAuth = { name: 'testusersha', password: 'test', mustChangePass: true } | ||
, shaU = '/_users/org.couchdb.user:' + shaAuth.name | ||
tap.test('sha user login', function (t) { | ||
couch.login(shaAuth, function (er, res, data) { | ||
t.ifError(er) | ||
if (er) return t.end() | ||
okStatus(t, res) | ||
t.deepEqual(data, { ok: true, name: 'testusersha', roles: [] }) | ||
t.ok(couch.token) | ||
t.deepEqual(couch.token, | ||
{ AuthSession: couch.token && couch.token.AuthSession, | ||
version: '1', | ||
expires: couch.token && couch.token.expires, | ||
path: '/', | ||
httponly: true }) | ||
t.ok(couch.token, 'has token') | ||
t.end() | ||
}) | ||
}) | ||
tap.test('switch user from sha to pbkdf2', function (t) { | ||
couch.changePass(shaAuth, function (er, res, data) { | ||
t.ifError(er) | ||
if (er) return t.end() | ||
okStatus(t, res) | ||
couch.get(shaU, function (er, res, data) { | ||
t.ifError(er) | ||
if (er) return t.end() | ||
okStatus(t, res) | ||
t.ok(data, 'data') | ||
t.has(data, | ||
{ _id: 'org.couchdb.user:testusersha', | ||
name: 'testusersha', | ||
roles: [], | ||
type: 'user' }) | ||
t.ok(data._rev, 'rev') | ||
t.ok(data.date, 'date') | ||
t.notOk(data.password_sha, 'sha_hash') | ||
t.ok(data.derived_key, 'derived_key') | ||
t.ok(data.password_scheme, 'password_scheme') | ||
t.ok(data.salt, 'salt') | ||
t.ok(data.iterations, 'iterations') | ||
t.ok(couch.token, 'token') | ||
t.equal(data.testingCouchLogin, undefined) | ||
t.equal(data.mustChangePass, true) | ||
userRecord = data | ||
t.end() | ||
}) | ||
}) | ||
}) | ||
@@ -104,2 +104,5 @@ // Should be able to use this module to log into the registry, as well. | ||
} | ||
function pbkdf2 (pass, salt, iterations) { | ||
return crypto.pbkdf2Sync(pass, salt, iterations, 20).toString('hex') | ||
} | ||
@@ -110,6 +113,6 @@ tap.test('change password manually', function (t) { | ||
, newSalt = 'test-salt-two' | ||
, newSha = sha(newPass + newSalt) | ||
, newKey = pbkdf2(newPass, newSalt, parseInt(userRecord.iterations,10)) | ||
userRecord.salt = newSalt | ||
userRecord.password_sha = newSha | ||
userRecord.derived_key = newKey | ||
couch.put(revved, userRecord, function (er, res, data) { | ||
@@ -145,6 +148,6 @@ t.ifError(er) | ||
, newSalt = 'test-salt' | ||
, newSha = sha(newPass + newSalt) | ||
, newKey = pbkdf2(newPass, newSalt, parseInt(userRecord.iterations,10)) | ||
userRecord.salt = newSalt | ||
userRecord.password_sha = newSha | ||
userRecord.derived_key = newKey | ||
couch.put(revved, userRecord, function (er, res, data) { | ||
@@ -242,4 +245,7 @@ t.ifError(er) | ||
t.ok(data.date, 'date') | ||
t.ok(data.password_sha, 'hash') | ||
t.notOk(data.password_sha, 'sha_hash') | ||
t.ok(data.derived_key, 'derived_key') | ||
t.ok(data.password_scheme, 'password_scheme') | ||
t.ok(data.salt, 'salt') | ||
t.ok(data.iterations, 'iterations') | ||
t.ok(couch.token, 'token') | ||
@@ -246,0 +252,0 @@ // now delete account |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
75150
1150
0