ramon-devise 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/CHANGELOG.rdoc +109 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +243 -0
  4. data/Rakefile +45 -0
  5. data/TODO +8 -0
  6. data/app/controllers/confirmations_controller.rb +33 -0
  7. data/app/controllers/passwords_controller.rb +41 -0
  8. data/app/controllers/sessions_controller.rb +33 -0
  9. data/app/models/devise_mailer.rb +53 -0
  10. data/app/views/confirmations/new.html.erb +16 -0
  11. data/app/views/devise_mailer/confirmation_instructions.html.erb +5 -0
  12. data/app/views/devise_mailer/reset_password_instructions.html.erb +8 -0
  13. data/app/views/passwords/edit.html.erb +20 -0
  14. data/app/views/passwords/new.html.erb +16 -0
  15. data/app/views/sessions/new.html.erb +23 -0
  16. data/generators/devise/USAGE +5 -0
  17. data/generators/devise/devise_generator.rb +25 -0
  18. data/generators/devise/lib/route_devise.rb +32 -0
  19. data/generators/devise/templates/README +22 -0
  20. data/generators/devise/templates/migration.rb +20 -0
  21. data/generators/devise/templates/model.rb +5 -0
  22. data/generators/devise_install/USAGE +3 -0
  23. data/generators/devise_install/devise_install_generator.rb +9 -0
  24. data/generators/devise_install/templates/devise.rb +40 -0
  25. data/generators/devise_views/USAGE +3 -0
  26. data/generators/devise_views/devise_views_generator.rb +24 -0
  27. data/init.rb +2 -0
  28. data/lib/devise.rb +79 -0
  29. data/lib/devise/controllers/filters.rb +111 -0
  30. data/lib/devise/controllers/helpers.rb +130 -0
  31. data/lib/devise/controllers/url_helpers.rb +49 -0
  32. data/lib/devise/failure.rb +38 -0
  33. data/lib/devise/hooks/confirmable.rb +11 -0
  34. data/lib/devise/hooks/rememberable.rb +27 -0
  35. data/lib/devise/locales/en.yml +18 -0
  36. data/lib/devise/mapping.rb +120 -0
  37. data/lib/devise/migrations.rb +51 -0
  38. data/lib/devise/models.rb +105 -0
  39. data/lib/devise/models/authenticatable.rb +97 -0
  40. data/lib/devise/models/confirmable.rb +156 -0
  41. data/lib/devise/models/recoverable.rb +88 -0
  42. data/lib/devise/models/rememberable.rb +95 -0
  43. data/lib/devise/models/validatable.rb +36 -0
  44. data/lib/devise/rails.rb +17 -0
  45. data/lib/devise/rails/routes.rb +109 -0
  46. data/lib/devise/rails/warden_compat.rb +26 -0
  47. data/lib/devise/strategies/authenticatable.rb +46 -0
  48. data/lib/devise/strategies/base.rb +24 -0
  49. data/lib/devise/strategies/rememberable.rb +35 -0
  50. data/lib/devise/version.rb +3 -0
  51. data/lib/devise/warden.rb +24 -0
  52. data/test/controllers/filters_test.rb +103 -0
  53. data/test/controllers/helpers_test.rb +55 -0
  54. data/test/controllers/url_helpers_test.rb +47 -0
  55. data/test/devise_test.rb +72 -0
  56. data/test/failure_test.rb +34 -0
  57. data/test/integration/authenticatable_test.rb +187 -0
  58. data/test/integration/confirmable_test.rb +89 -0
  59. data/test/integration/recoverable_test.rb +131 -0
  60. data/test/integration/rememberable_test.rb +65 -0
  61. data/test/mailers/confirmation_instructions_test.rb +59 -0
  62. data/test/mailers/reset_password_instructions_test.rb +62 -0
  63. data/test/mapping_test.rb +101 -0
  64. data/test/models/authenticatable_test.rb +118 -0
  65. data/test/models/confirmable_test.rb +237 -0
  66. data/test/models/recoverable_test.rb +141 -0
  67. data/test/models/rememberable_test.rb +130 -0
  68. data/test/models/validatable_test.rb +99 -0
  69. data/test/models_test.rb +111 -0
  70. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  71. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  72. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  73. data/test/rails_app/app/controllers/users_controller.rb +7 -0
  74. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  75. data/test/rails_app/app/models/account.rb +3 -0
  76. data/test/rails_app/app/models/admin.rb +3 -0
  77. data/test/rails_app/app/models/organizer.rb +3 -0
  78. data/test/rails_app/app/models/user.rb +3 -0
  79. data/test/rails_app/config/boot.rb +110 -0
  80. data/test/rails_app/config/environment.rb +41 -0
  81. data/test/rails_app/config/environments/development.rb +17 -0
  82. data/test/rails_app/config/environments/production.rb +28 -0
  83. data/test/rails_app/config/environments/test.rb +28 -0
  84. data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
  85. data/test/rails_app/config/initializers/session_store.rb +15 -0
  86. data/test/rails_app/config/routes.rb +18 -0
  87. data/test/routes_test.rb +79 -0
  88. data/test/support/assertions_helper.rb +22 -0
  89. data/test/support/integration_tests_helper.rb +66 -0
  90. data/test/support/model_tests_helper.rb +51 -0
  91. data/test/test_helper.rb +40 -0
  92. metadata +154 -0
