diff --git a/app/assets/javascripts/app/controllers/_profile/password.js.coffee b/app/assets/javascripts/app/controllers/_profile/password.js.coffee index abafaab68..e2100c6a1 100644 --- a/app/assets/javascripts/app/controllers/_profile/password.js.coffee +++ b/app/assets/javascripts/app/controllers/_profile/password.js.coffee @@ -13,8 +13,8 @@ class Index extends App.Controller html = $( App.view('profile/password')() ) configure_attributes = [ - { name: 'password_old', display: 'Current Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input span4', single: true }, - { name: 'password_new', display: 'New Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input span4', }, + { name: 'password_old', display: 'Current Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input', single: true }, + { name: 'password_new', display: 'New Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input', }, ] @form = new App.ControllerForm( @@ -27,38 +27,55 @@ class Index extends App.Controller update: (e) => e.preventDefault() params = @formParam(e.target) - error = @form.validate(params) - if error - @formValidate( form: e.target, errors: error ) - return false - @formDisable(e) + # validate + if params['password_new_confirm'] isnt params['password_new'] + @formEnable(e) + @$('[name=password_new]').val('') + @$('[name=password_new_confirm]').val('') + @notify + type: 'error' + msg: 'Can\'t update password, your new passwords do not match. Please try again!' + removeAll: true + return + if !params['password_new'] + @formEnable(e) + @notify + type: 'error' + msg: 'Please supply your new password!' + removeAll: true + return + # get data @ajax( - id: 'password_reset' - type: 'POST' - url: @apiPath + '/users/password_change' - data: JSON.stringify(params) + id: 'password_reset' + type: 'POST' + url: @apiPath + '/users/password_change' + data: JSON.stringify(params) processData: true - success: @success - error: @error + success: @success ) - success: (data, status, xhr) => - @render() - @notify( - type: 'success' - msg: App.i18n.translateContent( 'Password changed successfully!' ) - ) - - error: (xhr, status, error) => - @render() - data = JSON.parse( xhr.responseText ) - @notify( - type: 'error' - msg: App.i18n.translateContent( data.message ) - ) + success: (data) => + if data.message is 'ok' + @render() + @notify( + type: 'success' + msg: App.i18n.translateContent( 'Password changed successfully!' ) + ) + else + if data.notice + @notify + type: 'error' + msg: App.i18n.translateContent( data.notice[0], data.notice[1] ) + removeAll: true + else + @notify + type: 'error' + msg: 'Unable to set password. Please contact your administrator.' + removeAll: true + @formEnable( @$('form') ) App.Config.set( 'Password', { prio: 2000, name: 'Password', parent: '#profile', target: '#profile/password', controller: Index }, 'NavBarProfile' ) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ac1ecc79e..e14a06753 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -383,7 +383,7 @@ POST /api/v1/users/password_reset_verify Payload: { "token": "SoMeToKeN", - "password" "new_password" + "password": "new_password" } Response: @@ -398,6 +398,15 @@ curl http://localhost/api/v1/users/password_reset_verify.json -v -u #{login}:#{p def password_reset_verify if params[:password] + + # check password policy + result = password_policy(params[:password]) + if result != true + render :json => { :message => 'failed', :notice => result }, :status => :ok + return + end + + # set new password with token user = User.password_reset_via_token( params[:token], params[:password] ) else user = User.password_reset_check( params[:token] ) @@ -405,7 +414,7 @@ curl http://localhost/api/v1/users/password_reset_verify.json -v -u #{login}:#{p if user render :json => { :message => 'ok', :user_login => user.login }, :status => :ok else - render :json => { :message => 'failed' }, :status => :unprocessable_entity + render :json => { :message => 'failed' }, :status => :ok end end @@ -434,20 +443,28 @@ curl http://localhost/api/v1/users/password_change.json -v -u #{login}:#{passwor # check old password if !params[:password_old] - render :json => { :message => 'Old password needed!' }, :status => :unprocessable_entity + render :json => { :message => 'failed', :notice => ['Old password needed!'] }, :status => :ok return end user = User.authenticate( current_user.login, params[:password_old] ) if !user - render :json => { :message => 'Old password is wrong!' }, :status => :unprocessable_entity + render :json => { :message => 'failed', :notice => ['Old password is wrong!'] }, :status => :ok return end # set new password if !params[:password_new] - render :json => { :message => 'New password needed!' }, :status => :unprocessable_entity + render :json => { :message => 'failed', :notice => ['Please supply your new password!'] }, :status => :ok return end + + # check password policy + result = password_policy(params[:password_new]) + if result != true + render :json => { :message => 'failed', :notice => result }, :status => :ok + return + end + user.update_attributes( :password => params[:password_new] ) render :json => { :message => 'ok', :user_login => user.login }, :status => :ok end @@ -674,6 +691,19 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content private + def password_policy(password) + if Setting.get('password_min_size') > password.length + return ["Can\'t update password, it must be at least %s characters long!", Setting.get('password_min_size')] + end + if Setting.get('password_need_digit').to_i == 1 && password !~ /\d/ + return ["Can't update password, it must contain at least 1 digit!"] + end + if Setting.get('password_min_2_lower_2_upper_characters').to_i == 1 && ( password !~ /[A-Z].*[A-Z]/ || password !~ /[a-z].*[a-z]/ ) + return ["Can't update password, it must contain at least 2 lowercase and 2 uppercase characters!"] + end + true + end + def permission_check_by_role return true if is_role('Admin') return true if is_role('Agent') diff --git a/app/models/user.rb b/app/models/user.rb index 40fb38c39..9c8ef6199 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -203,7 +203,7 @@ returns end # auth ok - return user_auth + user_auth end =begin @@ -224,7 +224,7 @@ returns user_auth = Sso.check( params ) return if !user_auth - return user_auth + user_auth end =begin @@ -257,7 +257,6 @@ returns :updated_by_id => 1, :created_by_id => 1, ) - end =begin @@ -326,7 +325,7 @@ returns :subject => data[:subject], :body => data[:body] ) - return true + true end =begin @@ -349,7 +348,7 @@ returns user.login_failed = 0 user.save end - return user + user end =begin @@ -375,7 +374,7 @@ returns # delete token Token.where( :action => 'PasswordReset', :name => token ).first.destroy - return user + user end =begin @@ -431,7 +430,6 @@ returns self.firstname = scan[0][0].capitalize self.lastname = scan[0][1].capitalize end - end end diff --git a/db/seeds.rb b/db/seeds.rb index dca08902b..fa6998fe1 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -607,7 +607,7 @@ Setting.create_if_not_exists( }, ], }, - :state => 0, + :state => 1, :frontend => true ) Setting.create_if_not_exists( diff --git a/test/browser/signup_test.rb b/test/browser/signup_test.rb index e038a5f81..70c4cc762 100644 --- a/test/browser/signup_test.rb +++ b/test/browser/signup_test.rb @@ -57,8 +57,6 @@ class SignupTest < TestCase :execute => 'wait', :value => 5, }, - - # check action { :execute => 'check', :css => '.signup', @@ -73,6 +71,135 @@ class SignupTest < TestCase }, ], }, + { + :name => 'set password', + :action => [ + { + :execute => 'click', + :css => '.navbar-items-personal .user a', + }, + { + :execute => 'wait', + :value => 1, + }, + { + :execute => 'click', + :css => 'a[href="#profile"]', + }, + { + :execute => 'click', + :css => 'a[href="#profile/password"]', + }, + { + :execute => 'set', + :css => 'input[name="password_old"]', + :value => 'nonexisiting', + }, + { + :execute => 'set', + :css => 'input[name="password_new"]', + :value => 'some', + }, + { + :execute => 'set', + :css => 'input[name="password_new_confirm"]', + :value => 'some', + }, + { + :execute => 'click', + :css => '.content .btn--primary', + }, + { + :execute => 'watch_for', + :area => 'body', + :value => 'old password is wrong', + }, + { + :execute => 'set', + :css => 'input[name="password_old"]', + :value => 'some-pass', + }, + { + :execute => 'set', + :css => 'input[name="password_new_confirm"]', + :value => 'some2', + }, + { + :execute => 'click', + :css => '.content .btn--primary', + }, + { + :execute => 'watch_for', + :area => 'body', + :value => 'passwords do not match', + }, + { + :execute => 'set', + :css => 'input[name="password_new"]', + :value => 'some', + }, + { + :execute => 'set', + :css => 'input[name="password_new_confirm"]', + :value => 'some', + }, + { + :execute => 'click', + :css => '.content .btn--primary', + }, + { + :execute => 'watch_for', + :area => 'body', + :value => 'it must be at least', + }, + { + :execute => 'set', + :css => 'input[name="password_new"]', + :value => 'some-pass-new', + }, + { + :execute => 'set', + :css => 'input[name="password_new_confirm"]', + :value => 'some-pass-new', + }, + { + :execute => 'click', + :css => '.content .btn--primary', + }, + { + :execute => 'watch_for', + :area => 'body', + :value => 'must contain at least 1 digit', + }, + { + :execute => 'set', + :css => 'input[name="password_new"]', + :value => 'some-pass-new2', + }, + { + :execute => 'set', + :css => 'input[name="password_new_confirm"]', + :value => 'some-pass-new2', + }, + { + :execute => 'click', + :css => '.content .btn--primary', + }, + { + :execute => 'watch_for', + :area => 'body', + :value => 'Password changed successfully', + }, + { + :execute => 'logout', + }, + { + :execute => 'login', + :username => signup_user_email, + :password => 'some-pass-new2', + }, + ], + }, ] browser_single_test(tests) end