From cce7cf8c85f6b5662d571efee61d1a1cb3e21f45 Mon Sep 17 00:00:00 2001
From: Robin Ward <robin.ward@gmail.com>
Date: Mon, 14 Jul 2014 12:25:42 -0400
Subject: [PATCH] FEATURE: Require Javascript to activate an account via email
 link

---
 app/controllers/users_controller.rb           |   6 ++-
 app/views/users/activate_account.html.erb     |  36 +++++++++++-------
 .../users/perform_account_activation.html.erb |  20 ++++++++++
 config/locales/server.en.yml                  |   1 +
 config/routes.rb                              |   1 +
 spec/controllers/users_controller_spec.rb     |  11 +++---
 spec/fixtures/images/logo-dev.png             | Bin 5527 -> 5527 bytes
 spec/fixtures/images/logo.png                 | Bin 2714 -> 2701 bytes
 8 files changed, 54 insertions(+), 21 deletions(-)
 create mode 100644 app/views/users/perform_account_activation.html.erb

diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 5e8951604db..981be933f17 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -5,7 +5,7 @@ require_dependency 'avatar_upload_service'
 class UsersController < ApplicationController
 
   skip_before_filter :authorize_mini_profiler, only: [:avatar]
-  skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :activate_account, :authorize_email, :user_preferences_redirect, :avatar, :my_redirect]
+  skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :activate_account, :perform_account_activation, :authorize_email, :user_preferences_redirect, :avatar, :my_redirect]
 
   before_filter :ensure_logged_in, only: [:username, :update, :change_email, :user_preferences_redirect, :upload_user_image, :pick_avatar, :destroy_user_image, :destroy]
   before_filter :respond_to_suspicious_request, only: [:create]
@@ -273,6 +273,10 @@ class UsersController < ApplicationController
 
   def activate_account
     expires_now()
+    render layout: 'no_js'
+  end
+
+  def perform_account_activation
     if @user = EmailToken.confirm(params[:token])
 
       # Log in the user unless they need to be approved
diff --git a/app/views/users/activate_account.html.erb b/app/views/users/activate_account.html.erb
index 402de69ec83..a5380bcaafa 100644
--- a/app/views/users/activate_account.html.erb
+++ b/app/views/users/activate_account.html.erb
@@ -1,19 +1,27 @@
 <div id='simple-container'>
 
-  <%if flash[:error]%>
-    <div class='alert alert-error'>
-      <%=flash[:error]%>
-    </div>
-  <%else%>
     <h2><%= t 'activation.welcome_to', site_name: SiteSetting.title %></h2>
-    <p>
-    <% if @needs_approval %>
-      <%= t 'activation.approval_required' %>
-    <% else %>
-      <%= raw t('activation.please_continue', link: link_to(SiteSetting.title, '/')) %></a>.
+    <br/>
+    <button class='btn' id='activate-account-button'><%= t 'activation.action' %></button>
+
+    <%= form_tag(perform_activate_account_path, method: :put, id: 'activate-account-form') do %>
     <% end %>
-    </p>
-
-  <%end%>
-
 </div>
+
+<script language="javascript">
+  (function() {
+   var t1 = new Date().getTime(),
+       button = document.getElementById('activate-account-button'),
+       form = document.getElementById('activate-account-form');
+
+    button.addEventListener('click', function() {
+      var diff = new Date().getTime() - t1;
+
+      // Ensure the form has been visible for a few ms before allowing the
+      // user to submit.
+      if (diff > 50) {
+        form.submit();
+      }
+    });
+  })();
+</script>
diff --git a/app/views/users/perform_account_activation.html.erb b/app/views/users/perform_account_activation.html.erb
new file mode 100644
index 00000000000..34cd40442ce
--- /dev/null
+++ b/app/views/users/perform_account_activation.html.erb
@@ -0,0 +1,20 @@
+<div id='simple-container'>
+
+  <%if flash[:error]%>
+    <div class='alert alert-error'>
+      <%=flash[:error]%>
+    </div>
+  <%else%>
+    <h2><%= t 'activation.welcome_to', site_name: SiteSetting.title %></h2>
+    <p>
+    <% if @needs_approval %>
+      <%= t 'activation.approval_required' %>
+    <% else %>
+      <br>
+      <%= raw t('activation.please_continue', link: link_to(SiteSetting.title, '/')) %></a>.
+    <% end %>
+    </p>
+
+  <%end%>
+
+</div>
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 1a1e3d84e4a..ca32399e414 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -383,6 +383,7 @@ en:
     error: "There was an error changing your email address. Perhaps the address is already in use?"
 
   activation:
