mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-05-06 21:17:04 +02:00
New 0.4 version
This commit is contained in:
43
modules/users/server/config/strategies/facebook.js
Normal file
43
modules/users/server/config/strategies/facebook.js
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
url = require('url'),
|
||||
FacebookStrategy = require('passport-facebook').Strategy,
|
||||
users = require('../../controllers/users.server.controller');
|
||||
|
||||
module.exports = function(config) {
|
||||
// Use facebook strategy
|
||||
passport.use(new FacebookStrategy({
|
||||
clientID: config.facebook.clientID,
|
||||
clientSecret: config.facebook.clientSecret,
|
||||
callbackURL: config.facebook.callbackURL,
|
||||
profileFields: ['id', 'name', 'displayName', 'email', 'username', 'photos'],
|
||||
passReqToCallback: true
|
||||
},
|
||||
function(req, accessToken, refreshToken, profile, done) {
|
||||
// Set the provider data and include tokens
|
||||
var providerData = profile._json;
|
||||
providerData.accessToken = accessToken;
|
||||
providerData.refreshToken = refreshToken;
|
||||
|
||||
// Create the user OAuth profile
|
||||
var providerUserProfile = {
|
||||
firstName: profile.name.givenName,
|
||||
lastName: profile.name.familyName,
|
||||
displayName: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
username: profile.username,
|
||||
profileImageURL: (profile.photos && profile.photos.length) ? profile.photos[0].value : undefined,
|
||||
provider: 'facebook',
|
||||
providerIdentifierField: 'id',
|
||||
providerData: providerData
|
||||
};
|
||||
|
||||
// Save the user OAuth profile
|
||||
users.saveOAuthUserProfile(req, providerUserProfile, done);
|
||||
}
|
||||
));
|
||||
};
|
||||
40
modules/users/server/config/strategies/github.js
Normal file
40
modules/users/server/config/strategies/github.js
Normal file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
url = require('url'),
|
||||
GithubStrategy = require('passport-github').Strategy,
|
||||
users = require('../../controllers/users.server.controller');
|
||||
|
||||
module.exports = function(config) {
|
||||
// Use github strategy
|
||||
passport.use(new GithubStrategy({
|
||||
clientID: config.github.clientID,
|
||||
clientSecret: config.github.clientSecret,
|
||||
callbackURL: config.github.callbackURL,
|
||||
passReqToCallback: true
|
||||
},
|
||||
function(req, accessToken, refreshToken, profile, done) {
|
||||
// Set the provider data and include tokens
|
||||
var providerData = profile._json;
|
||||
providerData.accessToken = accessToken;
|
||||
providerData.refreshToken = refreshToken;
|
||||
|
||||
// Create the user OAuth profile
|
||||
var providerUserProfile = {
|
||||
displayName: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
username: profile.username,
|
||||
profileImageURL: (providerData.avatar_url) ? providerData.avatar_url : undefined,
|
||||
provider: 'github',
|
||||
providerIdentifierField: 'id',
|
||||
providerData: providerData
|
||||
};
|
||||
|
||||
// Save the user OAuth profile
|
||||
users.saveOAuthUserProfile(req, providerUserProfile, done);
|
||||
}
|
||||
));
|
||||
};
|
||||
42
modules/users/server/config/strategies/google.js
Normal file
42
modules/users/server/config/strategies/google.js
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
url = require('url'),
|
||||
GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
|
||||
users = require('../../controllers/users.server.controller');
|
||||
|
||||
module.exports = function(config) {
|
||||
// Use google strategy
|
||||
passport.use(new GoogleStrategy({
|
||||
clientID: config.google.clientID,
|
||||
clientSecret: config.google.clientSecret,
|
||||
callbackURL: config.google.callbackURL,
|
||||
passReqToCallback: true
|
||||
},
|
||||
function(req, accessToken, refreshToken, profile, done) {
|
||||
// Set the provider data and include tokens
|
||||
var providerData = profile._json;
|
||||
providerData.accessToken = accessToken;
|
||||
providerData.refreshToken = refreshToken;
|
||||
|
||||
// Create the user OAuth profile
|
||||
var providerUserProfile = {
|
||||
firstName: profile.name.givenName,
|
||||
lastName: profile.name.familyName,
|
||||
displayName: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
username: profile.username,
|
||||
profileImageURL: (providerData.picture) ? providerData.picture : undefined,
|
||||
provider: 'google',
|
||||
providerIdentifierField: 'id',
|
||||
providerData: providerData
|
||||
};
|
||||
|
||||
// Save the user OAuth profile
|
||||
users.saveOAuthUserProfile(req, providerUserProfile, done);
|
||||
}
|
||||
));
|
||||
};
|
||||
43
modules/users/server/config/strategies/linkedin.js
Normal file
43
modules/users/server/config/strategies/linkedin.js
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
url = require('url'),
|
||||
LinkedInStrategy = require('passport-linkedin').Strategy,
|
||||
users = require('../../controllers/users.server.controller');
|
||||
|
||||
module.exports = function(config) {
|
||||
// Use linkedin strategy
|
||||
passport.use(new LinkedInStrategy({
|
||||
consumerKey: config.linkedin.clientID,
|
||||
consumerSecret: config.linkedin.clientSecret,
|
||||
callbackURL: config.linkedin.callbackURL,
|
||||
passReqToCallback: true,
|
||||
profileFields: ['id', 'first-name', 'last-name', 'email-address', 'picture-url']
|
||||
},
|
||||
function(req, accessToken, refreshToken, profile, done) {
|
||||
// Set the provider data and include tokens
|
||||
var providerData = profile._json;
|
||||
providerData.accessToken = accessToken;
|
||||
providerData.refreshToken = refreshToken;
|
||||
|
||||
// Create the user OAuth profile
|
||||
var providerUserProfile = {
|
||||
firstName: profile.name.givenName,
|
||||
lastName: profile.name.familyName,
|
||||
displayName: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
username: profile.username,
|
||||
profileImageURL: (providerData.pictureUrl) ? providerData.pictureUrl : undefined,
|
||||
provider: 'linkedin',
|
||||
providerIdentifierField: 'id',
|
||||
providerData: providerData
|
||||
};
|
||||
|
||||
// Save the user OAuth profile
|
||||
users.saveOAuthUserProfile(req, providerUserProfile, done);
|
||||
}
|
||||
));
|
||||
};
|
||||
38
modules/users/server/config/strategies/local.js
Normal file
38
modules/users/server/config/strategies/local.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
LocalStrategy = require('passport-local').Strategy,
|
||||
User = require('mongoose').model('User');
|
||||
|
||||
module.exports = function() {
|
||||
// Use local strategy
|
||||
passport.use(new LocalStrategy({
|
||||
usernameField: 'username',
|
||||
passwordField: 'password'
|
||||
},
|
||||
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'
|
||||
});
|
||||
}
|
||||
if (!user.authenticate(password)) {
|
||||
return done(null, false, {
|
||||
message: 'Invalid password'
|
||||
});
|
||||
}
|
||||
|
||||
return done(null, user);
|
||||
});
|
||||
}
|
||||
));
|
||||
};
|
||||
39
modules/users/server/config/strategies/twitter.js
Normal file
39
modules/users/server/config/strategies/twitter.js
Normal file
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
url = require('url'),
|
||||
TwitterStrategy = require('passport-twitter').Strategy,
|
||||
users = require('../../controllers/users.server.controller');
|
||||
|
||||
module.exports = function(config) {
|
||||
// Use twitter strategy
|
||||
passport.use(new TwitterStrategy({
|
||||
consumerKey: config.twitter.clientID,
|
||||
consumerSecret: config.twitter.clientSecret,
|
||||
callbackURL: config.twitter.callbackURL,
|
||||
passReqToCallback: true
|
||||
},
|
||||
function(req, token, tokenSecret, profile, done) {
|
||||
// Set the provider data and include tokens
|
||||
var providerData = profile._json;
|
||||
providerData.token = token;
|
||||
providerData.tokenSecret = tokenSecret;
|
||||
|
||||
// Create the user OAuth profile
|
||||
var providerUserProfile = {
|
||||
displayName: profile.displayName,
|
||||
username: profile.username,
|
||||
profileImageURL: (profile.photos && profile.photos.length) ? profile.photos[0].value : undefined,
|
||||
provider: 'twitter',
|
||||
providerIdentifierField: 'id_str',
|
||||
providerData: providerData
|
||||
};
|
||||
|
||||
// Save the user OAuth profile
|
||||
users.saveOAuthUserProfile(req, providerUserProfile, done);
|
||||
}
|
||||
));
|
||||
};
|
||||
34
modules/users/server/config/users.server.config.js
Normal file
34
modules/users/server/config/users.server.config.js
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport'),
|
||||
User = require('mongoose').model('User'),
|
||||
path = require('path'),
|
||||
config = require(path.resolve('./config/config'));
|
||||
|
||||
module.exports = function(app, db) {
|
||||
// Serialize sessions
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user.id);
|
||||
});
|
||||
|
||||
// Deserialize sessions
|
||||
passport.deserializeUser(function(id, done) {
|
||||
User.findOne({
|
||||
_id: id
|
||||
}, '-salt -password', function(err, user) {
|
||||
done(err, user);
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize strategies
|
||||
config.utils.getGlobbedPaths(path.join(__dirname, './strategies/**/*.js')).forEach(function(strategy) {
|
||||
require(path.resolve(strategy))(config);
|
||||
});
|
||||
|
||||
// Add passport's middleware
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
};
|
||||
16
modules/users/server/controllers/users.server.controller.js
Executable file
16
modules/users/server/controllers/users.server.controller.js
Executable file
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Extend user's controller
|
||||
*/
|
||||
module.exports = _.extend(
|
||||
require('./users/users.authentication.server.controller'),
|
||||
require('./users/users.authorization.server.controller'),
|
||||
require('./users/users.password.server.controller'),
|
||||
require('./users/users.profile.server.controller')
|
||||
);
|
||||
@@ -0,0 +1,208 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _ = require('lodash'),
|
||||
path = require('path'),
|
||||
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller')),
|
||||
mongoose = require('mongoose'),
|
||||
passport = require('passport'),
|
||||
User = mongoose.model('User');
|
||||
|
||||
/**
|
||||
* Signup
|
||||
*/
|
||||
exports.signup = function(req, res) {
|
||||
// For security measurement we remove the roles from the req.body object
|
||||
delete req.body.roles;
|
||||
|
||||
// Init Variables
|
||||
var user = new User(req.body);
|
||||
var message = null;
|
||||
|
||||
// Add missing user fields
|
||||
user.provider = 'local';
|
||||
user.displayName = user.firstName + ' ' + user.lastName;
|
||||
|
||||
// Then save the user
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
// Remove sensitive data before login
|
||||
user.password = undefined;
|
||||
user.salt = undefined;
|
||||
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Signin after passport authentication
|
||||
*/
|
||||
exports.signin = function(req, res, next) {
|
||||
passport.authenticate('local', function(err, user, info) {
|
||||
if (err || !user) {
|
||||
res.status(400).send(info);
|
||||
} else {
|
||||
// Remove sensitive data before login
|
||||
user.password = undefined;
|
||||
user.salt = undefined;
|
||||
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
})(req, res, next);
|
||||
};
|
||||
|
||||
/**
|
||||
* Signout
|
||||
*/
|
||||
exports.signout = function(req, res) {
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
};
|
||||
|
||||
/**
|
||||
* OAuth callback
|
||||
*/
|
||||
exports.oauthCallback = function(strategy) {
|
||||
return function(req, res, next) {
|
||||
passport.authenticate(strategy, function(err, user, redirectURL) {
|
||||
if (err || !user) {
|
||||
return res.redirect('/#!/signin');
|
||||
}
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
return res.redirect('/#!/signin');
|
||||
}
|
||||
|
||||
return res.redirect(redirectURL || '/');
|
||||
});
|
||||
})(req, res, next);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to save or update a OAuth user profile
|
||||
*/
|
||||
exports.saveOAuthUserProfile = function(req, providerUserProfile, done) {
|
||||
if (!req.user) {
|
||||
// Define a search query fields
|
||||
var searchMainProviderIdentifierField = 'providerData.' + providerUserProfile.providerIdentifierField;
|
||||
var searchAdditionalProviderIdentifierField = 'additionalProvidersData.' + providerUserProfile.provider + '.' + providerUserProfile.providerIdentifierField;
|
||||
|
||||
// Define main provider search query
|
||||
var mainProviderSearchQuery = {};
|
||||
mainProviderSearchQuery.provider = providerUserProfile.provider;
|
||||
mainProviderSearchQuery[searchMainProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField];
|
||||
|
||||
// Define additional provider search query
|
||||
var additionalProviderSearchQuery = {};
|
||||
additionalProviderSearchQuery[searchAdditionalProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField];
|
||||
|
||||
// Define a search query to find existing user with current provider profile
|
||||
var searchQuery = {
|
||||
$or: [mainProviderSearchQuery, additionalProviderSearchQuery]
|
||||
};
|
||||
|
||||
User.findOne(searchQuery, function(err, user) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
} else {
|
||||
if (!user) {
|
||||
var possibleUsername = providerUserProfile.username || ((providerUserProfile.email) ? providerUserProfile.email.split('@')[0] : '');
|
||||
|
||||
User.findUniqueUsername(possibleUsername, null, function(availableUsername) {
|
||||
user = new User({
|
||||
firstName: providerUserProfile.firstName,
|
||||
lastName: providerUserProfile.lastName,
|
||||
username: availableUsername,
|
||||
displayName: providerUserProfile.displayName,
|
||||
email: providerUserProfile.email,
|
||||
profileImageURL: providerUserProfile.profileImageURL,
|
||||
provider: providerUserProfile.provider,
|
||||
providerData: providerUserProfile.providerData
|
||||
});
|
||||
|
||||
// And save the user
|
||||
user.save(function(err) {
|
||||
return done(err, user);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return done(err, user);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// User is already logged in, join the provider data to the existing user
|
||||
var user = req.user;
|
||||
|
||||
// Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured
|
||||
if (user.provider !== providerUserProfile.provider && (!user.additionalProvidersData || !user.additionalProvidersData[providerUserProfile.provider])) {
|
||||
// Add the provider data to the additional provider data field
|
||||
if (!user.additionalProvidersData) user.additionalProvidersData = {};
|
||||
user.additionalProvidersData[providerUserProfile.provider] = providerUserProfile.providerData;
|
||||
|
||||
// Then tell mongoose that we've updated the additionalProvidersData field
|
||||
user.markModified('additionalProvidersData');
|
||||
|
||||
// And save the user
|
||||
user.save(function(err) {
|
||||
return done(err, user, '/#!/settings/accounts');
|
||||
});
|
||||
} else {
|
||||
return done(new Error('User is already connected using this provider'), user);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove OAuth provider
|
||||
*/
|
||||
exports.removeOAuthProvider = function(req, res, next) {
|
||||
var user = req.user;
|
||||
var provider = req.param('provider');
|
||||
|
||||
if (user && provider) {
|
||||
// Delete the additional provider
|
||||
if (user.additionalProvidersData[provider]) {
|
||||
delete user.additionalProvidersData[provider];
|
||||
|
||||
// Then tell mongoose that we've updated the additionalProvidersData field
|
||||
user.markModified('additionalProvidersData');
|
||||
}
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _ = require('lodash'),
|
||||
mongoose = require('mongoose'),
|
||||
User = mongoose.model('User');
|
||||
|
||||
/**
|
||||
* User middleware
|
||||
*/
|
||||
exports.userByID = function(req, res, next, id) {
|
||||
User.findOne({
|
||||
_id: id
|
||||
}).exec(function(err, user) {
|
||||
if (err) return next(err);
|
||||
if (!user) return next(new Error('Failed to load User ' + id));
|
||||
req.profile = user;
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Require login routing middleware
|
||||
*/
|
||||
exports.requiresLogin = function(req, res, next) {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).send({
|
||||
message: 'User is not logged in'
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
/**
|
||||
* User authorizations routing middleware
|
||||
*/
|
||||
exports.hasAuthorization = function(roles) {
|
||||
var _this = this;
|
||||
|
||||
return function(req, res, next) {
|
||||
_this.requiresLogin(req, res, function() {
|
||||
if (_.intersection(req.user.roles, roles).length) {
|
||||
return next();
|
||||
} else {
|
||||
return res.status(403).send({
|
||||
message: 'User is not authorized'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,249 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _ = require('lodash'),
|
||||
path = require('path'),
|
||||
config = require(path.resolve('./config/config')),
|
||||
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller')),
|
||||
mongoose = require('mongoose'),
|
||||
passport = require('passport'),
|
||||
User = mongoose.model('User'),
|
||||
nodemailer = require('nodemailer'),
|
||||
crypto = require('crypto'),
|
||||
async = require('async'),
|
||||
crypto = require('crypto');
|
||||
|
||||
/**
|
||||
* Forgot for reset password (forgot POST)
|
||||
*/
|
||||
exports.forgot = function(req, res, next) {
|
||||
async.waterfall([
|
||||
// Generate random token
|
||||
function(done) {
|
||||
crypto.randomBytes(20, function(err, buffer) {
|
||||
var token = buffer.toString('hex');
|
||||
done(err, token);
|
||||
});
|
||||
},
|
||||
// Lookup user by username
|
||||
function(token, done) {
|
||||
if (req.body.username) {
|
||||
User.findOne({
|
||||
username: req.body.username
|
||||
}, '-salt -password', function(err, user) {
|
||||
if (!user) {
|
||||
return res.status(400).send({
|
||||
message: 'No account with that username has been found'
|
||||
});
|
||||
} else if (user.provider !== 'local') {
|
||||
return res.status(400).send({
|
||||
message: 'It seems like you signed up using your ' + user.provider + ' account'
|
||||
});
|
||||
} else {
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
|
||||
user.save(function(err) {
|
||||
done(err, token, user);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return res.status(400).send({
|
||||
message: 'Username field must not be blank'
|
||||
});
|
||||
}
|
||||
},
|
||||
function(token, user, done) {
|
||||
res.render(path.resolve('modules/users/server/templates/reset-password-email'), {
|
||||
name: user.displayName,
|
||||
appName: config.app.title,
|
||||
url: 'http://' + req.headers.host + '/api/auth/reset/' + token
|
||||
}, function(err, emailHTML) {
|
||||
done(err, emailHTML, user);
|
||||
});
|
||||
},
|
||||
// If valid email, send reset email using service
|
||||
function(emailHTML, user, done) {
|
||||
var smtpTransport = nodemailer.createTransport(config.mailer.options);
|
||||
var mailOptions = {
|
||||
to: user.email,
|
||||
from: config.mailer.from,
|
||||
subject: 'Password Reset',
|
||||
html: emailHTML
|
||||
};
|
||||
smtpTransport.sendMail(mailOptions, function(err) {
|
||||
if (!err) {
|
||||
res.send({
|
||||
message: 'An email has been sent to ' + user.email + ' with further instructions.'
|
||||
});
|
||||
}
|
||||
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
], function(err) {
|
||||
if (err) return next(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset password GET from email token
|
||||
*/
|
||||
exports.validateResetToken = function(req, res) {
|
||||
User.findOne({
|
||||
resetPasswordToken: req.params.token,
|
||||
resetPasswordExpires: {
|
||||
$gt: Date.now()
|
||||
}
|
||||
}, function(err, user) {
|
||||
if (!user) {
|
||||
return res.redirect('/#!/password/reset/invalid');
|
||||
}
|
||||
|
||||
res.redirect('/#!/password/reset/' + req.params.token);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset password POST from email token
|
||||
*/
|
||||
exports.reset = function(req, res, next) {
|
||||
// Init Variables
|
||||
var passwordDetails = req.body;
|
||||
var message = null;
|
||||
|
||||
async.waterfall([
|
||||
|
||||
function(done) {
|
||||
User.findOne({
|
||||
resetPasswordToken: req.params.token,
|
||||
resetPasswordExpires: {
|
||||
$gt: Date.now()
|
||||
}
|
||||
}, function(err, user) {
|
||||
if (!err && user) {
|
||||
if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
|
||||
user.password = passwordDetails.newPassword;
|
||||
user.resetPasswordToken = undefined;
|
||||
user.resetPasswordExpires = undefined;
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
// Return authenticated user
|
||||
res.json(user);
|
||||
|
||||
done(err, user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return res.status(400).send({
|
||||
message: 'Passwords do not match'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return res.status(400).send({
|
||||
message: 'Password reset token is invalid or has expired.'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
function(user, done) {
|
||||
res.render('modules/users/server/templates/reset-password-confirm-email', {
|
||||
name: user.displayName,
|
||||
appName: config.app.title
|
||||
}, function(err, emailHTML) {
|
||||
done(err, emailHTML, user);
|
||||
});
|
||||
},
|
||||
// If valid email, send reset email using service
|
||||
function(emailHTML, user, done) {
|
||||
var smtpTransport = nodemailer.createTransport(config.mailer.options);
|
||||
var mailOptions = {
|
||||
to: user.email,
|
||||
from: config.mailer.from,
|
||||
subject: 'Your password has been changed',
|
||||
html: emailHTML
|
||||
};
|
||||
|
||||
smtpTransport.sendMail(mailOptions, function(err) {
|
||||
done(err, 'done');
|
||||
});
|
||||
}
|
||||
], function(err) {
|
||||
if (err) return next(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Change Password
|
||||
*/
|
||||
exports.changePassword = function(req, res, next) {
|
||||
// Init Variables
|
||||
var passwordDetails = req.body;
|
||||
var message = null;
|
||||
|
||||
if (req.user) {
|
||||
if (passwordDetails.newPassword) {
|
||||
User.findById(req.user.id, function(err, user) {
|
||||
if (!err && user) {
|
||||
if (user.authenticate(passwordDetails.currentPassword)) {
|
||||
if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
|
||||
user.password = passwordDetails.newPassword;
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.send({
|
||||
message: 'Password changed successfully'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'Passwords do not match'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'Current password is incorrect'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'User is not found'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'Please provide a new password'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'User is not signed in'
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var _ = require('lodash'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller')),
|
||||
mongoose = require('mongoose'),
|
||||
passport = require('passport'),
|
||||
User = mongoose.model('User');
|
||||
|
||||
/**
|
||||
* Update user details
|
||||
*/
|
||||
exports.update = function (req, res) {
|
||||
// Init Variables
|
||||
var user = req.user;
|
||||
|
||||
// For security measurement we remove the roles from the req.body object
|
||||
delete req.body.roles;
|
||||
|
||||
if (user) {
|
||||
// Merge existing user
|
||||
user = _.extend(user, req.body);
|
||||
user.updated = Date.now();
|
||||
user.displayName = user.firstName + ' ' + user.lastName;
|
||||
|
||||
user.save(function (err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function (err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'User is not signed in'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update profile picture
|
||||
*/
|
||||
exports.changeProfilePicture = function (req, res) {
|
||||
var user = req.user;
|
||||
var message = null;
|
||||
|
||||
if (user) {
|
||||
fs.writeFile('./modules/users/client/img/profile/uploads/' + req.files.file.name, req.files.file.buffer, function (uploadError) {
|
||||
if (uploadError) {
|
||||
return res.status(400).send({
|
||||
message: 'Error occurred while uploading profile picture'
|
||||
});
|
||||
} else {
|
||||
user.profileImageURL = 'modules/users/img/profile/uploads/' + req.files.file.name;
|
||||
|
||||
user.save(function (saveError) {
|
||||
if (saveError) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(saveError)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function (err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).send({
|
||||
message: 'User is not signed in'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send User
|
||||
*/
|
||||
exports.me = function (req, res) {
|
||||
res.json(req.user || null);
|
||||
};
|
||||
150
modules/users/server/models/user.server.model.js
Executable file
150
modules/users/server/models/user.server.model.js
Executable file
@@ -0,0 +1,150 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var mongoose = require('mongoose'),
|
||||
Schema = mongoose.Schema,
|
||||
crypto = require('crypto');
|
||||
|
||||
/**
|
||||
* A Validation function for local strategy properties
|
||||
*/
|
||||
var validateLocalStrategyProperty = function(property) {
|
||||
return ((this.provider !== 'local' && !this.updated) || property.length);
|
||||
};
|
||||
|
||||
/**
|
||||
* A Validation function for local strategy password
|
||||
*/
|
||||
var validateLocalStrategyPassword = function(password) {
|
||||
return (this.provider !== 'local' || (password && password.length > 6));
|
||||
};
|
||||
|
||||
/**
|
||||
* User Schema
|
||||
*/
|
||||
var UserSchema = new Schema({
|
||||
firstName: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: '',
|
||||
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
|
||||
},
|
||||
lastName: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: '',
|
||||
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
|
||||
},
|
||||
displayName: {
|
||||
type: String,
|
||||
trim: true
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: '',
|
||||
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
|
||||
match: [/.+\@.+\..+/, 'Please fill a valid email address']
|
||||
},
|
||||
username: {
|
||||
type: String,
|
||||
unique: 'testing error message',
|
||||
required: 'Please fill in a username',
|
||||
trim: true
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
default: '',
|
||||
validate: [validateLocalStrategyPassword, 'Password should be longer']
|
||||
},
|
||||
salt: {
|
||||
type: String
|
||||
},
|
||||
profileImageURL: {
|
||||
type: String,
|
||||
default: 'modules/users/img/profile/default.png'
|
||||
},
|
||||
provider: {
|
||||
type: String,
|
||||
required: 'Provider is required'
|
||||
},
|
||||
providerData: {},
|
||||
additionalProvidersData: {},
|
||||
roles: {
|
||||
type: [{
|
||||
type: String,
|
||||
enum: ['user', 'admin']
|
||||
}],
|
||||
default: ['user']
|
||||
},
|
||||
updated: {
|
||||
type: Date
|
||||
},
|
||||
created: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
},
|
||||
/* For reset password */
|
||||
resetPasswordToken: {
|
||||
type: String
|
||||
},
|
||||
resetPasswordExpires: {
|
||||
type: Date
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Hook a pre save method to hash the password
|
||||
*/
|
||||
UserSchema.pre('save', function(next) {
|
||||
if (this.password && this.password.length > 6) {
|
||||
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
|
||||
this.password = this.hashPassword(this.password);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
* Create instance method for hashing a password
|
||||
*/
|
||||
UserSchema.methods.hashPassword = function(password) {
|
||||
if (this.salt && password) {
|
||||
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
|
||||
} else {
|
||||
return password;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create instance method for authenticating user
|
||||
*/
|
||||
UserSchema.methods.authenticate = function(password) {
|
||||
return this.password === this.hashPassword(password);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find possible not used username
|
||||
*/
|
||||
UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
|
||||
var _this = this;
|
||||
var possibleUsername = username + (suffix || '');
|
||||
|
||||
_this.findOne({
|
||||
username: possibleUsername
|
||||
}, function(err, user) {
|
||||
if (!err) {
|
||||
if (!user) {
|
||||
callback(possibleUsername);
|
||||
} else {
|
||||
return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
|
||||
}
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
mongoose.model('User', UserSchema);
|
||||
53
modules/users/server/routes/auth.server.routes.js
Normal file
53
modules/users/server/routes/auth.server.routes.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport');
|
||||
|
||||
module.exports = function(app) {
|
||||
// User Routes
|
||||
var users = require('../controllers/users.server.controller');
|
||||
|
||||
// Setting up the users password api
|
||||
app.route('/api/auth/forgot').post(users.forgot);
|
||||
app.route('/api/auth/reset/:token').get(users.validateResetToken);
|
||||
app.route('/api/auth/reset/:token').post(users.reset);
|
||||
|
||||
// Setting up the users authentication api
|
||||
app.route('/api/auth/signup').post(users.signup);
|
||||
app.route('/api/auth/signin').post(users.signin);
|
||||
app.route('/api/auth/signout').get(users.signout);
|
||||
|
||||
// Setting the facebook oauth routes
|
||||
app.route('/api/auth/facebook').get(passport.authenticate('facebook', {
|
||||
scope: ['email']
|
||||
}));
|
||||
app.route('/api/auth/facebook/callback').get(users.oauthCallback('facebook'));
|
||||
|
||||
// Setting the twitter oauth routes
|
||||
app.route('/api/auth/twitter').get(passport.authenticate('twitter'));
|
||||
app.route('/api/auth/twitter/callback').get(users.oauthCallback('twitter'));
|
||||
|
||||
// Setting the google oauth routes
|
||||
app.route('/api/auth/google').get(passport.authenticate('google', {
|
||||
scope: [
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'https://www.googleapis.com/auth/userinfo.email'
|
||||
]
|
||||
}));
|
||||
app.route('/api/auth/google/callback').get(users.oauthCallback('google'));
|
||||
|
||||
// Setting the linkedin oauth routes
|
||||
app.route('/api/auth/linkedin').get(passport.authenticate('linkedin', {
|
||||
scope: [
|
||||
'r_basicprofile',
|
||||
'r_emailaddress'
|
||||
]
|
||||
}));
|
||||
app.route('/api/auth/linkedin/callback').get(users.oauthCallback('linkedin'));
|
||||
|
||||
// Setting the github oauth routes
|
||||
app.route('/api/auth/github').get(passport.authenticate('github'));
|
||||
app.route('/api/auth/github/callback').get(users.oauthCallback('github'));
|
||||
};
|
||||
21
modules/users/server/routes/users.server.routes.js
Normal file
21
modules/users/server/routes/users.server.routes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport');
|
||||
|
||||
module.exports = function(app) {
|
||||
// User Routes
|
||||
var users = require('../controllers/users.server.controller');
|
||||
|
||||
// Setting up the users profile api
|
||||
app.route('/api/users/me').get(users.me);
|
||||
app.route('/api/users').put(users.update);
|
||||
app.route('/api/users/accounts').delete(users.removeOAuthProvider);
|
||||
app.route('/api/users/password').post(users.changePassword);
|
||||
app.route('/api/users/picture').post(users.changeProfilePicture);
|
||||
|
||||
// Finish by binding the user middleware
|
||||
app.param('userId', users.userByID);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Dear {{name}},</p>
|
||||
<p></p>
|
||||
<p>This is a confirmation that the password for your account has just been changed</p>
|
||||
<br>
|
||||
<br>
|
||||
<p>The {{appName}} Support Team</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p>Dear {{name}},</p>
|
||||
<br>
|
||||
<p>
|
||||
You have requested to have your password reset for your account at {{appName}}
|
||||
</p>
|
||||
<p>Please visit this url to reset your password:</p>
|
||||
<p>{{url}}</p>
|
||||
<strong>If you didn't make this request, you can ignore this email.</strong>
|
||||
<br>
|
||||
<br>
|
||||
<p>The {{appName}} Support Team</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user