Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
splitting token/token_expires_at into confirmation_token, remember_to…
…ken, & remember_token_expires_at
  • Loading branch information
Daniel Croak committed Aug 31, 2009
1 parent 5d524d4 commit 46f3617
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 107 deletions.
6 changes: 4 additions & 2 deletions app/controllers/clearance/confirmations_controller.rb
Expand Up @@ -13,7 +13,8 @@ def new
end

def create
@user = ::User.find_by_id_and_token(params[:user_id], params[:token])
@user = ::User.find_by_id_and_confirmation_token(
params[:user_id], params[:token])
@user.confirm_email!

sign_in(@user)
Expand Down Expand Up @@ -46,7 +47,8 @@ def forbid_missing_token
end

def forbid_non_existent_user
unless ::User.find_by_id_and_token(params[:user_id], params[:token])
unless ::User.find_by_id_and_confirmation_token(
params[:user_id], params[:token])
raise ActionController::Forbidden, "non-existent user"
end
end
Expand Down
9 changes: 6 additions & 3 deletions app/controllers/clearance/passwords_controller.rb
Expand Up @@ -22,12 +22,14 @@ def create
end

def edit
@user = ::User.find_by_id_and_token(params[:user_id], params[:token])
@user = ::User.find_by_id_and_confirmation_token(
params[:user_id], params[:token])
render :template => 'passwords/edit'
end

def update
@user = ::User.find_by_id_and_token(params[:user_id], params[:token])
@user = ::User.find_by_id_and_confirmation_token(
params[:user_id], params[:token])

if @user.update_password(params[:user][:password],
params[:user][:password_confirmation])
Expand All @@ -49,7 +51,8 @@ def forbid_missing_token
end

def forbid_non_existent_user
unless ::User.find_by_id_and_token(params[:user_id], params[:token])
unless ::User.find_by_id_and_confirmation_token(
params[:user_id], params[:token])
raise ActionController::Forbidden, "non-existent user"
end
end
Expand Down
4 changes: 3 additions & 1 deletion app/views/clearance_mailer/change_password.html.erb
Expand Up @@ -2,6 +2,8 @@ Someone, hopefully you, has requested that we send you a link to change your pas

Here's the link:

<%= edit_user_password_url(@user, :token => @user.token, :escape => false) %>
<%= edit_user_password_url(@user,
:token => @user.confirmation_token,
:escape => false) %>

If you didn't request this, ignore this email. Don't worry. Your password hasn't been changed.
5 changes: 4 additions & 1 deletion app/views/clearance_mailer/confirmation.html.erb
@@ -1,2 +1,5 @@
<%= new_user_confirmation_url :user_id => @user, :token => @user.token, :encode => false %>
<%= new_user_confirmation_url(
:user_id => @user,
:token => @user.confirmation_token,
:encode => false) %>
2 changes: 1 addition & 1 deletion app/views/passwords/edit.html.erb
Expand Up @@ -7,7 +7,7 @@
<%= error_messages_for :user %>
<% form_for(:user,
:url => user_password_path(@user, :token => @user.token),
:url => user_password_path(@user, :token => @user.confirmation_token),
:html => { :method => :put }) do |form| %>
<div class="password_field">
<%= form.label :password, "Choose password" %>
Expand Down
9 changes: 5 additions & 4 deletions generators/clearance/templates/migrations/create_users.rb
Expand Up @@ -4,15 +4,16 @@ def self.up
t.string :email
t.string :encrypted_password, :limit => 128
t.string :salt, :limit => 128
t.string :token, :limit => 128
t.datetime :token_expires_at
t.string :confirmation_token, :limit => 128
t.string :remember_token, :limit => 128
t.datetime :remember_token_expires_at
t.boolean :email_confirmed, :default => false, :null => false
t.timestamps
end

add_index :users, [:id, :token]
add_index :users, [:id, :confirmation_token]
add_index :users, :email
add_index :users, :token
add_index :users, :remember_token
end

