var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, FacebookStrategy = require('passport-facebook').Strategy
, mongodb = require('mongodb')
, mongoose = require('mongoose')
, bcrypt = require('bcrypt')
, SALT_WORK_FACTOR = 15;
// connects to mongodb
mongoose.connect('localhost', 'test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback(){
console.log('Connected to MongoDB');
});
// user scheme
var userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true }, //passwords doesn't need to be unique
accessToken:{ type: String } // used for Remember Me
});
// bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if(err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
user.password = hash;
next();
});
});
});
// password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// remember me implementation
userSchema.methods.generateRandomToken = function () {
var user = this,
chars = "_!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
token = new Date().getTime() + '_';
for (var x = 0; x < SALT_WORK_FACTOR; x++) {
var i = Math.floor(Math.random() * 94);
token += chars.charAt(i);
}
return token;
};
// seed a test user
var User = mongoose.model('User', userSchema);
/*
var usr = new User({ username: 'bob', email: 'bob@example.com', password: 'secret' });
usr.save(function(err) {
if (err) {
console.log(err);
} else {
console.log('user: ' + usr.username + + 'saved.');
}
})*/
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
//
// Both serializer and deserializer edited for Remember Me functionality
passport.serializeUser( function(user, done) {
var createAccessToken = function() {
var token = user.generateRandomToken();
User.findOne( { accessToken: token }, function (err, existingUser) {
if (err) return done(err);
if (existingUser) {
createAccessToken(); //run it again. has to be unique
} else {
user.set('accessToken', token);
user.save( function(err) {
if (err) return done(err);
return done(null, user.get('accessToken'));
});
}
});
}
console.log('serializing user');
if (user._id) { createAccessToken(); }
else { done(null, user); }
});
passport.deserializeUser( function(token, done) {
console.log('deserializing ' + token.provider);
if (token.provider === undefined) {
User.findOne( { accessToken: token }, function(err, user) {
done(err, user);
});
} else { done(null, token); }
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
passport.use(new LocalStrategy(function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) return done(err);
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
user.comparePassword(password, function(err, isMatch) {
if (err) return done(err);
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
// Use the FacebookStrategy within Passport.
// Strategies in Passport require a `verify` function, which accept
// credentials (in this case, an accessToken, refreshToken, and Facebook
// profile), and invoke a callback with a user object.
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
}, function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function() {
// To keep the example simple, the user's Facebook profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Facebook account with a user record in your database,
// and return that user instead.
return done(null, profile);
});
}
));
// to ensure that users are logged in
function ensureAuthenticated(req, res, next) {
console.log('checking to see if authenticated');
if (req.isAuthenticated()) return next();
res.redirect('/login');
}
/*
* ============================================================
* Routes
*
*/
module.exports = function(app) {
/*
* GET home page.
*
* '/'
*/
app.get('/', function(req, res){
res.render('index', { title: 'DERS' });
});
/*
* GET TEST PAGE
*
* '/test'
*/
app.get('/test', function(req, res) {
res.render('test', {
title: 'test',
loggedin: false
});
});
app.get('/home', function(req, res) {
res.render('home', {
title: 'home',
loggedin: false
});
});
/*
* GET dashboard
*
* '/dashboard'
*/
app.get('/dashboard', function(req, res) {
console.log('/dashboard - ' + req.user);
res.render('dashboard', {
title: 'kanin',
loggedin: true
});
});
/*
* GET login page
*
* '/login'
*/
app.get('/login', function(req, res) {
res.render('login', { title: 'Logg inn' });
});
/* POST */
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) {
console.log(info.message);
req.session.messages = [info.message];
return res.redirect('/login');
}
req.logIn(user, function(err) {
if (err) return next(err);
return res.redirect('/dashboard');
})
})(req, res, next);
});
// GET /auth/facebook
// Use passport.authenticate() as route middleware to authenticate the
// request. The first step in Facebook authentication will involve
// redirecting the user to facebook.com. After authorization, Facebook will
// redirect the user back to this application at /auth/facebook/callback
app.get('/auth/facebook', passport.authenticate('facebook'), function(req, res){
// The request will be redirected to Facebook for authentication, so this
// function will not be called.
});
// GET /auth/facebook/callback
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
app.get('/auth/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login' }), function(req, res) {
console.log('/auth/facebook/callback --- ' + req.user.username);
res.redirect('/dashboard');
});
/*
* GET logout
*
* '/logout'
*/
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/test');
});
/*
* GET project page
*
* '/project'
*/
app.get('/project', function(req, res) {
res.render('project', { title: 'Harepus', loggedin: true });
})
/*
* GET signup page
*
* '/signup'
*/
app.get('/signup', function(req, res) {
res.render('signup', { title: 'Registrer deg' });
});
/* POST */
app.post('/signup', function(req, res) {
AM.addNewAccount({
name : req.param('name'),
email : req.param('email'),
user : req.param('user'),
pass : req.param('pass'),
country : req.param('country')
}, function(e) {
if (e) {
res.send(e, 400);
} else {
res.send('ok', 200);
}
});
});
/*
* ERRORS
*/
/* 404 */
app.get('*', function(req, res) {
res.render('error', { title: '404', text: 'Fant ikke siden' });
});
/* 403 on POST */
app.post('*', function(req, res) {
res.render('error', { title: '403', text: 'Du har ikke tilgang til denne siden' });
});
};