diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3e510bb25..fb537e6a5 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -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 diff --git a/app/models/email_token.rb b/app/models/email_token.rb index a7eb036f9..d08c09161 100644 --- a/app/models/email_token.rb +++ b/app/models/email_token.rb @@ -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 diff --git a/app/views/users/password_reset.html.erb b/app/views/users/password_reset.html.erb index c1597a541..93a5fd40c 100644 --- a/app/views/users/password_reset.html.erb +++ b/app/views/users/password_reset.html.erb @@ -48,6 +48,10 @@ <%end%> +<%- content_for(:no_ember_head) do %> + <%= script "ember_jquery" %> +<%- end %> + diff --git a/config/routes.rb b/config/routes.rb index 2859b5bff..518fab5ca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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' diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 54f221b0f..435f4fd2e 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -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) }