2017-10-11 10:15:19 -04:00
|
|
|
var express = require('express');
|
|
|
|
var router = express.Router();
|
|
|
|
|
2017-10-11 12:55:46 -04:00
|
|
|
var User = require('../models/User.js');
|
|
|
|
var Invite = require('../models/Invite.js');
|
2017-10-11 10:15:19 -04:00
|
|
|
|
|
|
|
var passport = require('passport');
|
|
|
|
|
2018-01-15 15:29:32 -05:00
|
|
|
var async = require('async');
|
|
|
|
|
|
|
|
// Normalizes, decomposes, and lowercases a unicode string
|
|
|
|
function canonicalize(username) {
|
|
|
|
return username.normalize('NFKD').toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks if an invite code is valid
|
|
|
|
// Returns the invite object if valid
|
|
|
|
function checkInvite(code, cb) {
|
2017-10-14 17:49:11 -04:00
|
|
|
Invite.findOne({code: code}, function (err, invite) {
|
2018-01-15 15:29:32 -05:00
|
|
|
if (err)
|
|
|
|
cb(err);
|
|
|
|
else if (!invite)
|
|
|
|
cb('Invalid invite code.');
|
|
|
|
else if (invite.used)
|
|
|
|
cb('Invite already used.');
|
|
|
|
else if (invite.exp < Date.now())
|
|
|
|
cb('Invite expired.');
|
2017-10-12 12:50:02 -04:00
|
|
|
else
|
2018-01-15 15:29:32 -05:00
|
|
|
cb(null, invite);
|
2017-10-12 12:50:02 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-15 15:29:32 -05:00
|
|
|
// Validates the username, then registers the user in the database using the given invite.
|
2018-07-24 19:37:49 -04:00
|
|
|
function registerUser(username, password, invite, sanitize, cb) {
|
2018-01-15 15:29:32 -05:00
|
|
|
async.series([
|
|
|
|
function (cb) {
|
|
|
|
// Canonicalize and sanitize the username, checking for HTML
|
|
|
|
var canonicalName = canonicalize(username);
|
2018-07-24 19:37:49 -04:00
|
|
|
var sanitizedName = sanitize(canonicalName).replace(/\s/g,'');
|
2018-01-15 15:29:32 -05:00
|
|
|
|
|
|
|
if (sanitizedName !== canonicalName)
|
2018-07-24 19:37:49 -04:00
|
|
|
cb('Username contains invalid characters.');
|
2018-01-15 15:29:32 -05:00
|
|
|
else if (canonicalName.length > 36)
|
|
|
|
cb('Username too long.');
|
|
|
|
else
|
|
|
|
cb(null);
|
|
|
|
},
|
2018-07-24 19:37:49 -04:00
|
|
|
function(cb) {
|
|
|
|
async.waterfall([
|
|
|
|
function(cb) {
|
|
|
|
User.count({canonicalname: canonicalize(username)}, cb);
|
|
|
|
},
|
|
|
|
function(count, cb) {
|
|
|
|
if (count !== 0)
|
|
|
|
cb('Username in use.');
|
|
|
|
else
|
|
|
|
cb(null);
|
|
|
|
}
|
|
|
|
], cb);
|
|
|
|
},
|
2018-01-15 15:29:32 -05:00
|
|
|
function (cb) {
|
|
|
|
User.register(new User({
|
|
|
|
username: username,
|
|
|
|
canonicalname: canonicalize(username),
|
|
|
|
scope: invite.scope,
|
|
|
|
date: Date.now()
|
|
|
|
}), password, cb);
|
|
|
|
},
|
|
|
|
function (cb) {
|
|
|
|
invite.use(canonicalize(username), cb);
|
|
|
|
}
|
|
|
|
], function (err) {
|
|
|
|
cb(err);
|
2017-10-12 12:50:02 -04:00
|
|
|
});
|
2017-10-11 12:55:46 -04:00
|
|
|
}
|
|
|
|
|
2018-01-15 15:29:32 -05:00
|
|
|
// Authenticates and creates the required session variables
|
|
|
|
function setupSession(username, req, res, cb) {
|
|
|
|
// Body needs to contain canonical name for proper authentication
|
|
|
|
req.body.canonicalname = canonicalize(req.body.username);
|
|
|
|
|
|
|
|
passport.authenticate('local')(req, res, function () {
|
|
|
|
req.session.save(function (err) {
|
|
|
|
if (!err) {
|
2018-01-15 17:13:35 -05:00
|
|
|
req.session.passport.username = username;
|
|
|
|
req.session.passport.canonicalname = canonicalize(username);
|
2018-01-15 15:29:32 -05:00
|
|
|
}
|
|
|
|
cb(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
router.post('/register', function (req, res) {
|
|
|
|
async.waterfall([
|
|
|
|
function (cb) {
|
|
|
|
checkInvite(req.body.invite, cb);
|
|
|
|
},
|
|
|
|
function (invite, cb) {
|
|
|
|
registerUser(req.body.username, req.body.password, invite, req.sanitize, cb);
|
|
|
|
},
|
|
|
|
function (cb) {
|
|
|
|
setupSession(req.body.username, req, res, cb);
|
|
|
|
}
|
|
|
|
], function (err) {
|
|
|
|
if (err) {
|
|
|
|
res.status(401).json({'message': err});
|
2017-10-18 13:31:08 -04:00
|
|
|
} else {
|
2018-01-15 15:29:32 -05:00
|
|
|
res.status(200).json({'message': 'Registration successful.'});
|
2017-10-12 12:50:02 -04:00
|
|
|
}
|
2017-10-11 12:55:46 -04:00
|
|
|
});
|
2017-10-11 10:15:19 -04:00
|
|
|
});
|
|
|
|
|
2017-10-18 13:31:08 -04:00
|
|
|
router.post('/login', function (req, res, next) {
|
2018-01-15 15:29:32 -05:00
|
|
|
// Take 'username' from the form and canonicalize it for authentication.
|
|
|
|
req.body.canonicalname = canonicalize(req.body.username);
|
|
|
|
|
|
|
|
async.waterfall([
|
|
|
|
function (cb) {
|
|
|
|
passport.authenticate('local', function(err, user, info) {
|
|
|
|
cb(err, user, info);
|
|
|
|
})(req, res, next);
|
|
|
|
},
|
|
|
|
function (user, info, cb) {
|
|
|
|
if (!user)
|
|
|
|
cb(info);
|
|
|
|
else
|
|
|
|
req.logIn(user, cb);
|
|
|
|
},
|
|
|
|
function (cb) {
|
2018-01-15 17:13:35 -05:00
|
|
|
req.session.passport.username = req.body.username;
|
|
|
|
req.session.passport.canonicalname = canonicalize(req.body.username);
|
2018-01-15 15:29:32 -05:00
|
|
|
cb();
|
|
|
|
}
|
|
|
|
], function (err) {
|
|
|
|
if (err)
|
|
|
|
res.status(401).json({'message': err});
|
|
|
|
else
|
|
|
|
res.status(200).json({'message': 'Login successful.'});
|
|
|
|
});
|
2017-10-11 10:15:19 -04:00
|
|
|
});
|
|
|
|
|
2017-10-18 13:31:08 -04:00
|
|
|
router.get('/logout', function (req, res) {
|
|
|
|
req.logout();
|
|
|
|
res.status(200).json({'message': 'Logged out.'});
|
2017-10-14 17:49:11 -04:00
|
|
|
});
|
|
|
|
|
2018-01-15 15:29:32 -05:00
|
|
|
router.get('/session', function (req, res) {
|
2018-01-15 17:13:35 -05:00
|
|
|
console.log(req.session.passport);
|
2018-01-15 15:29:32 -05:00
|
|
|
if (req.session.passport.canonicalname) {
|
|
|
|
User.findOne({canonicalname: req.session.passport.canonicalname}, function (err, user) {
|
|
|
|
res.status(200).json({
|
|
|
|
username: user.username,
|
|
|
|
canonicalname: user.canonicalname,
|
|
|
|
scope: user.scope
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
res.status(401).json({'message': 'Unauthorized.'});
|
|
|
|
}
|
2017-10-18 13:31:08 -04:00
|
|
|
});
|
2017-10-11 10:15:19 -04:00
|
|
|
|
|
|
|
module.exports = router;
|