mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-01-06 22:40:26 -05:00
121 lines
3 KiB
JavaScript
121 lines
3 KiB
JavaScript
var crypto = require('crypto')
|
|
var fs = require('fs')
|
|
|
|
try {
|
|
// optional, won't be available on windows
|
|
var crypt3 = require('crypt3')
|
|
} catch(err) {
|
|
}
|
|
|
|
try {
|
|
var fsExt = require('fs-ext')
|
|
} catch(e) {
|
|
fsExt = {
|
|
flock: function() {
|
|
arguments[arguments.length-1]()
|
|
}
|
|
}
|
|
}
|
|
|
|
// open and flock with exponential backoff
|
|
function open_flock(name, opmod, flmod, tries, backoff, cb) {
|
|
fs.open(name, opmod, function(err, fd) {
|
|
if (err) return cb(err, fd)
|
|
|
|
fsExt.flock(fd, flmod, function(err) {
|
|
if (err) {
|
|
if (!tries) {
|
|
fs.close(fd, function() {
|
|
cb(err)
|
|
})
|
|
} else {
|
|
fs.close(fd, function() {
|
|
setTimeout(function() {
|
|
open_flock(name, opmod, flmod, tries-1, backoff*2, cb)
|
|
}, backoff)
|
|
})
|
|
}
|
|
} else {
|
|
cb(null, fd)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// this function neither unlocks file nor closes it
|
|
// it'll have to be done manually later
|
|
function lock_and_read(name, _callback) {
|
|
open_flock(name, 'r', 'exnb', 4, 10, function(err, fd) {
|
|
function callback(err) {
|
|
if (err && fd) {
|
|
fs.close(fd, function(err2) {
|
|
_callback(err)
|
|
})
|
|
} else {
|
|
_callback.apply(null, arguments)
|
|
}
|
|
}
|
|
|
|
if (err) return callback(err, fd)
|
|
|
|
fs.fstat(fd, function(err, st) {
|
|
if (err) return callback(err, fd)
|
|
|
|
var buffer = new Buffer(st.size)
|
|
if (st.size === 0) return onRead(null, 0, buffer)
|
|
fs.read(fd, buffer, 0, st.size, null, onRead)
|
|
|
|
function onRead(err, bytesRead, buffer) {
|
|
if (err) return callback(err, fd)
|
|
if (bytesRead != st.size) return callback(new Error('st.size != bytesRead'), fd)
|
|
|
|
callback(null, fd, buffer)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
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 if (crypt3) {
|
|
return crypt3(passwd, hash) === hash
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
function add_user_to_htpasswd(body, user, passwd) {
|
|
if (user != encodeURIComponent(user)) {
|
|
var err = Error("username shouldn't contain non-uri-safe characters")
|
|
err.status = 409
|
|
throw err
|
|
}
|
|
|
|
if (crypt3) {
|
|
passwd = crypt3(passwd)
|
|
} else {
|
|
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.parse_htpasswd = parse_htpasswd
|
|
module.exports.verify_password = verify_password
|
|
module.exports.add_user_to_htpasswd = add_user_to_htpasswd
|
|
module.exports.lock_and_read = lock_and_read
|