@@ -0,0 +1,51 @@
1
+ module Devise
2
+ # Helpers to migration:
3
+ #
4
+ # create_table :accounts do |t|
5
+ # t.authenticatable
6
+ # t.confirmable
7
+ # t.recoverable
8
+ # t.rememberable
9
+ # t.timestamps
10
+ # end
11
+ #
12
+ # However this method does not add indexes. If you need them, here is the declaration:
13
+ #
14
+ # add_index "accounts", ["email"], :name => "email", :unique => true
15
+ # add_index "accounts", ["confirmation_token"], :name => "confirmation_token", :unique => true
16
+ # add_index "accounts", ["reset_password_token"], :name => "reset_password_token", :unique => true
17
+ #
18
+ module Migrations
19
+
20
+ # Creates email, encrypted_password and password_salt.
21
+ #
22
+ def authenticatable(options={})
23
+ null = options[:null] || false
24
+ string :email, :limit => 100, :null => null
25
+ string :encrypted_password, :limit => 40, :null => null
26
+ string :password_salt, :limit => 20, :null => null
27
+ end
28
+
29
+ # Creates confirmation_token, confirmed_at and confirmation_sent_at.
30
+ #
31
+ def confirmable
32
+ string :confirmation_token, :limit => 20
33
+ datetime :confirmed_at
34
+ datetime :confirmation_sent_at
35
+ end
36
+
37
+ # Creates reset_password_token.
38
+ #
39
+ def recoverable
40
+ string :reset_password_token, :limit => 20
41
+ end
42
+
43
+ # Creates remember_token and remember_created_at.
44
+ #
45
+ def rememberable
46
+ string :remember_token, :limit => 20
47
+ datetime :remember_created_at
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,105 @@
1
+ module Devise
2
+ module Models
3
+ # Creates configuration values for Devise and for the given module.
4
+ #
5
+ # Devise::Models.config(Devise::Authenticable, :stretches, 10)
6
+ #
7
+ # The line above creates:
8
+ #
9
+ # 1) An accessor called Devise.stretches, which value is used by default;
10
+ #
11
+ # 2) Some class methods for your model Model.stretches and Model.stretches=
12
+ # which have higher priority than Devise.stretches;
13
+ #
14
+ # 3) And an instance method stretches.
15
+ #
16
+ # To add the class methods you need to have a module ClassMethods defined
17
+ # inside the given class.
18
+ #
19
+ def self.config(mod, accessor, default=nil) #:nodoc:
20
+ Devise.send :"#{accessor}=", default
21
+
22
+ mod.class_eval <<-METHOD, __FILE__, __LINE__
23
+ def #{accessor}
24
+ self.class.#{accessor}
25
+ end
26
+ METHOD
27
+
28
+ mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
29
+ def #{accessor}
30
+ if defined?(@#{accessor})
31
+ @#{accessor}
32
+ elsif superclass.respond_to?(:#{accessor})
33
+ superclass.#{accessor}
34
+ else
35
+ Devise.#{accessor}
36
+ end
37
+ end
38
+
39
+ def #{accessor}=(value)
40
+ @#{accessor} = value
41
+ end
42
+ METHOD
43
+ end
44
+
45
+ # Shortcut method for including all devise modules inside your model.
46
+ # You can give some extra options while declaring devise in your model:
47
+ #
48
+ # * except: convenient option that allows you to add all devise modules,
49
+ # removing only the modules you setup here:
50
+ #
51
+ # devise :all, :except => :rememberable
52
+ #
53
+ # You can also give the following configuration values in a hash: :pepper,
54
+ # :stretches, :confirm_within and :remember_for. Please check your Devise
55
+ # initialiazer for a complete description on those values.
56
+ #
57
+ # Examples:
58
+ #
59
+ # # include only authenticatable module (default)
60
+ # devise
61
+ #
62
+ # # include authenticatable + confirmable modules
63
+ # devise :confirmable
64
+ #
65
+ # # include authenticatable + recoverable modules
66
+ # devise :recoverable
67
+ #
68
+ # # include authenticatable + rememberable modules
69
+ # devise :rememberable
70
+ #
71
+ # # include authenticatable + validatable modules
72
+ # devise :validatable
73
+ #
74
+ # # include authenticatable + confirmable + recoverable + rememberable + validatable
75
+ # devise :confirmable, :recoverable, :rememberable, :validatable
76
+ #
77
+ # # shortcut to include all modules (same as above)
78
+ # devise :all
79
+ #
80
+ # # include all except recoverable
81
+ # devise :all, :except => :recoverable
82
+ #
83
+ def devise(*modules)
84
+ options = modules.extract_options!
85
+
86
+ modules = Devise::ALL if modules.include?(:all)
87
+ modules -= Array(options.delete(:except))
88
+ modules = [:authenticatable] | modules
89
+
90
+ modules.each do |m|
91
+ devise_modules << m.to_sym
92
+ include Devise::Models.const_get(m.to_s.classify)
93
+ end
94
+
95
+ # Convert new keys to methods which overwrites Devise defaults
96
+ options.each { |key, value| send(:"#{key}=", value) }
97
+ end
98
+
99
+ # Stores all modules included inside the model, so we are able to verify
100
+ # which routes are needed.
101
+ def devise_modules
102
+ @devise_modules ||= []
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,97 @@
1
+ require 'digest/sha1'
2
+ require 'devise/strategies/authenticatable'
3
+
4
+ module Devise
5
+ module Models
6
+
7
+ # Authenticable Module, responsible for encrypting password and validating
8
+ # authenticity of a user while signing in.
9
+ #
10
+ # Configuration:
11
+ #
12
+ # You can overwrite configuration values by setting in globally in Devise,
13
+ # using devise method or overwriting the respective instance method.
14
+ #
15
+ # pepper: encryption key used for creating encrypted password. Each time
16
+ # password changes, it's gonna be encrypted again, and this key
17
+ # is added to the password and salt to create a secure hash.
18
+ # Always use `rake secret' to generate a new key.
19
+ #
20
+ # stretches: defines how many times the password will be encrypted.
21
+ #
22
+ # Examples:
23
+ #
24
+ # User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
25
+ # User.find(1).valid_password?('password123') # returns true/false
26
+ #
27
+ module Authenticatable
28
+ def self.included(base)
29
+ base.class_eval do
30
+ extend ClassMethods
31
+
32
+ attr_reader :password
33
+ attr_accessor :password_confirmation
34
+ end
35
+ end
36
+
37
+ # Regenerates password salt and encrypted password each time password is
38
+ # setted.
39
+ def password=(new_password)
40
+ @password = new_password
41
+ self.password_salt = friendly_token
42
+ self.encrypted_password = password_digest(@password)
43
+ end
44
+
45
+ # Verifies whether an incoming_password (ie from login) is the user
46
+ # password.
47
+ def valid_password?(incoming_password)
48
+ password_digest(incoming_password) == encrypted_password
49
+ end
50
+
51
+ protected
52
+
53
+ # Gererates a default password digest based on salt, pepper and the
54
+ # incoming password.
55
+ def password_digest(password_to_digest)
56
+ digest = pepper
57
+ stretches.times { digest = secure_digest(password_salt, digest, password_to_digest, pepper) }
58
+ digest
59
+ end
60
+
61
+ # Generate a SHA1 digest joining args. Generated token is something like
62
+ #
63
+ # --arg1--arg2--arg3--argN--
64
+ def secure_digest(*tokens)
65
+ ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
66
+ end
67
+
68
+ # Generate a friendly string randomically to be used as token.
69
+ def friendly_token
70
+ ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
71
+ end
72
+
73
+ module ClassMethods
74
+ # Authenticate a user based on email and password. Returns the
75
+ # authenticated user if it's valid or nil.
76
+ # Attributes are :email and :password
77
+ def authenticate(attributes={})
78
+ authenticatable = find_by_email(attributes[:email])
79
+ authenticatable if authenticatable.try(:valid_password?, attributes[:password])
80
+ end
81
+
82
+ # Attempt to find a user by it's email. If not user is found, returns a
83
+ # new user with an email not found error.
84
+ def find_or_initialize_with_error_by_email(email)
85
+ perishable = find_or_initialize_by_email(email)
86
+ if perishable.new_record?
87
+ perishable.errors.add(:email, :not_found, :default => 'not found')
88
+ end
89
+ perishable
90
+ end
91
+ end
92
+
93
+ Devise::Models.config(self, :pepper)
94
+ Devise::Models.config(self, :stretches, 10)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,156 @@
1
+ require 'devise/hooks/confirmable'
2
+
3
+ module Devise
4
+ module Models
5
+
6
+ # Confirmable is responsible to verify if an account is already confirmed to
7
+ # sign in, and to send emails with confirmation instructions.
8
+ # Confirmation instructions are sent to the user email after creating a
9
+ # record, after updating it's email and also when manually requested by
10
+ # a new confirmation instruction request.
11
+ # Whenever the user update it's email, his account is automatically unconfirmed,
12
+ # it means it won't be able to sign in again without confirming the account
13
+ # again through the email that was sent.
14
+ #
15
+ # Configuration:
16
+ #
17
+ # confirm_within: the time you want the user will have to confirm it's account
18
+ # without blocking his access. When confirm_within is zero, the
19
+ # user won't be able to sign in without confirming. You can
20
+ # use this to let your user access some features of your
21
+ # application without confirming the account, but blocking it
22
+ # after a certain period (ie 7 days). By default confirm_within is
23
+ # zero, it means users always have to confirm to sign in.
24
+ #
25
+ # Examples:
26
+ #
27
+ # User.find(1).confirm! # returns true unless it's already confirmed
28
+ # User.find(1).confirmed? # true/false
29
+ # User.find(1).send_confirmation_instructions # manually send instructions
30
+ # User.find(1).reset_confirmation! # reset confirmation status and send instructions
31
+ module Confirmable
32
+
33
+ def self.included(base)
34
+ base.class_eval do
35
+ extend ClassMethods
36
+
37
+ before_create :generate_confirmation_token
38
+ after_create :send_confirmation_instructions
39
+ end
40
+ end
41
+
42
+ # Confirm a user by setting it's confirmed_at to actual time. If the user
43
+ # is already confirmed, add en error to email field
44
+ def confirm!
45
+ unless_confirmed do
46
+ self.confirmation_token = nil
47
+ self.confirmed_at = Time.now
48
+ save(false)
49
+ end
50
+ end
51
+
52
+ # Verifies whether a user is confirmed or not
53
+ def confirmed?
54
+ !new_record? && confirmed_at?
55
+ end
56
+
57
+ # Send confirmation instructions by email
58
+ def send_confirmation_instructions
59
+ ::DeviseMailer.deliver_confirmation_instructions(self)
60
+ end
61
+
62
+ # Remove confirmation date and send confirmation instructions, to ensure
63
+ # after sending these instructions the user won't be able to sign in without
64
+ # confirming it's account
65
+ def reset_confirmation!
66
+ unless_confirmed do
67
+ generate_confirmation_token
68
+ save(false)
69
+ send_confirmation_instructions
70
+ end
71
+ end
72
+
73
+ # Verify whether a user is active to sign in or not. If the user is
74
+ # already confirmed, it should never be blocked. Otherwise we need to
75
+ # calculate if the confirm time has not expired for this user, in other
76
+ # words, if the confirmation is still valid.
77
+ def active?
78
+ confirmed? || confirmation_period_valid?
79
+ end
80
+
81
+ protected
82
+
83
+ # Checks if the confirmation for the user is within the limit time.
84
+ # We do this by calculating if the difference between today and the
85
+ # confirmation sent date does not exceed the confirm in time configured.
86
+ # Confirm_in is a model configuration, must always be an integer value.
87
+ #
88
+ # Example:
89
+ #
90
+ # # confirm_within = 1.day and confirmation_sent_at = today
91
+ # confirmation_period_valid? # returns true
92
+ #
93
+ # # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
94
+ # confirmation_period_valid? # returns true
95
+ #
96
+ # # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
97
+ # confirmation_period_valid? # returns false
98
+ #
99
+ # # confirm_within = 0.days
100
+ # confirmation_period_valid? # will always return false
101
+ #
102
+ def confirmation_period_valid?
103
+ confirmation_sent_at? &&
104
+ (Time.now.utc - confirmation_sent_at.utc) < confirm_within
105
+ end
106
+
107
+ # Checks whether the record is confirmed or not, yielding to the block
108
+ # if it's already confirmed, otherwise adds an error to email.
109
+ def unless_confirmed
110
+ unless confirmed?
111
+ yield
112
+ else
113
+ errors.add(:email, :already_confirmed, :default => 'already confirmed')
114
+ false
115
+ end
116
+ end
117
+
118
+ # Generates a new random token for confirmation, and stores the time
119
+ # this token is being generated
120
+ def generate_confirmation_token
121
+ self.confirmed_at = nil
122
+ self.confirmation_token = friendly_token
123
+ self.confirmation_sent_at = Time.now.utc
124
+ end
125
+
126
+ module ClassMethods
127
+
128
+ # Attempt to find a user by it's email. If a record is found, send new
129
+ # confirmation instructions to it. If not user is found, returns a new user
130
+ # with an email not found error.
131
+ # Options must contain the user email
132
+ def send_confirmation_instructions(attributes={})
133
+ confirmable = find_or_initialize_with_error_by_email(attributes[:email])
134
+ confirmable.reset_confirmation! unless confirmable.new_record?
135
+ confirmable
136
+ end
137
+
138
+ # Find a user by it's confirmation token and try to confirm it.
139
+ # If no user is found, returns a new user with an error.
140
+ # If the user is already confirmed, create an error for the user
141
+ # Options must have the confirmation_token
142
+ def confirm!(attributes={})
143
+ confirmable = find_or_initialize_by_confirmation_token(attributes[:confirmation_token])
144
+ if confirmable.new_record?
145
+ confirmable.errors.add(:confirmation_token, :invalid)
146
+ else
147
+ confirmable.confirm!
148
+ end
149
+ confirmable
150
+ end
151
+ end
152
+
153
+ Devise::Models.config(self, :confirm_within, 0.days)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,88 @@
1
+ module Devise
2
+ module Models
3
+
4
+ # Recoverable takes care of reseting the user password and send reset instructions
5
+ # Examples:
6
+ #
7
+ # # resets the user password and save the record, true if valid passwords are given, otherwise false
8
+ # User.find(1).reset_password!('password123', 'password123')
9
+ # # only resets the user password, without saving the record
10
+ # user = User.find(1)
11
+ # user.reset_password('password123', 'password123')
12
+ # # creates a new token and send it with instructions about how to reset the password
13
+ # User.find(1).send_reset_password_instructions
14
+ module Recoverable
15
+ def self.included(base)
16
+ base.class_eval do
17
+ extend ClassMethods
18
+ end
19
+ end
20
+
21
+ # Update password
22
+ def reset_password(new_password, new_password_confirmation)
23
+ self.password = new_password
24
+ self.password_confirmation = new_password_confirmation
25
+ end
26
+
27
+ # Update password saving the record and clearing token. Returns true if
28
+ # the passwords are valid and the record was saved, false otherwise.
29
+ def reset_password!(new_password, new_password_confirmation)
30
+ reset_password(new_password, new_password_confirmation)
31
+ clear_reset_password_token if valid?
32
+ save
33
+ end
34
+
35
+ # Resets reset password token and send reset password instructions by email
36
+ def send_reset_password_instructions
37
+ generate_reset_password_token!
38
+ ::DeviseMailer.deliver_reset_password_instructions(self)
39
+ end
40
+
41
+ protected
42
+
43
+ # Generates a new random token for reset password
44
+ def generate_reset_password_token
45
+ self.reset_password_token = friendly_token
46
+ end
47
+
48
+ # Resets the reset password token with and save the record without
49
+ # validating
50
+ def generate_reset_password_token!
51
+ generate_reset_password_token && save(false)
52
+ end
53
+
54
+ # Removes reset_password token
55
+ def clear_reset_password_token
56
+ self.reset_password_token = nil
57
+ end
58
+
59
+ module ClassMethods
60
+
61
+ # Attempt to find a user by it's email. If a record is found, send new
62
+ # password instructions to it. If not user is found, returns a new user
63
+ # with an email not found error.
64
+ # Attributes must contain the user email
65
+ def send_reset_password_instructions(attributes={})
66
+ recoverable = find_or_initialize_with_error_by_email(attributes[:email])
67
+ recoverable.send_reset_password_instructions unless recoverable.new_record?
68
+ recoverable
69
+ end
70
+
71
+ # Attempt to find a user by it's reset_password_token to reset it's
72
+ # password. If a user is found, reset it's password and automatically
73
+ # try saving the record. If not user is found, returns a new user
74
+ # containing an error in reset_password_token attribute.
75
+ # Attributes must contain reset_password_token, password and confirmation
76
+ def reset_password!(attributes={})
77
+ recoverable = find_or_initialize_by_reset_password_token(attributes[:reset_password_token])
78
+ if recoverable.new_record?
79
+ recoverable.errors.add(:reset_password_token, :invalid)
80
+ else
81
+ recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
82
+ end
83
+ recoverable
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end