moved helper functions to auth.js as well as all passport strategies
This commit is contained in:
@ -30,37 +30,6 @@ UserSchema.virtual('password').set(function(password) {
|
||||
return this._password;
|
||||
});
|
||||
|
||||
/**
|
||||
* Validations
|
||||
*/
|
||||
var validatePresenceOf = function(value) {
|
||||
return value && value.length;
|
||||
};
|
||||
|
||||
// the below 4 validations only apply if you are signing up traditionally
|
||||
UserSchema.path('name').validate(function(name) {
|
||||
// if you are authenticating by any of the oauth strategies, don't validate
|
||||
if (authTypes.indexOf(this.provider) !== -1) return true;
|
||||
return name.length;
|
||||
}, 'Name cannot be blank');
|
||||
|
||||
UserSchema.path('email').validate(function(email) {
|
||||
// if you are authenticating by any of the oauth strategies, don't validate
|
||||
if (authTypes.indexOf(this.provider) !== -1) return true;
|
||||
return email.length;
|
||||
}, 'Email cannot be blank');
|
||||
|
||||
UserSchema.path('username').validate(function(username) {
|
||||
// if you are authenticating by any of the oauth strategies, don't validate
|
||||
if (authTypes.indexOf(this.provider) !== -1) return true;
|
||||
return username.length;
|
||||
}, 'Username cannot be blank');
|
||||
|
||||
UserSchema.path('hashed_password').validate(function(hashed_password) {
|
||||
// if you are authenticating by any of the oauth strategies, don't validate
|
||||
if (authTypes.indexOf(this.provider) !== -1) return true;
|
||||
return hashed_password.length;
|
||||
}, 'Password cannot be blank');
|
||||
|
||||
|
||||
/**
|
||||
|
16
server.js
16
server.js
@ -6,7 +6,7 @@ var express = require('express'),
|
||||
passport = require('passport'),
|
||||
config = require('./conf');
|
||||
|
||||
var User = require('./server/models/User');
|
||||
var Auth = require('./server/controllers/auth');
|
||||
|
||||
var db = mongoose.connect(config.db);
|
||||
var app = express();
|
||||
@ -25,13 +25,13 @@ app.use(passport.session());
|
||||
app.use(app.router);
|
||||
app.use(express.static(config.root + '/public'));
|
||||
|
||||
passport.use(User.localStrategy);
|
||||
passport.use(User.twitterStrategy());
|
||||
passport.use(User.facebookStrategy());
|
||||
passport.use(User.googleStrategy());
|
||||
passport.use(User.linkedInStrategy());
|
||||
passport.serializeUser(User.serializeUser);
|
||||
passport.deserializeUser(User.deserializeUser);
|
||||
passport.use(Auth.localStrategy);
|
||||
passport.use(Auth.twitterStrategy());
|
||||
passport.use(Auth.facebookStrategy());
|
||||
passport.use(Auth.googleStrategy());
|
||||
passport.use(Auth.linkedInStrategy());
|
||||
passport.serializeUser(Auth.serializeUser);
|
||||
passport.deserializeUser(Auth.deserializeUser);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1,46 +1,173 @@
|
||||
var passport = require('passport')
|
||||
, User = require('../models/User.js');
|
||||
var passport = require('passport'),
|
||||
User = require('../models/User'),
|
||||
crypto = require('crypto'),
|
||||
LocalStrategy = require('passport-local').Strategy,
|
||||
TwitterStrategy = require('passport-twitter').Strategy,
|
||||
FacebookStrategy = require('passport-facebook').Strategy,
|
||||
GoogleStrategy = require('passport-google').Strategy,
|
||||
LinkedInStrategy = require('passport-linkedin').Strategy,
|
||||
userRoles = require('../../client/js/routingConfig').userRoles;
|
||||
|
||||
|
||||
function findByUsername(username, callback) {
|
||||
User.findOne({ username: username }, function(err, user) {
|
||||
if (user) callback(err, user);
|
||||
});
|
||||
}
|
||||
|
||||
function findOrCreateOauthUser(provider, providerId, callback) {
|
||||
User.findOne({ $where: provider + '===' + providerId }, function(err, user) {
|
||||
if (user) return user;
|
||||
user = {
|
||||
username: provider + '_user',
|
||||
role: userRoles.user,
|
||||
provider: provider
|
||||
};
|
||||
user[provider] = providerId;
|
||||
user.save(function(err) {
|
||||
callback(err, user);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function findAll(callback) {
|
||||
User.find(function(err, users) {
|
||||
callback(err, users);
|
||||
});
|
||||
}
|
||||
|
||||
function findById(id, callback) {
|
||||
User.findById(id, function(err, user) {
|
||||
if (user) callback(err, user);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
register: function(req, res, next) {
|
||||
try {
|
||||
User.validate(req.body);
|
||||
}
|
||||
catch(err) {
|
||||
return res.send(400, err.message);
|
||||
}
|
||||
register: function(req, res, next) {
|
||||
|
||||
User.addUser(req.body.username, req.body.password, req.body.role, function(err, user) {
|
||||
if(err === 'UserAlreadyExists') return res.send(403, "User already exists");
|
||||
else if(err) return res.send(500);
|
||||
User.findOne({ username: req.body.username }, function(err, user) {
|
||||
if (user) return res.send(403, 'User already exists');
|
||||
|
||||
req.logIn(user, function(err) {
|
||||
if(err) { next(err); }
|
||||
else { res.json(200, { "role": user.role, "username": user.username }); }
|
||||
});
|
||||
user = new User({
|
||||
username: req.body.username,
|
||||
password: req.body.password,
|
||||
role: req.body.role
|
||||
});
|
||||
|
||||
user.save(function(err) {
|
||||
req.logIn(user, function(err) {
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
res.send(200, { 'role': user.role, 'username': user.username });
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
login: function(req, res, next) {
|
||||
passport.authenticate('local', function(err, user) {
|
||||
login: function(req, res, next) {
|
||||
passport.authenticate('local', function(err, user) {
|
||||
if (err) return next(err);
|
||||
if (!user) return res.send(400);
|
||||
req.logIn(user, function(err) {
|
||||
if (err) return next(err);
|
||||
if (req.body.rememberme) req.session.cookie.maxAge = 1000 * 60 * 60 * 24 * 7;
|
||||
res.json(200, { "role": user.role, "username": user.username });
|
||||
});
|
||||
})(req, res, next);
|
||||
},
|
||||
|
||||
if(err) { return next(err); }
|
||||
if(!user) { return res.send(400); }
|
||||
logout: function(req, res) {
|
||||
req.logout();
|
||||
res.send(200);
|
||||
},
|
||||
|
||||
|
||||
req.logIn(user, function(err) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if(req.body.rememberme) req.session.cookie.maxAge = 1000 * 60 * 60 * 24 * 7;
|
||||
res.json(200, { "role": user.role, "username": user.username });
|
||||
});
|
||||
})(req, res, next);
|
||||
},
|
||||
|
||||
logout: function(req, res) {
|
||||
req.logout();
|
||||
res.send(200);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
localStrategy: new LocalStrategy(function(username, password, done) {
|
||||
this.findByUsername(username, function(err, user) {
|
||||
if (!user) {
|
||||
done(null, false, { message: 'Username does not exist' });
|
||||
} else if (user.password !== password) {
|
||||
done(null, false, { message: 'Incorrect password' });
|
||||
} else {
|
||||
return done(null, user);
|
||||
}
|
||||
});
|
||||
}),
|
||||
|
||||
twitterStrategy: function() {
|
||||
if(!process.env.TWITTER_CONSUMER_KEY) throw new Error('A Twitter Consumer Key is required if you want to enable login via Twitter.');
|
||||
if(!process.env.TWITTER_CONSUMER_SECRET) throw new Error('A Twitter Consumer Secret is required if you want to enable login via Twitter.');
|
||||
|
||||
return new TwitterStrategy({
|
||||
consumerKey: process.env.TWITTER_CONSUMER_KEY,
|
||||
consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
|
||||
callbackURL: process.env.TWITTER_CALLBACK_URL || 'http://localhost:8000/auth/twitter/callback'
|
||||
},
|
||||
function(token, tokenSecret, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser(profile.provider, profile.id);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
facebookStrategy: function() {
|
||||
if(!process.env.FACEBOOK_APP_ID) throw new Error('A Facebook App ID is required if you want to enable login via Facebook.');
|
||||
if(!process.env.FACEBOOK_APP_SECRET) throw new Error('A Facebook App Secret is required if you want to enable login via Facebook.');
|
||||
|
||||
return new FacebookStrategy({
|
||||
clientID: process.env.FACEBOOK_APP_ID,
|
||||
clientSecret: process.env.FACEBOOK_APP_SECRET,
|
||||
callbackURL: process.env.FACEBOOK_CALLBACK_URL || "http://localhost:8000/auth/facebook/callback"
|
||||
},
|
||||
function(accessToken, refreshToken, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser(profile.provider, profile.id);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
googleStrategy: function() {
|
||||
|
||||
return new GoogleStrategy({
|
||||
returnURL: process.env.GOOGLE_RETURN_URL || "http://localhost:8000/auth/google/return",
|
||||
realm: process.env.GOOGLE_REALM || "http://localhost:8000/"
|
||||
},
|
||||
function(identifier, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser('google', identifier);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
linkedInStrategy: function() {
|
||||
if(!process.env.LINKED_IN_KEY) throw new Error('A LinkedIn App Key is required if you want to enable login via LinkedIn.');
|
||||
if(!process.env.LINKED_IN_SECRET) throw new Error('A LinkedIn App Secret is required if you want to enable login via LinkedIn.');
|
||||
|
||||
return new LinkedInStrategy({
|
||||
consumerKey: process.env.LINKED_IN_KEY,
|
||||
consumerSecret: process.env.LINKED_IN_SECRET,
|
||||
callbackURL: process.env.LINKED_IN_CALLBACK_URL || "http://localhost:8000/auth/linkedin/callback"
|
||||
},
|
||||
function(token, tokenSecret, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser('linkedin', profile.id);
|
||||
done(null,user);
|
||||
}
|
||||
);
|
||||
},
|
||||
serializeUser: function(user, done) {
|
||||
done(null, user.id);
|
||||
},
|
||||
|
||||
deserializeUser: function(id, done) {
|
||||
var user = module.exports.findById(id);
|
||||
|
||||
if(user) { done(null, user); }
|
||||
else { done(null, false); }
|
||||
}
|
||||
};
|
@ -1,197 +1,19 @@
|
||||
var _ = require('underscore'),
|
||||
mongoose = require('mongoose'),
|
||||
crypto = require('crypto'),
|
||||
passport = require('passport'),
|
||||
LocalStrategy = require('passport-local').Strategy,
|
||||
TwitterStrategy = require('passport-twitter').Strategy,
|
||||
FacebookStrategy = require('passport-facebook').Strategy,
|
||||
GoogleStrategy = require('passport-google').Strategy,
|
||||
LinkedInStrategy = require('passport-linkedin').Strategy,
|
||||
check = require('validator').check,
|
||||
userRoles = require('../../client/js/routingConfig').userRoles;
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var UserSchema = new mongoose.Schema({
|
||||
name: String,
|
||||
email: String,
|
||||
username: {
|
||||
type: String,
|
||||
unique: true
|
||||
unique: true,
|
||||
required: true
|
||||
},
|
||||
password: String,
|
||||
name: String,
|
||||
email: String,
|
||||
provider: String,
|
||||
hashed_password: String,
|
||||
salt: String,
|
||||
facebook: {},
|
||||
twitter: {},
|
||||
google: {}
|
||||
facebook: String,
|
||||
twitter: String,
|
||||
google: String,
|
||||
linkedin: String
|
||||
});
|
||||
|
||||
var User = mongoose.model('User', UserSchema);
|
||||
|
||||
var users = [
|
||||
{
|
||||
id: 1,
|
||||
username: "user",
|
||||
password: "123",
|
||||
role: userRoles.user
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "admin",
|
||||
password: "123",
|
||||
role: userRoles.admin
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
|
||||
addUser: function(username, password, role, callback) {
|
||||
if (this.findByUsername(username)) {
|
||||
return callback("UserAlreadyExists");
|
||||
}
|
||||
|
||||
var user = new User({
|
||||
username: username,
|
||||
password: password,
|
||||
role: role
|
||||
});
|
||||
|
||||
user.save(function(err) {
|
||||
callback(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
findOrCreateOauthUser: function(provider, providerId) {
|
||||
User.findOne({ $where: provider + '===' + providerId }, function(err, user) {
|
||||
if (user) {
|
||||
return user;
|
||||
} else {
|
||||
user = {
|
||||
username: provider + '_user',
|
||||
role: userRoles.user,
|
||||
provider: provider
|
||||
};
|
||||
user[provider] = providerId;
|
||||
|
||||
user.save(function(err) {
|
||||
return user;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
findAll: function() {
|
||||
User.find(function(err, users) {
|
||||
return users;
|
||||
});
|
||||
},
|
||||
|
||||
findById: function(id) {
|
||||
User.findById(id, function(err, user) {
|
||||
if (user) return user;
|
||||
});
|
||||
},
|
||||
|
||||
findByUsername: function(username) {
|
||||
User.findOne({ username: username }, function(err, user) {
|
||||
if (user) return user;
|
||||
});
|
||||
},
|
||||
|
||||
validate: function(user) {
|
||||
check(user.username, 'Username must be 1-20 characters long').len(1, 20);
|
||||
check(user.password, 'Password must be 5-60 characters long').len(5, 60);
|
||||
check(user.username, 'Invalid username').not(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/);
|
||||
|
||||
// TODO: Seems node-validator's isIn function doesn't handle Number arrays very well...
|
||||
// Till this is rectified Number arrays must be converted to string arrays
|
||||
// https://github.com/chriso/node-validator/issues/185
|
||||
var stringArr = _.map(_.values(userRoles), function(val) { return val.toString() });
|
||||
check(user.role, 'Invalid user role given').isIn(stringArr);
|
||||
},
|
||||
|
||||
localStrategy: new LocalStrategy(
|
||||
function(username, password, done) {
|
||||
|
||||
var user = module.exports.findByUsername(username);
|
||||
|
||||
if(!user) {
|
||||
done(null, false, { message: 'Incorrect username.' });
|
||||
}
|
||||
else if(user.password != password) {
|
||||
done(null, false, { message: 'Incorrect username.' });
|
||||
}
|
||||
else {
|
||||
return done(null, user);
|
||||
}
|
||||
|
||||
}
|
||||
),
|
||||
|
||||
twitterStrategy: function() {
|
||||
if(!process.env.TWITTER_CONSUMER_KEY) throw new Error('A Twitter Consumer Key is required if you want to enable login via Twitter.');
|
||||
if(!process.env.TWITTER_CONSUMER_SECRET) throw new Error('A Twitter Consumer Secret is required if you want to enable login via Twitter.');
|
||||
|
||||
return new TwitterStrategy({
|
||||
consumerKey: process.env.TWITTER_CONSUMER_KEY,
|
||||
consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
|
||||
callbackURL: process.env.TWITTER_CALLBACK_URL || 'http://localhost:8000/auth/twitter/callback'
|
||||
},
|
||||
function(token, tokenSecret, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser(profile.provider, profile.id);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
facebookStrategy: function() {
|
||||
if(!process.env.FACEBOOK_APP_ID) throw new Error('A Facebook App ID is required if you want to enable login via Facebook.');
|
||||
if(!process.env.FACEBOOK_APP_SECRET) throw new Error('A Facebook App Secret is required if you want to enable login via Facebook.');
|
||||
|
||||
return new FacebookStrategy({
|
||||
clientID: process.env.FACEBOOK_APP_ID,
|
||||
clientSecret: process.env.FACEBOOK_APP_SECRET,
|
||||
callbackURL: process.env.FACEBOOK_CALLBACK_URL || "http://localhost:8000/auth/facebook/callback"
|
||||
},
|
||||
function(accessToken, refreshToken, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser(profile.provider, profile.id);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
googleStrategy: function() {
|
||||
|
||||
return new GoogleStrategy({
|
||||
returnURL: process.env.GOOGLE_RETURN_URL || "http://localhost:8000/auth/google/return",
|
||||
realm: process.env.GOOGLE_REALM || "http://localhost:8000/"
|
||||
},
|
||||
function(identifier, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser('google', identifier);
|
||||
done(null, user);
|
||||
});
|
||||
},
|
||||
|
||||
linkedInStrategy: function() {
|
||||
if(!process.env.LINKED_IN_KEY) throw new Error('A LinkedIn App Key is required if you want to enable login via LinkedIn.');
|
||||
if(!process.env.LINKED_IN_SECRET) throw new Error('A LinkedIn App Secret is required if you want to enable login via LinkedIn.');
|
||||
|
||||
return new LinkedInStrategy({
|
||||
consumerKey: process.env.LINKED_IN_KEY,
|
||||
consumerSecret: process.env.LINKED_IN_SECRET,
|
||||
callbackURL: process.env.LINKED_IN_CALLBACK_URL || "http://localhost:8000/auth/linkedin/callback"
|
||||
},
|
||||
function(token, tokenSecret, profile, done) {
|
||||
var user = module.exports.findOrCreateOauthUser('linkedin', profile.id);
|
||||
done(null,user);
|
||||
}
|
||||
);
|
||||
},
|
||||
serializeUser: function(user, done) {
|
||||
done(null, user.id);
|
||||
},
|
||||
|
||||
deserializeUser: function(id, done) {
|
||||
var user = module.exports.findById(id);
|
||||
|
||||
if(user) { done(null, user); }
|
||||
else { done(null, false); }
|
||||
}
|
||||
};
|
||||
module.exports = mongoose.model('User', UserSchema);
|
Reference in New Issue
Block a user