def self.down
Expand Down
21 changes: 11 additions & 10 deletions generators/clearance/templates/migrations/update_users.rb
@@ -1,36 +1,37 @@
class ClearanceUpdateUsers < ActiveRecord::Migration
def self.up
<%
<%
existing_columns = ActiveRecord::Base.connection.columns(:users).collect { |each| each.name }
columns = [
[:email, 't.string :email'],
[:encrypted_password, 't.string :encrypted_password, :limit => 128'],
[:salt, 't.string :salt, :limit => 128'],
[:token, 't.string :token, :limit => 128'],
[:token_expires_at, 't.datetime :token_expires_at'],
[:email_confirmed, 't.boolean :email_confirmed, :default => false, :null => false']
].delete_if {|c| existing_columns.include?(c.first.to_s)}
[:salt, 't.string :salt, :limit => 128'],
[:confirmation_token, 't.string :confirmation_token, :limit => 128'],
[:remember_token, 't.string :remember_token, :limit => 128'],
[:remember_token_expires_at, 't.datetime :remember_token_expires_at'],
[:email_confirmed, 't.boolean :email_confirmed, :default => false, :null => false']
].delete_if {|c| existing_columns.include?(c.first.to_s)}
-%>
change_table(:users) do |t|
<% columns.each do |c| -%>
<%= c.last %>
<% end -%>
end

<%
existing_indexes = ActiveRecord::Base.connection.indexes(:users)
index_names = existing_indexes.collect { |each| each.name }
new_indexes = [
[:index_users_on_id_and_token, 'add_index :users, [:id, :token]'],
[:index_users_on_id_and_confirmation_token, 'add_index :users, [:id, :confirmation_token]'],
[:index_users_on_email, 'add_index :users, :email'],
[:index_users_on_token, 'add_index :users, :token']
[:index_users_on_remember_token, 'add_index :users, :remember_token']
].delete_if { |each| index_names.include?(each.first.to_s) }
-%>
<% new_indexes.each do |each| -%>
<%= each.last %>
<% end -%>
end

def self.down
change_table(:users) do |t|
<% unless columns.empty? -%>
Expand Down
8 changes: 5 additions & 3 deletions lib/clearance/authentication.rb
Expand Up @@ -49,8 +49,10 @@ def authenticate
def sign_in(user)
if user
user.remember_me!
cookies[:remember_token] = { :value => user.token,
:expires => user.token_expires_at }
cookies[:remember_token] = {
:value => user.remember_token,
:expires => user.remember_token_expires_at
}
end
end

Expand Down Expand Up @@ -81,7 +83,7 @@ def deny_access(flash_message = nil)

def user_from_cookie
if token = cookies[:remember_token]
return nil unless user = ::User.find_by_token(token)
return nil unless user = ::User.find_by_remember_token(token)
return user if user.remember?
end
end
Expand Down
47 changes: 25 additions & 22 deletions lib/clearance/user.rb
Expand Up @@ -83,7 +83,9 @@ module Callbacks
# salt, token, password encryption are handled before_save.
def self.included(model)
model.class_eval do
before_save :initialize_salt, :encrypt_password, :initialize_token
before_save :initialize_salt,
:encrypt_password,
:initialize_confirmation_token
end
end
end
Expand All @@ -105,15 +107,19 @@ def authenticated?(password)
# @example
# user.remember?
def remember?
token_expires_at && Time.now.utc < token_expires_at
remember_token &&
remember_token_expires_at &&
Time.now.utc < remember_token_expires_at
end

# Remember me for a year.
#
# @example
# user.remember_me!
# cookies[:remember_token] = { :value => user.token,
# :expires => user.token_expires_at }
# cookies[:remember_token] = {
# :value => user.remember_token,
# :expires => user.remember_token_expires_at
# }
def remember_me!
remember_me_until! 1.year.from_now.utc
end
Expand All @@ -123,7 +129,8 @@ def remember_me!
# @example
# user.forget_me!
def forget_me!
clear_token
self.remember_token = nil
self.remember_token_expires_at = nil
save(false)
end

Expand All @@ -132,8 +139,8 @@ def forget_me!
# @example
# user.confirm_email!
def confirm_email!
self.email_confirmed = true
self.token = nil
self.email_confirmed = true
self.confirmation_token = nil
save(false)
end

