FIX: only invalidate password reset links using javascript

This commit is contained in:
Neil Lalonde 2016-01-04 11:48:54 -05:00
parent 0ba1e8a76f
commit c7df6783a9
5 changed files with 54 additions and 2 deletions

View file

@ -23,6 +23,7 @@ class UsersController < ApplicationController
:send_activation_email,
:authorize_email,
:password_reset,
:confirm_email_token,
:admin_login]
def index
@ -355,7 +356,12 @@ class UsersController < ApplicationController
expires_now
if EmailToken.valid_token_format?(params[:token])
@user = EmailToken.confirm(params[:token])
if request.put?
@user = EmailToken.confirm(params[:token])
else
email_token = EmailToken.confirmable(params[:token])
@user = email_token.try(:user)
end
if @user
session["password-#{params[:token]}"] = @user.id
@ -387,6 +393,12 @@ class UsersController < ApplicationController
render layout: 'no_ember'
end
def confirm_email_token
expires_now
EmailToken.confirm(params[:token])
render json: success_json
end
def logon_after_password_reset
message = if Guardian.new(@user).can_access_forum?
# Log in the user

View file

@ -44,7 +44,7 @@ class EmailToken < ActiveRecord::Base
def self.confirm(token)
return unless valid_token_format?(token)
email_token = EmailToken.where("token = ? and expired = FALSE AND ((NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?))", token, EmailToken.valid_after, EmailToken.confirm_valid_after).includes(:user).first
email_token = confirmable(token)
return if email_token.blank?
user = email_token.user
@ -59,12 +59,17 @@ class EmailToken < ActiveRecord::Base
user.save!
end
end
# redeem invite, if available
return User.find_by(email: Email.downcase(user.email)) if Invite.redeem_from_email(user.email).present?
user
rescue ActiveRecord::RecordInvalid
# If the user's email is already taken, just return nil (failure)
end
def self.confirmable(token)
EmailToken.where("token = ? and expired = FALSE AND ((NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?))", token, EmailToken.valid_after, EmailToken.confirm_valid_after).includes(:user).first
end
end
# == Schema Information

View file

@ -48,6 +48,10 @@
<%end%>
</div>
<%- content_for(:no_ember_head) do %>
<%= script "ember_jquery" %>
<%- end %>
<script type="text/javascript">
document.getElementById('user_password').focus();
@ -56,4 +60,6 @@
sk = e.shiftKey?e.shiftKey:((kc == 16)?true:false);
(((kc >= 65 && kc <= 90) && !sk)||((kc >= 97 && kc <= 122) && sk)) ? document.getElementById('capsLockWarning').style.visibility = 'visible' : document.getElementById('capsLockWarning').style.visibility = 'hidden';
}
$.ajax('<%= path "/users/confirm-email-token/#{params[:token]}" %>', {dataType: 'json'});
</script>

View file

@ -266,6 +266,7 @@ Discourse::Application.routes.draw do
get "users/search/users" => "users#search_users"
get "users/account-created/" => "users#account_created"
get "users/password-reset/:token" => "users#password_reset"
get "users/confirm-email-token/:token" => "users#confirm_email_token", constraints: { format: 'json' }
put "users/password-reset/:token" => "users#password_reset"
get "users/activate-account/:token" => "users#activate_account"
put "users/activate-account/:token" => "users#perform_account_activation", as: 'perform_activate_account'

View file

@ -326,6 +326,16 @@ describe UsersController do
expect(user.auth_token).to_not eq old_token
expect(user.auth_token.length).to eq 32
end
it "doesn't invalidate the token when loading the page" do
user = Fabricate(:user, auth_token: SecureRandom.hex(16))
email_token = user.email_tokens.create(email: user.email)
get :password_reset, token: email_token.token
email_token.reload
expect(email_token.confirmed).to eq(false)
end
end
context 'submit change' do
@ -361,6 +371,24 @@ describe UsersController do
end
end
describe '.confirm_email_token' do
let(:user) { Fabricate(:user) }
it "token doesn't match any records" do
email_token = user.email_tokens.create(email: user.email)
get :confirm_email_token, token: SecureRandom.hex, format: :json
expect(response).to be_success
expect(email_token.reload.confirmed).to eq(false)
end
it "token matches" do
email_token = user.email_tokens.create(email: user.email)
get :confirm_email_token, token: email_token.token, format: :json
expect(response).to be_success
expect(email_token.reload.confirmed).to eq(true)
end
end
describe '.admin_login' do
let(:admin) { Fabricate(:admin) }
let(:user) { Fabricate(:user) }