Merge pull request #4621 from HabitRPG/lefnire/change-email

feat(change-email): allow changing email address
This commit is contained in:
Tyler Renelle
2015-02-03 15:40:06 -07:00
4 changed files with 68 additions and 58 deletions
+4 -25
View File
@@ -77,33 +77,12 @@ habitrpg.controller('SettingsCtrl',
$rootScope.$state.go('tasks');
}
$scope.changeUsername = function(changeUser){
if (!changeUser.newUsername || !changeUser.password) {
return alert(window.env.t('fillAll'));
}
$http.post(ApiUrl.get() + '/api/v2/user/change-username', changeUser)
$scope.changeUser = function(attr, updates){
$http.post(ApiUrl.get() + '/api/v2/user/change-'+attr, updates)
.success(function(){
alert(window.env.t('usernameSuccess'));
$scope.changeUser = {};
alert(window.env.t(attr+'Success'));
_.each(updates, function(v,k){updates[k]=null;});
User.sync();
})
.error(function(data){
alert(data.err);
});
}
$scope.changePassword = function(changePass){
if (!changePass.oldPassword || !changePass.newPassword || !changePass.confirmNewPassword) {
return alert(window.env.t('fillAll'));
}
$http.post(ApiUrl.get() + '/api/v2/user/change-password', changePass)
.success(function(data, status, headers, config){
if (data.err) return alert(data.err);
alert(window.env.t('passSuccess'));
$scope.changePass = {};
})
.error(function(data, status, headers, config){
alert(data.err);
});
}
+42 -23
View File
@@ -23,6 +23,10 @@ var accountSuspended = function(uuid){
code: 'ACCOUNT_SUSPENDED'
};
}
// escape email for regex, then search case-insensitive. See http://stackoverflow.com/a/3561711/362790
var mongoEmailRegex = function(email){
return new RegExp('^' + email.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i');
}
api.auth = function(req, res, next) {
var uid = req.headers['x-api-user'];
@@ -196,9 +200,7 @@ api.resetPassword = function(req, res, next){
newPassword = utils.makeSalt(), // use a salt as the new password too (they'll change it later)
hashed_password = utils.encryptPassword(newPassword, salt);
// escape email for regex, then search case-insensitive. See http://stackoverflow.com/a/3561711/362790
var emailRegExp = new RegExp('^' + email.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i');
User.findOne({'auth.local.email':emailRegExp}, function(err, user){
User.findOne({'auth.local.email':mongoEmailRegex(email)}, function(err, user){
if (err) return next(err);
if (!user) return res.send(500, {err:"Couldn't find a user registered for email " + email});
user.auth.local.salt = salt;
@@ -215,28 +217,45 @@ api.resetPassword = function(req, res, next){
});
};
var invalidPassword = function(user, password){
var hashed_password = utils.encryptPassword(password, user.auth.local.salt);
if (hashed_password !== user.auth.local.hashed_password)
return {code:401, err:"Incorrect password"};
return false;
}
api.changeUsername = function(req, res, next) {
var user = res.locals.user,
password = req.body.password,
newUsername = req.body.newUsername;
async.waterfall([
function(cb){
User.findOne({'auth.local.username': req.body.username}, {auth:1}, cb);
},
function(found, cb){
if (found) return cb({code:401, err: "Username already taken"});
if (invalidPassword(res.locals.user, req.body.password)) return cb(invalidPassword(res.locals.user, req.body.password));
res.locals.user.auth.local.username = req.body.username;
res.locals.user.save(cb);
}
], function(err){
if (err) return err.code ? res.json(err.code, err) : next(err);
res.send(200);
})
}
User.findOne({'auth.local.username': newUsername}, function(err, result) {
if (err) next(err);
if(result) return res.json(401, {err: "Username already taken"});
var salt = user.auth.local.salt;
var hashed_password = utils.encryptPassword(password, salt);
if (hashed_password !== user.auth.local.hashed_password)
return res.json(401, {err:"Incorrect password"});
user.auth.local.username = newUsername;
user.save(function(err, saved){
if (err) next(err);
res.send(200);
user = password = newUsername = null;
})
});
api.changeEmail = function(req, res, next){
async.waterfall([
function(cb){
User.findOne({'auth.local.email': mongoEmailRegex(req.body.email)}, {auth:1}, cb);
},
function(found, cb){
if(found) return cb({code:401, err: "Email already taken"});
if (invalidPassword(res.locals.user, req.body.password)) return cb(invalidPassword(res.locals.user, req.body.password));
res.locals.user.auth.local.email = req.body.email;
res.locals.user.save(cb);
}
], function(err){
if (err) return err.code ? res.json(err.code,err) : next(err);
res.send(200);
})
}
api.changePassword = function(req, res, next) {
+1
View File
@@ -11,6 +11,7 @@ router.post('/api/v2/user/auth/social', i18n.getUserLanguage, auth.loginSocial);
router.post('/api/v2/user/reset-password', i18n.getUserLanguage, auth.resetPassword);
router.post('/api/v2/user/change-password', i18n.getUserLanguage, auth.auth, auth.changePassword);
router.post('/api/v2/user/change-username', i18n.getUserLanguage, auth.auth, auth.changeUsername);
router.post('/api/v2/user/change-email', i18n.getUserLanguage, auth.auth, auth.changeEmail);
router.post('/api/v1/register', i18n.getUserLanguage, auth.registerUser);
router.post('/api/v1/user/auth/local', i18n.getUserLanguage, auth.loginLocal);
+21 -10
View File
@@ -103,7 +103,7 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
| 
=env.t('loginNameDescription3')
p=env.t('email')
|: {{::user.auth.local.email}}
|: {{user.auth.local.email}}
p
small.muted
=env.t('emailChange1')
@@ -112,22 +112,33 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
| 
=env.t('emailChange3')
hr
h5=env.t('changeUsername')
form(ng-submit='changeUsername(changeUser)', ng-show='user.auth.local')
form(ng-submit='changeUser("username", usernameUpdates)', ng-init='usernameUpdates={}', ng-show='user.auth.local', name='changeUsername', novalidate)
//-.alert.alert-danger(ng-messages='changeUsername.$error && changeUsername.submitted')=env.t('fillAll')
.form-group
input.form-control(type='text', placeholder=env.t('newUsername'), ng-model='changeUser.newUsername', required)
input.form-control(type='text', placeholder=env.t('newUsername'), ng-model='usernameUpdates.username', required)
.form-group
input.form-control(type='password', placeholder=env.t('password'), ng-model='changeUser.password', required)
input.btn.btn-default(type='submit', value=env.t('submit'))
input.form-control(type='password', placeholder=env.t('password'), ng-model='usernameUpdates.password', required)
input.btn.btn-default(type='submit', ng-disabled='changeUsername.$invalid', value=env.t('submit'))
h5=env.t('changeEmail')
form(ng-submit='changeUser("email", emailUpdates)', ng-show='user.auth.local', name='changeEmail', novalidate)
.form-group
input.form-control(type='text', placeholder=env.t('newEmail'), ng-model='emailUpdates.email', required)
.form-group
input.form-control(type='password', placeholder=env.t('password'), ng-model='emailUpdates.password', required)
input.btn.btn-default(type='submit', ng-disabled='changeEmail.$invalid', value=env.t('submit'))
h5=env.t('changePass')
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
form(ng-submit='changeUser("password", passwordUpdates)', ng-show='user.auth.local', name='changePassword', novalidate)
.form-group
input.form-control(type='password', placeholder=env.t('oldPass'), ng-model='changePass.oldPassword', required)
input.form-control(type='password', placeholder=env.t('oldPass'), ng-model='passwordUpdates.oldPassword', required)
.form-group
input.form-control(type='password', placeholder=env.t('newPass'), ng-model='changePass.newPassword', required)
input.form-control(type='password', placeholder=env.t('newPass'), ng-model='passwordUpdates.newPassword', required)
.form-group
input.form-control(type='password', placeholder=env.t('confirmPass'), ng-model='changePass.confirmNewPassword', required)
input.btn.btn-default(type='submit', value=env.t('submit'))
input.form-control(type='password', placeholder=env.t('confirmPass'), ng-model='passwordUpdates.confirmNewPassword', required)
input.btn.btn-default(type='submit', ng-disabled='changePassword.$invalid', value=env.t('submit'))
.panel.panel-default