feat(users): limit for reset password time interval

add password reset configure item for time interval
default 24 hours
only can reset once in setting hours

#20 , #61e0534
This commit is contained in:
OldHawk
2017-11-30 15:09:12 +08:00
parent 9e1564247b
commit b87f33e67d
9 changed files with 75 additions and 10 deletions

View File

@@ -165,6 +165,19 @@ module.exports = {
showDemoSignMessage: true
},
/**
* @password
*
* password setting
*
* @resetTokenExpires: reset password token expires time, default 1 hour
* @resetTimeInterval: reset password time interval, default 24 hours, means only can do once in 24 hours.
*/
password: {
resetTokenExpires: 60 * 60 * 1000 * 1,
resetTimeInterval: 60 * 60 * 1000 * 24
},
/**
* @invite
*

View File

@@ -1034,6 +1034,16 @@
}
},
//status pages
STATUS_PAGE: {
BAD_REQUEST: 'Bad Request',
FORBIDDEN: 'Forbidden',
MADE_BAD_REQUEST: 'You made a bad request',
NOT_AUTHORIZED_THIS: 'You are not authorized to access this resource',
NOT_FOUND: 'Not Found',
PAGE_NOT_FOUND: 'Page Or Resources Not Found'
},
/////////////////////////resources tag fields///////////////////////////////////
RESOURCESTAGS: {
TYPE: {
@@ -1198,7 +1208,8 @@
SENDING_RESET_MAIL_SUCCESSFULLY: 'An email has been sent to the provided email with further instructions. please check it then reset your password',
SENDING_RESET_MAIL_FAILED: 'The password reset mail send failed',
PASSWORDS_DO_NOT_MATCH: 'twice passwords do not match',
RESET_TOKEN_INVALID: 'Password reset token is invalid or has expired.'
RESET_TOKEN_INVALID: 'Password reset token is invalid or has expired.',
RESET_PASSWORD_TO_FREQUENT: 'Reset password operation is too frequent, you can do once only in {{hours}} hours, next time is: {{nextTime}}'
}
};

View File

@@ -1034,6 +1034,16 @@
}
},
//status pages
STATUS_PAGE: {
BAD_REQUEST: '请求错误',
FORBIDDEN: '请求禁止',
MADE_BAD_REQUEST: '您发起了一个无效的请求',
NOT_AUTHORIZED_THIS: '您无权访问此资源',
NOT_FOUND: '无法访问',
PAGE_NOT_FOUND: '没有找到页面或资源'
},
/////////////////////////resources tag fields///////////////////////////////////
RESOURCESTAGS: {
TYPE: {
@@ -1198,7 +1208,8 @@
SENDING_RESET_MAIL_SUCCESSFULLY: '系统已向您帐户的注册邮箱发送了一封验证邮件, 请检查邮件并跟据邮件提示进一步重置您的帐户密码',
SENDING_RESET_MAIL_FAILED: '密码重置邮件发送失败',
PASSWORDS_DO_NOT_MATCH: '两次密码不匹配',
RESET_TOKEN_INVALID: '密码重置请求无效或已过期'
RESET_TOKEN_INVALID: '密码重置请求无效或已过期',
RESET_PASSWORD_TO_FREQUENT: '密码重置操作过于频繁, 您在 {{hours}} 小时内只能操作一次, 下次可操作时间为: {{nextTime}}'
}
};

View File

@@ -44,6 +44,9 @@
params: {
message: function ($stateParams) {
return $stateParams.message;
},
params: function ($stateParams) {
return $stateParams.params;
}
},
data: {
@@ -58,6 +61,9 @@
params: {
message: function ($stateParams) {
return $stateParams.message;
},
params: function ($stateParams) {
return $stateParams.params;
}
},
data: {

View File

@@ -10,9 +10,11 @@
function ErrorController($stateParams) {
var vm = this;
vm.errorMessage = null;
vm.errorParams = null;
// Display custom message if it was set
if ($stateParams.message) vm.errorMessage = $stateParams.message;
if ($stateParams.params) vm.errorParams = $stateParams.params;
}
}());

View File

@@ -5,9 +5,9 @@
.module('core')
.factory('authInterceptor', authInterceptor);
authInterceptor.$inject = ['$q', '$injector', 'Authentication'];
authInterceptor.$inject = ['$q', '$injector', 'Authentication', '$translate'];
function authInterceptor($q, $injector, Authentication) {
function authInterceptor($q, $injector, Authentication, $translate) {
var service = {
responseError: responseError
};
@@ -18,7 +18,7 @@
if (!rejection.config.ignoreAuthModule) {
switch (rejection.status) {
case 400:
$injector.get('$state').go('bad-request', { message: rejection.data.message });
$injector.get('$state').go('bad-request', {message: rejection.data.message, params: rejection.data.params});
break;
case 401:
// Deauthenticate the global user
@@ -29,11 +29,15 @@
$injector.get('$state').transitionTo('forbidden');
break;
case 404:
$injector.get('$state').go('not-found', { message: rejection.data.message });
$injector.get('$state').go('not-found', {message: rejection.data.message, params: rejection.data.params});
break;
case -1: // Handle error if no response from server(Network Lost or Server not responding)
var Notification = $injector.get('Notification');
Notification.error({ message: 'No response received from server. Please try again later.', title: 'Error processing request!', delay: 5000 });
Notification.error({
message: 'No response received from server. Please try again later.',
title: 'Error processing request!',
delay: 5000
});
break;
}
}

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('PasswordController', PasswordController);
PasswordController.$inject = ['$scope', '$stateParams', 'UsersService', '$location', 'Authentication', 'PasswordValidator', 'NotifycationService'];
PasswordController.$inject = ['$scope', '$stateParams', 'UsersService', '$location', 'Authentication', 'PasswordValidator', 'NotifycationService', '$translate'];
function PasswordController($scope, $stateParams, UsersService, $location, Authentication, PasswordValidator, NotifycationService) {
function PasswordController($scope, $stateParams, UsersService, $location, Authentication, PasswordValidator, NotifycationService, $translate) {
var vm = this;
vm.resetUserPassword = resetUserPassword;
@@ -64,6 +64,10 @@
// Show user error message and clear form
vm.credentials = null;
vm.isSendingMail = false;
if (response.data.params) {
response.data.message = $translate.instant(response.data.message, response.data.params);
}
NotifycationService.showErrorNotify(response.data.message, 'SIGN.REST_MAIL_SEND_FAILED');
}

View File

@@ -12,10 +12,12 @@ var path = require('path'),
nodemailer = require('nodemailer'),
async = require('async'),
crypto = require('crypto'),
moment = require('moment'),
traceLogCreate = require(path.resolve('./config/lib/tracelog')).create;
var smtpTransport = nodemailer.createTransport(config.mailer.options);
var traceConfig = config.meanTorrentConfig.trace;
var passwordConfig = config.meanTorrentConfig.password;
/**
* Forgot for reset password (forgot POST)
@@ -49,9 +51,18 @@ exports.forgot = function (req, res, next) {
return res.status(400).send({
message: 'It seems like you signed up using your ' + user.provider + ' account, please sign in using that provider.'
});
} else if (user.nextResetPasswordTime > Date.now()) {
return res.status(400).send({
message: 'SERVER.RESET_PASSWORD_TO_FREQUENT',
params: {
hours: passwordConfig.resetTimeInterval / (60 * 60 * 1000),
nextTime: moment(user.nextResetPasswordTime).format('YYYY-MM-DD HH:mm:ss')
}
});
} else {
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.resetPasswordExpires = Date.now() + passwordConfig.resetTokenExpires;
user.nextResetPasswordTime = Date.now() + passwordConfig.resetTimeInterval;
user.save(function (err) {
done(err, token, user);

View File

@@ -233,6 +233,9 @@ var UserSchema = new Schema({
},
resetPasswordExpires: {
type: Date
},
nextResetPasswordTime: {
type: Date
}
});