SECURITY: Only allow users to resend activation email with a valid session.
* Improve error when an active user tries to request for an activation email.
This commit is contained in:
parent
dd60cb82c3
commit
7ebfa3c901
|
@ -1,4 +1,5 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
|
|
||||||
export default Ember.Controller.extend(ModalFunctionality, {
|
export default Ember.Controller.extend(ModalFunctionality, {
|
||||||
|
@ -9,9 +10,13 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
sendActivationEmail: function() {
|
sendActivationEmail() {
|
||||||
ajax('/users/action/send_activation_email', {data: {username: this.get('username')}, type: 'POST'});
|
ajax('/users/action/send_activation_email', {
|
||||||
|
data: { username: this.get('username') },
|
||||||
|
type: 'POST'
|
||||||
|
}).then(() => {
|
||||||
this.set('emailSent', true);
|
this.set('emailSent', true);
|
||||||
|
}).catch(popupAjaxError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ class SessionController < ApplicationController
|
||||||
skip_before_filter :redirect_to_login_if_required
|
skip_before_filter :redirect_to_login_if_required
|
||||||
skip_before_filter :preload_json, :check_xhr, only: ['sso', 'sso_login', 'become', 'sso_provider', 'destroy']
|
skip_before_filter :preload_json, :check_xhr, only: ['sso', 'sso_login', 'become', 'sso_provider', 'destroy']
|
||||||
|
|
||||||
|
ACTIVATE_USER_KEY = "activate_user"
|
||||||
|
|
||||||
def csrf
|
def csrf
|
||||||
render json: {csrf: form_authenticity_token }
|
render json: {csrf: form_authenticity_token }
|
||||||
end
|
end
|
||||||
|
@ -276,6 +278,7 @@ class SessionController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_activated(user)
|
def not_activated(user)
|
||||||
|
session[ACTIVATE_USER_KEY] = user.username
|
||||||
render json: {
|
render json: {
|
||||||
error: I18n.t("login.not_activated"),
|
error: I18n.t("login.not_activated"),
|
||||||
reason: 'not_activated',
|
reason: 'not_activated',
|
||||||
|
@ -303,6 +306,7 @@ class SessionController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def login(user)
|
def login(user)
|
||||||
|
session.delete(ACTIVATE_USER_KEY)
|
||||||
log_on_user(user)
|
log_on_user(user)
|
||||||
|
|
||||||
if payload = session.delete(:sso_payload)
|
if payload = session.delete(:sso_payload)
|
||||||
|
|
|
@ -567,14 +567,26 @@ class UsersController < ApplicationController
|
||||||
RateLimiter.new(nil, "activate-min-#{request.remote_ip}", 6, 1.minute).performed!
|
RateLimiter.new(nil, "activate-min-#{request.remote_ip}", 6, 1.minute).performed!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (current_user && !current_user.staff?) ||
|
||||||
|
(params[:username] != session[SessionController::ACTIVATE_USER_KEY])
|
||||||
|
|
||||||
|
raise Discourse::InvalidAccess
|
||||||
|
end
|
||||||
|
|
||||||
@user = User.find_by_username_or_email(params[:username].to_s)
|
@user = User.find_by_username_or_email(params[:username].to_s)
|
||||||
|
|
||||||
raise Discourse::NotFound unless @user
|
raise Discourse::NotFound unless @user
|
||||||
|
|
||||||
|
session.delete(SessionController::ACTIVATE_USER_KEY)
|
||||||
|
|
||||||
|
if @user.active
|
||||||
|
render_json_error(I18n.t('activation.activated'), status: 409)
|
||||||
|
elsif @user
|
||||||
@email_token = @user.email_tokens.unconfirmed.active.first
|
@email_token = @user.email_tokens.unconfirmed.active.first
|
||||||
enqueue_activation_email if @user
|
enqueue_activation_email
|
||||||
render nothing: true
|
render nothing: true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def enqueue_activation_email
|
def enqueue_activation_email
|
||||||
@email_token ||= @user.email_tokens.create(email: @user.email)
|
@email_token ||= @user.email_tokens.create(email: @user.email)
|
||||||
|
|
|
@ -614,6 +614,7 @@ en:
|
||||||
welcome_to: "Welcome to %{site_name}!"
|
welcome_to: "Welcome to %{site_name}!"
|
||||||
approval_required: "A moderator must manually approve your new account before you can access this forum. You'll get an email when your account is approved!"
|
approval_required: "A moderator must manually approve your new account before you can access this forum. You'll get an email when your account is approved!"
|
||||||
missing_session: "We cannot detect if your account was created, please ensure you have cookies enabled."
|
missing_session: "We cannot detect if your account was created, please ensure you have cookies enabled."
|
||||||
|
activated: "Sorry, this account has already been activated."
|
||||||
post_action_types:
|
post_action_types:
|
||||||
off_topic:
|
off_topic:
|
||||||
title: 'Off-Topic'
|
title: 'Off-Topic'
|
||||||
|
|
|
@ -1403,10 +1403,29 @@ describe UsersController do
|
||||||
context 'for an existing user' do
|
context 'for an existing user' do
|
||||||
let(:user) { Fabricate(:user, active: false) }
|
let(:user) { Fabricate(:user, active: false) }
|
||||||
|
|
||||||
|
context 'for an activated account' do
|
||||||
|
it 'fails' do
|
||||||
|
active_user = Fabricate(:user, active: true)
|
||||||
|
session[SessionController::ACTIVATE_USER_KEY] = active_user.username
|
||||||
|
xhr :post, :send_activation_email, username: active_user.username
|
||||||
|
|
||||||
|
expect(response.status).to eq(409)
|
||||||
|
|
||||||
|
expect(JSON.parse(response.body)['errors']).to include(I18n.t(
|
||||||
|
'activation.activated'
|
||||||
|
))
|
||||||
|
|
||||||
|
expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a valid email_token' do
|
context 'with a valid email_token' do
|
||||||
it 'should send the activation email' do
|
it 'should send the activation email' do
|
||||||
|
session["activate_user"] = user.username
|
||||||
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
||||||
xhr :post, :send_activation_email, username: user.username
|
xhr :post, :send_activation_email, username: user.username
|
||||||
|
|
||||||
|
expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1418,13 +1437,17 @@ describe UsersController do
|
||||||
|
|
||||||
it 'should generate a new token' do
|
it 'should generate a new token' do
|
||||||
expect {
|
expect {
|
||||||
|
session["activate_user"] = user.username
|
||||||
xhr :post, :send_activation_email, username: user.username
|
xhr :post, :send_activation_email, username: user.username
|
||||||
}.to change{ user.email_tokens(true).count }.by(1)
|
}.to change{ user.email_tokens(true).count }.by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should send an email' do
|
it 'should send an email' do
|
||||||
|
session["activate_user"] = user.username
|
||||||
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
||||||
xhr :post, :send_activation_email, username: user.username
|
xhr :post, :send_activation_email, username: user.username
|
||||||
|
|
||||||
|
expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue