mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
Merge branch 'auth'
This commit is contained in:
commit
435ff1beeb
4 changed files with 2 additions and 202 deletions
|
@ -163,7 +163,6 @@ Auth.prototype.middleware = function() {
|
|||
var user = credentials.slice(0, index)
|
||||
, pass = credentials.slice(index + 1)
|
||||
|
||||
debugger
|
||||
self.authenticate(user, pass, function(err, groups) {
|
||||
if (!err && groups != null && groups != false) {
|
||||
req.remote_user = AuthenticatedUser(user, groups)
|
||||
|
|
141
lib/htpasswd.js
141
lib/htpasswd.js
|
@ -1,141 +0,0 @@
|
|||
var fs = require('fs')
|
||||
, crypto = require('crypto')
|
||||
, fs_storage = require('./local-fs')
|
||||
, UError = require('./error').UserError
|
||||
|
||||
try {
|
||||
// optional, won't be available on windows
|
||||
var crypt3 = require('crypt3')
|
||||
} catch(err) {
|
||||
crypt3 = function() {
|
||||
return NaN
|
||||
}
|
||||
}
|
||||
|
||||
function parse_htpasswd(input) {
|
||||
var result = {}
|
||||
input.split('\n').forEach(function(line) {
|
||||
var args = line.split(':', 3)
|
||||
if (args.length > 1) result[args[0]] = args[1]
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
function verify_password(user, passwd, hash) {
|
||||
if (hash.indexOf('{PLAIN}') === 0) {
|
||||
return passwd === hash.substr(7)
|
||||
} else if (hash.indexOf('{SHA}') === 0) {
|
||||
return crypto.createHash('sha1').update(passwd, 'binary').digest('base64') === hash.substr(5)
|
||||
} else {
|
||||
return crypt3(passwd, hash) === hash
|
||||
}
|
||||
}
|
||||
|
||||
function add_user_to_htpasswd(body, user, passwd) {
|
||||
if (user != encodeURIComponent(user)) {
|
||||
throw new UError({
|
||||
status: 409,
|
||||
message: "username shouldn't contain non-uri-safe characters",
|
||||
})
|
||||
}
|
||||
|
||||
passwd = crypt3(passwd)
|
||||
if (!passwd) {
|
||||
passwd = '{SHA}' + crypto.createHash('sha1').update(passwd, 'binary').digest('base64')
|
||||
}
|
||||
var comment = 'autocreated ' + (new Date()).toJSON()
|
||||
|
||||
var newline = user + ':' + passwd + ':' + comment + '\n'
|
||||
if (body.length && body[body.length-1] != '\n') newline = '\n' + newline
|
||||
return body + newline
|
||||
}
|
||||
|
||||
module.exports = function(path) {
|
||||
var result = {}
|
||||
var users = {}
|
||||
var last_time
|
||||
|
||||
// hopefully race-condition-free way to add users:
|
||||
// 1. lock file for writing (other processes can still read)
|
||||
// 2. reload .htpasswd
|
||||
// 3. write new data into .htpasswd.tmp
|
||||
// 4. move .htpasswd.tmp to .htpasswd
|
||||
// 5. reload .htpasswd
|
||||
// 6. unlock file
|
||||
result.add_user = function(user, passwd, maxusers, real_cb) {
|
||||
function sanity_check() {
|
||||
if (users[user]) {
|
||||
return new UError({
|
||||
status: 403,
|
||||
message: 'this user already exists',
|
||||
})
|
||||
} else if (Object.keys(users).length >= maxusers) {
|
||||
return new UError({
|
||||
status: 403,
|
||||
message: 'maximum amount of users reached',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// preliminary checks, just to ensure that file won't be reloaded if it's not needed
|
||||
var s_err = sanity_check()
|
||||
if (s_err) return real_cb(s_err)
|
||||
|
||||
fs_storage.lock_and_read(path, function(err, fd, res) {
|
||||
// callback that cleanups fd first
|
||||
function cb(err) {
|
||||
if (!fd) return real_cb(err)
|
||||
fs.close(fd, function() {
|
||||
real_cb(err)
|
||||
})
|
||||
}
|
||||
|
||||
// ignore ENOENT errors, we'll just create .htpasswd in that case
|
||||
if (err && err.code != 'ENOENT') return cb(err)
|
||||
|
||||
var body = (res || '').toString('utf8')
|
||||
users = parse_htpasswd(body)
|
||||
|
||||
// real checks, to prevent race conditions
|
||||
var s_err = sanity_check()
|
||||
if (s_err) return cb(s_err)
|
||||
|
||||
try {
|
||||
body = add_user_to_htpasswd(body, user, passwd)
|
||||
} catch(err) {
|
||||
return cb(err)
|
||||
}
|
||||
fs_storage.write(path, body, function(err) {
|
||||
if (err) return cb(err)
|
||||
result.reload(cb)
|
||||
})
|
||||
})
|
||||
}
|
||||
result.verify = function(user, passwd) {
|
||||
if (!users[user]) return false
|
||||
return verify_password(user, passwd, users[user])
|
||||
}
|
||||
result.reload = function(callback) {
|
||||
fs.open(path, 'r', function(err, fd) {
|
||||
if (err) return callback(err)
|
||||
fs.fstat(fd, function(err, st) {
|
||||
if (err) return callback(err)
|
||||
if (last_time === st.mtime) return callback()
|
||||
|
||||
var buffer = new Buffer(st.size)
|
||||
fs.read(fd, buffer, 0, st.size, null, function(err, bytesRead, buffer) {
|
||||
if (err) return callback(err)
|
||||
if (bytesRead != st.size) return callback(new Error('st.size != bytesRead'))
|
||||
users = parse_htpasswd(buffer.toString('utf8'))
|
||||
callback()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// exports for unit tests
|
||||
module.exports._parse_htpasswd = parse_htpasswd
|
||||
module.exports._verify_password = verify_password
|
||||
module.exports._add_user_to_htpasswd = add_user_to_htpasswd
|
|
@ -46,6 +46,7 @@ dependencies:
|
|||
onscroll: '>=0.0.3 <1.0.0-0'
|
||||
transition-complete: '>=0.0.2 <1.0.0-0'
|
||||
helpers.less: 'git://github.com/bpeacock/helpers.less.git'
|
||||
sinopia-htpasswd: '>= 0.2.0'
|
||||
|
||||
# TODO: not really needed
|
||||
tar.gz: '~0.1.1'
|
||||
|
@ -55,9 +56,6 @@ optionalDependencies:
|
|||
# and unavailable on windows
|
||||
fs-ext: '>=0.3.2 <1.0.0-0'
|
||||
|
||||
# bundled
|
||||
crypt3: '>=0.1.5 <1.0.0-0'
|
||||
|
||||
# Policy for now:
|
||||
# - small, unstable and rarely updated libraries (i.e. crypt3) get bundled
|
||||
# - big, stable and frequently updated libraries (i.e. request) don't
|
||||
|
@ -72,7 +70,7 @@ bundledDependencies:
|
|||
- transition-complete
|
||||
- helpers.less
|
||||
- tar.gz
|
||||
- crypt3
|
||||
- sinopia-htpasswd
|
||||
|
||||
devDependencies:
|
||||
rimraf: '>=2.2.5 <3.0.0-0'
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
var assert = require('assert')
|
||||
, parse_htpasswd = require('../../lib/htpasswd')._parse_htpasswd
|
||||
, verify_password = require('../../lib/htpasswd')._verify_password
|
||||
, add_user_to_htpasswd = require('../../lib/htpasswd')._add_user_to_htpasswd
|
||||
|
||||
describe('parse_htpasswd', function() {
|
||||
// TODO
|
||||
})
|
||||
|
||||
describe('verify_password', function() {
|
||||
it('should verify plain', function() {
|
||||
assert(verify_password('user', 'pass', '{PLAIN}pass'))
|
||||
assert(!verify_password('user', 'p', '{PLAIN}pass'))
|
||||
})
|
||||
it('should verify sha', function() {
|
||||
assert(verify_password('user', 'pass', '{SHA}nU4eI71bcnBGqeO0t9tXvY1u5oQ='))
|
||||
assert(!verify_password('user', 'p', '{SHA}nU4eI71bcnBGqeO0t9tXvY1u5oQ='))
|
||||
})
|
||||
it('should verify crypt', function() {
|
||||
assert(verify_password('user', 'pass', 'ulINxGnqObi36'))
|
||||
assert(!verify_password('user', 'p', 'ulINxGnqObi36'))
|
||||
})
|
||||
it('should verify crypt-sha', function() {
|
||||
assert(verify_password('user', 'pass', '$6$Qx0eNSKPbxocgA==$ugjO0.z9yOFiaJXJK4ulvGYIxF/KZBV4lGqasArYPqPPT4orZ6NlnIE5KhtiOVs.5EoWxLg1sjp318G8RpI2x1'))
|
||||
assert(!verify_password('user', 'p', '$6$Qx0eNSKPbxocgA==$ugjO0.z9yOFiaJXJK4ulvGYIxF/KZBV4lGqasArYPqPPT4orZ6NlnIE5KhtiOVs.5EoWxLg1sjp318G8RpI2x1'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('add_user_to_htpasswd', function() {
|
||||
it('should add user to empty file', function() {
|
||||
var res = add_user_to_htpasswd('', 'user', 'passwd')
|
||||
assert(res.match(/^user:[^:\n]+:autocreated [^\n]+\n$/))
|
||||
})
|
||||
|
||||
it('should append user / newline checks', function() {
|
||||
var res = add_user_to_htpasswd('testtest', 'user', 'passwd')
|
||||
assert(res.match(/^testtest\nuser:[^:\n]+:autocreated [^\n]+\n$/))
|
||||
var res = add_user_to_htpasswd('testtest\n', 'user', 'passwd')
|
||||
assert(res.match(/^testtest\nuser:[^:\n]+:autocreated [^\n]+\n$/))
|
||||
var res = add_user_to_htpasswd('testtest\n\n', 'user', 'passwd')
|
||||
assert(res.match(/^testtest\n\nuser:[^:\n]+:autocreated [^\n]+\n$/))
|
||||
})
|
||||
|
||||
it('should not append invalid users', function() {
|
||||
assert.throws(function() {
|
||||
add_user_to_htpasswd('', 'us:er', 'passwd')
|
||||
}, /non-uri-safe/)
|
||||
assert.throws(function() {
|
||||
add_user_to_htpasswd('', 'us\ner', 'passwd')
|
||||
}, /non-uri-safe/)
|
||||
assert.throws(function() {
|
||||
add_user_to_htpasswd('', 'us#er', 'passwd')
|
||||
}, /non-uri-safe/)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in a new issue