Skip to content

Commit

Permalink
add user registration
Browse files Browse the repository at this point in the history
  • Loading branch information
rlidwka committed Jul 21, 2014
1 parent 9a14a6e commit ff8a5e9
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 7 deletions.
16 changes: 16 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var assert = require('assert')
, crypto = require('crypto')
, Path = require('path')
, minimatch = require('minimatch')
, UError = require('./error').UserError
, utils = require('./utils')

// [[a, [b, c]], d] -> [a, b, c, d]
Expand Down Expand Up @@ -168,6 +169,21 @@ Config.prototype.authenticate = function(user, password, cb) {
}.bind(this))
}

Config.prototype.add_user = function(user, password, cb) {
if (this.HTPasswd) {
if (this.max_users || this.max_users == null) {
var max_users = Number(this.max_users || Infinity)
this.HTPasswd.add_user(user, password, max_users, cb)
return
}
}

return cb(new UError({
status: 409,
message: 'registration is disabled',
}))
}

module.exports = Config

var parse_interval_table = {
Expand Down
78 changes: 75 additions & 3 deletions lib/htpasswd.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,85 @@ function verify_password(user, passwd, 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
result.add_user = function(user, passwd, cb) {
// TODO

// 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: 409,
message: 'this user already exists',
})
} else if (Object.keys(users).length >= maxusers) {
return new UError({
status: 409,
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
Expand All @@ -45,7 +118,6 @@ module.exports = function(path) {
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()
Expand Down
25 changes: 21 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,27 @@ module.exports = function(config_hash) {
})

app.put('/-/user/:org_couchdb_user', function(req, res, next) {
res.status(409)
return res.send({
error: 'registration is not implemented',
})
if (req.remoteUser != null) {
res.status(200)
return res.send({
ok: 'you are authenticated as "' + req.remoteUser + '"',
})
} else {
if (typeof(req.body.name) !== 'string' || typeof(req.body.password) !== 'string') {

This comment has been minimized.

Copy link
@yms9654

yms9654 Jul 29, 2014

client side code:
npm adduser
Username: admin
Password: 1234qwer
Email: [email protected]

print a log:
console.log(req.body.password, typeof(req.body.password)); => undefined, undefined

node version: 0.10.24
npm version: 1.3.21

Thank you for your code.
Please check this error.

This comment has been minimized.

Copy link
@rlidwka

rlidwka Jul 31, 2014

Author Owner

Thanks for the report, I opened an issue about it: #93 , not sure if it could be fixed though.

In the meantime you can upgrade to npm 1.4.x, those versions should work.

res.status(409)
return res.send({
ok: 'user/password is not found in request (npm issue?)',
})
}
config.add_user(req.body.name, req.body.password, function(err) {
if (err) return next(err)

res.status(201)
return res.send({
ok: 'user "' + req.remoteUser + '" created',
})
})
}
})

app.put('/-/user/:org_couchdb_user/-rev/*', function(req, res, next) {
Expand Down

0 comments on commit ff8a5e9

Please sign in to comment.