Expand All @@ -142,7 +149,7 @@ def confirm_email!
# @example
# user.forgot_password!
def forgot_password!
generate_token
generate_confirmation_token
save(false)
end

Expand All @@ -155,7 +162,9 @@ def forgot_password!
def update_password(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
clear_token if valid?
if valid?
self.confirmation_token = nil
end
save
end

Expand All @@ -167,7 +176,7 @@ def generate_hash(string)

def initialize_salt
if new_record?
self.salt = generate_hash("--#{Time.now.utc.to_s}--#{password}--")
self.salt = generate_hash("--#{Time.now.utc}--#{password}--")
end
end

Expand All @@ -180,27 +189,21 @@ def encrypt(string)
generate_hash("--#{salt}--#{string}--")
end

def generate_token
self.token = encrypt("--#{Time.now.utc.to_s}--#{password}--")
self.token_expires_at = nil
end

def clear_token
self.token = nil
self.token_expires_at = nil
def generate_confirmation_token
self.confirmation_token = encrypt("--#{Time.now.utc}--#{password}--")
end

def initialize_token
generate_token if new_record?
def initialize_confirmation_token
generate_confirmation_token if new_record?
end

def password_required?
encrypted_password.blank? || !password.blank?
end

def remember_me_until!(time)
self.token_expires_at = time
self.token = encrypt("--#{token_expires_at}--#{password}--")
self.remember_token_expires_at = time
self.remember_token = encrypt("--#{time}--#{password}--")
save(false)
end
end
Expand Down
2 changes: 1 addition & 1 deletion shoulda_macros/clearance.rb
Expand Up @@ -176,7 +176,7 @@ def should_display_a_password_update_form
warn "[DEPRECATION] should_display_a_password_update_form: not meant to be public, no longer used internally"
should "have a form for the user's token, password, and password confirm" do
update_path = ERB::Util.h(
user_password_path(@user, :token => @user.token)
user_password_path(@user, :token => @user.confirmation_token)
)

assert_select 'form[action=?]', update_path do
Expand Down
18 changes: 10 additions & 8 deletions test/controllers/confirmations_controller_test.rb
Expand Up @@ -10,13 +10,14 @@ class ConfirmationsControllerTest < ActionController::TestCase
setup { @user = Factory(:user) }

should "have a token" do
assert_not_nil @user.token
assert_not_equal "", @user.token
assert_not_nil @user.confirmation_token
assert_not_equal "", @user.confirmation_token
end

context "on GET to #new with correct id and token" do
setup do
get :new, :user_id => @user.to_param, :token => @user.token
get :new, :user_id => @user.to_param,
:token => @user.confirmation_token
end

should_set_the_flash_to /confirmed email/i
Expand All @@ -28,11 +29,12 @@ class ConfirmationsControllerTest < ActionController::TestCase
context "with an incorrect token" do
setup do
@bad_token = "bad token"
assert_not_equal @bad_token, @user.token
assert_not_equal @bad_token, @user.confirmation_token
end

should_forbid "on GET to #new with incorrect token" do
get :new, :user_id => @user.to_param, :token => @bad_token
get :new, :user_id => @user.to_param,
:token => @bad_token
end
end

Expand All @@ -48,7 +50,7 @@ class ConfirmationsControllerTest < ActionController::TestCase
context "a signed in confirmed user on GET to #new with token" do
setup do
@user = Factory(:user)
@token = @user.token
@token = @user.confirmation_token
@user.confirm_email!
sign_in_as @user

Expand All @@ -63,7 +65,7 @@ class ConfirmationsControllerTest < ActionController::TestCase
context "a bad user" do
setup do
@user = Factory(:user)
@token = @user.token
@token = @user.confirmation_token
@user.confirm_email!

@bad_user = Factory(:email_confirmed_user)
Expand All @@ -78,7 +80,7 @@ class ConfirmationsControllerTest < ActionController::TestCase
context "a signed out confirmed user on GET to #new with token" do
setup do
@user = Factory(:user)
@token = @user.token
@token = @user.confirmation_token
@user.confirm_email!
get :new, :user_id => @user.to_param, :token => @token
end
Expand Down

0 comments on commit 46f3617

Please sign in to comment.