+    action: "Activate your account"
     already_done: "Sorry, this account confirmation link is no longer valid. Perhaps your account is already active?"
     please_continue: "Your new account is confirmed, and you are now logged in. Continue to %{link}"
     welcome_to: "Welcome to %{site_name}!"
diff --git a/config/routes.rb b/config/routes.rb
index 99f8d6fe91a..eae6e189e32 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -188,6 +188,7 @@ Discourse::Application.routes.draw do
   get "users/password-reset/:token" => "users#password_reset"
   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'
   get "users/authorize-email/:token" => "users#authorize_email"
   get "users/hp" => "users#get_honeypot_value"
   get "my/*path", to: 'users#my_redirect'
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 66a4152ac2c..23c5897ed58 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -65,7 +65,6 @@ describe UsersController do
     end
 
     context 'valid token' do
-
       it 'authorizes with a correct token' do
         user = Fabricate(:user)
         email_token = user.email_tokens.create(email: user.email)
@@ -82,7 +81,7 @@ describe UsersController do
     context 'invalid token' do
       before do
         EmailToken.expects(:confirm).with('asdfasdf').returns(nil)
-        get :activate_account, token: 'asdfasdf'
+        put :perform_account_activation, token: 'asdfasdf'
       end
 
       it 'return success' do
@@ -105,13 +104,13 @@ describe UsersController do
         it 'enqueues a welcome message if the user object indicates so' do
           user.send_welcome_message = true
           user.expects(:enqueue_welcome_message).with('welcome_user')
-          get :activate_account, token: 'asdfasdf'
+          put :perform_account_activation, token: 'asdfasdf'
         end
 
         it "doesn't enqueue the welcome message if the object returns false" do
           user.send_welcome_message = false
           user.expects(:enqueue_welcome_message).with('welcome_user').never
-          get :activate_account, token: 'asdfasdf'
+          put :perform_account_activation, token: 'asdfasdf'
         end
 
       end
@@ -120,7 +119,7 @@ describe UsersController do
         before do
           Guardian.any_instance.expects(:can_access_forum?).returns(true)
           EmailToken.expects(:confirm).with('asdfasdf').returns(user)
-          get :activate_account, token: 'asdfasdf'
+          put :perform_account_activation, token: 'asdfasdf'
         end
 
         it 'returns success' do
@@ -145,7 +144,7 @@ describe UsersController do
         before do
           Guardian.any_instance.expects(:can_access_forum?).returns(false)
           EmailToken.expects(:confirm).with('asdfasdf').returns(user)
-          get :activate_account, token: 'asdfasdf'
+          put :perform_account_activation, token: 'asdfasdf'
         end
 
         it 'returns success' do
diff --git a/spec/fixtures/images/logo-dev.png b/spec/fixtures/images/logo-dev.png
index ad8b055c99061834ff1208fb22250d9bc43fd990..7cbeb6d6ce5fb485d2741664c8ff5ae112d467f7 100644
GIT binary patch
delta 65
zcmbQPJzaZ)o2ZCMh@p{{k)f4|nXZ9}m4U%&T~3b4QKGU6=n}gMHf~`60#8>zmvv4F
FO#mgv5gPyi

delta 65
zcmbQPJzaZ)o2ZCkh@pv<fw`55rM97gm4U&v5AVY!M~TWRpi3-Y8~%y`2s~Z=T-G@y
GGywp0DHA0C

diff --git a/spec/fixtures/images/logo.png b/spec/fixtures/images/logo.png
index ad8b1e0847a205e6a72aedb08c1be897402b3c2b..d09fee186e1ab1c8d53c547b201c30780fb82ed4 100644
GIT binary patch
delta 68
zcmbOw+ABK2WTPVomxxJ-p^=r5p_QqDu7Qb_fk8^R&6>%vT(S!25~5r!0t`Ul>FVdQ
I&MBb@07d^0Q2+n{

delta 79
zcmeAboh3TKgp08_$lZxy-8q?;8x6U+L<~a=O{@&etxPPn4GpXe46c26A2vCFOI870
UV)@$eR}4Vl>FVdQ&MBb@0Ife4X8-^I