deviseOne 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +38 -0
  4. data/.yardopts +9 -0
  5. data/CHANGELOG.md +1117 -0
  6. data/CONTRIBUTING.md +14 -0
  7. data/Gemfile +29 -0
  8. data/Gemfile.lock +199 -0
  9. data/MIT-LICENSE +20 -0
  10. data/README.md +529 -0
  11. data/Rakefile +35 -0
  12. data/app/controllers/devise/confirmations_controller.rb +47 -0
  13. data/app/controllers/devise/omniauth_callbacks_controller.rb +30 -0
  14. data/app/controllers/devise/passwords_controller.rb +71 -0
  15. data/app/controllers/devise/registrations_controller.rb +143 -0
  16. data/app/controllers/devise/sessions_controller.rb +166 -0
  17. data/app/controllers/devise/unlocks_controller.rb +46 -0
  18. data/app/controllers/devise_controller.rb +193 -0
  19. data/app/helpers/devise_helper.rb +25 -0
  20. data/app/mailers/devise/mailer.rb +20 -0
  21. data/app/views/devise/confirmations/new.html.erb +16 -0
  22. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  23. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  24. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  25. data/app/views/devise/passwords/edit.html.erb +25 -0
  26. data/app/views/devise/passwords/new.html.erb +16 -0
  27. data/app/views/devise/registrations/edit.html.erb +39 -0
  28. data/app/views/devise/registrations/new.html.erb +29 -0
  29. data/app/views/devise/sessions/new.html.erb +27 -0
  30. data/app/views/devise/shared/_links.html.erb +21 -0
  31. data/app/views/devise/unlocks/new.html.erb +16 -0
  32. data/config/locales/en.yml +70 -0
  33. data/devise.gemspec +33 -0
  34. data/devise.png +0 -0
  35. data/gemfiles/Gemfile.rails-3.2-stable +29 -0
  36. data/gemfiles/Gemfile.rails-3.2-stable.lock +169 -0
  37. data/gemfiles/Gemfile.rails-4.0-stable +29 -0
  38. data/gemfiles/Gemfile.rails-4.0-stable.lock +165 -0
  39. data/gemfiles/Gemfile.rails-4.1-stable +29 -0
  40. data/gemfiles/Gemfile.rails-4.1-stable.lock +170 -0
  41. data/lib/devise.rb +499 -0
  42. data/lib/devise/controllers/helpers.rb +284 -0
  43. data/lib/devise/controllers/rememberable.rb +47 -0
  44. data/lib/devise/controllers/scoped_views.rb +17 -0
  45. data/lib/devise/controllers/sign_in_out.rb +102 -0
  46. data/lib/devise/controllers/store_location.rb +58 -0
  47. data/lib/devise/controllers/url_helpers.rb +69 -0
  48. data/lib/devise/delegator.rb +16 -0
  49. data/lib/devise/failure_app.rb +212 -0
  50. data/lib/devise/hooks/activatable.rb +10 -0
  51. data/lib/devise/hooks/csrf_cleaner.rb +7 -0
  52. data/lib/devise/hooks/forgetable.rb +9 -0
  53. data/lib/devise/hooks/lockable.rb +7 -0
  54. data/lib/devise/hooks/proxy.rb +21 -0
  55. data/lib/devise/hooks/rememberable.rb +7 -0
  56. data/lib/devise/hooks/timeoutable.rb +35 -0
  57. data/lib/devise/hooks/trackable.rb +9 -0
  58. data/lib/devise/mailers/helpers.rb +90 -0
  59. data/lib/devise/mapping.rb +175 -0
  60. data/lib/devise/models.rb +119 -0
  61. data/lib/devise/models/authenticatable.rb +290 -0
  62. data/lib/devise/models/confirmable.rb +305 -0
  63. data/lib/devise/models/database_authenticatable.rb +164 -0
  64. data/lib/devise/models/lockable.rb +196 -0
  65. data/lib/devise/models/omniauthable.rb +27 -0
  66. data/lib/devise/models/recoverable.rb +157 -0
  67. data/lib/devise/models/registerable.rb +25 -0
  68. data/lib/devise/models/rememberable.rb +142 -0
  69. data/lib/devise/models/timeoutable.rb +49 -0
  70. data/lib/devise/models/trackable.rb +38 -0
  71. data/lib/devise/models/validatable.rb +66 -0
  72. data/lib/devise/modules.rb +28 -0
  73. data/lib/devise/omniauth.rb +28 -0
  74. data/lib/devise/omniauth/config.rb +45 -0
  75. data/lib/devise/omniauth/url_helpers.rb +18 -0
  76. data/lib/devise/orm/active_record.rb +3 -0
  77. data/lib/devise/orm/mongoid.rb +3 -0
  78. data/lib/devise/parameter_filter.rb +40 -0
  79. data/lib/devise/parameter_sanitizer.rb +99 -0
  80. data/lib/devise/rails.rb +56 -0
  81. data/lib/devise/rails/routes.rb +495 -0
  82. data/lib/devise/rails/warden_compat.rb +22 -0
  83. data/lib/devise/strategies/authenticatable.rb +173 -0
  84. data/lib/devise/strategies/base.rb +20 -0
  85. data/lib/devise/strategies/database_authenticatable.rb +24 -0
  86. data/lib/devise/strategies/rememberable.rb +59 -0
  87. data/lib/devise/test_helpers.rb +132 -0
  88. data/lib/devise/time_inflector.rb +14 -0
  89. data/lib/devise/token_generator.rb +70 -0
  90. data/lib/devise/version.rb +3 -0
  91. data/lib/generators/active_record/devise_generator.rb +91 -0
  92. data/lib/generators/active_record/templates/migration.rb +18 -0
  93. data/lib/generators/active_record/templates/migration_existing.rb +25 -0
  94. data/lib/generators/devise/controllers_generator.rb +44 -0
  95. data/lib/generators/devise/devise_generator.rb +26 -0
  96. data/lib/generators/devise/install_generator.rb +29 -0
  97. data/lib/generators/devise/orm_helpers.rb +51 -0
  98. data/lib/generators/devise/views_generator.rb +135 -0
  99. data/lib/generators/mongoid/devise_generator.rb +55 -0
  100. data/lib/generators/templates/README +35 -0
  101. data/lib/generators/templates/controllers/README +14 -0
  102. data/lib/generators/templates/controllers/confirmations_controller.rb +28 -0
  103. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +28 -0
  104. data/lib/generators/templates/controllers/passwords_controller.rb +32 -0
  105. data/lib/generators/templates/controllers/registrations_controller.rb +60 -0
  106. data/lib/generators/templates/controllers/sessions_controller.rb +25 -0
  107. data/lib/generators/templates/controllers/unlocks_controller.rb +28 -0
  108. data/lib/generators/templates/devise.rb +263 -0
  109. data/lib/generators/templates/markerb/confirmation_instructions.markerb +5 -0
  110. data/lib/generators/templates/markerb/reset_password_instructions.markerb +8 -0
  111. data/lib/generators/templates/markerb/unlock_instructions.markerb +7 -0
  112. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +16 -0
  113. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +19 -0
  114. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +15 -0
  115. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +27 -0
  116. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +17 -0
  117. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +15 -0
  118. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +16 -0
  119. data/script/cached-bundle +49 -0
  120. data/script/s3-put +71 -0
  121. data/test/controllers/custom_registrations_controller_test.rb +35 -0
  122. data/test/controllers/custom_strategy_test.rb +62 -0
  123. data/test/controllers/helpers_test.rb +316 -0
  124. data/test/controllers/internal_helpers_test.rb +129 -0
  125. data/test/controllers/load_hooks_controller_test.rb +19 -0
  126. data/test/controllers/passwords_controller_test.rb +31 -0
  127. data/test/controllers/sessions_controller_test.rb +102 -0
  128. data/test/controllers/url_helpers_test.rb +65 -0
  129. data/test/delegator_test.rb +19 -0
  130. data/test/devise_test.rb +107 -0
  131. data/test/failure_app_test.rb +275 -0
  132. data/test/generators/active_record_generator_test.rb +109 -0
  133. data/test/generators/controllers_generator_test.rb +48 -0
  134. data/test/generators/devise_generator_test.rb +39 -0
  135. data/test/generators/install_generator_test.rb +13 -0
  136. data/test/generators/mongoid_generator_test.rb +23 -0
  137. data/test/generators/views_generator_test.rb +96 -0
  138. data/test/helpers/devise_helper_test.rb +49 -0
  139. data/test/integration/authenticatable_test.rb +731 -0
  140. data/test/integration/confirmable_test.rb +324 -0
  141. data/test/integration/database_authenticatable_test.rb +94 -0
  142. data/test/integration/http_authenticatable_test.rb +105 -0
  143. data/test/integration/lockable_test.rb +239 -0
  144. data/test/integration/omniauthable_test.rb +133 -0
  145. data/test/integration/recoverable_test.rb +334 -0
  146. data/test/integration/registerable_test.rb +361 -0
  147. data/test/integration/rememberable_test.rb +176 -0
  148. data/test/integration/timeoutable_test.rb +189 -0
  149. data/test/integration/trackable_test.rb +92 -0
  150. data/test/mailers/confirmation_instructions_test.rb +115 -0
  151. data/test/mailers/reset_password_instructions_test.rb +96 -0
  152. data/test/mailers/unlock_instructions_test.rb +91 -0
  153. data/test/mapping_test.rb +128 -0
  154. data/test/models/authenticatable_test.rb +23 -0
  155. data/test/models/confirmable_test.rb +461 -0
  156. data/test/models/database_authenticatable_test.rb +249 -0
  157. data/test/models/lockable_test.rb +328 -0
  158. data/test/models/omniauthable_test.rb +7 -0
  159. data/test/models/recoverable_test.rb +205 -0
  160. data/test/models/registerable_test.rb +7 -0
  161. data/test/models/rememberable_test.rb +198 -0
  162. data/test/models/serializable_test.rb +49 -0
  163. data/test/models/timeoutable_test.rb +51 -0
  164. data/test/models/trackable_test.rb +41 -0
  165. data/test/models/validatable_test.rb +127 -0
  166. data/test/models_test.rb +144 -0
  167. data/test/omniauth/config_test.rb +57 -0
  168. data/test/omniauth/url_helpers_test.rb +54 -0
  169. data/test/orm/active_record.rb +10 -0
  170. data/test/orm/mongoid.rb +13 -0
  171. data/test/parameter_sanitizer_test.rb +81 -0
  172. data/test/rails_app/Rakefile +6 -0
  173. data/test/rails_app/app/active_record/admin.rb +6 -0
  174. data/test/rails_app/app/active_record/shim.rb +2 -0
  175. data/test/rails_app/app/active_record/user.rb +6 -0
  176. data/test/rails_app/app/active_record/user_on_engine.rb +7 -0
  177. data/test/rails_app/app/active_record/user_on_main_app.rb +7 -0
  178. data/test/rails_app/app/controllers/admins/sessions_controller.rb +6 -0
  179. data/test/rails_app/app/controllers/admins_controller.rb +11 -0
  180. data/test/rails_app/app/controllers/application_controller.rb +12 -0
  181. data/test/rails_app/app/controllers/application_with_fake_engine.rb +30 -0
  182. data/test/rails_app/app/controllers/custom/registrations_controller.rb +21 -0
  183. data/test/rails_app/app/controllers/home_controller.rb +25 -0
  184. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  185. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  186. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +14 -0
  187. data/test/rails_app/app/controllers/users_controller.rb +31 -0
  188. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  189. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +3 -0
  190. data/test/rails_app/app/mailers/users/mailer.rb +3 -0
  191. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +4 -0
  192. data/test/rails_app/app/mongoid/admin.rb +29 -0
  193. data/test/rails_app/app/mongoid/shim.rb +23 -0
  194. data/test/rails_app/app/mongoid/user.rb +39 -0
  195. data/test/rails_app/app/mongoid/user_on_engine.rb +39 -0
  196. data/test/rails_app/app/mongoid/user_on_main_app.rb +39 -0
  197. data/test/rails_app/app/views/admins/index.html.erb +1 -0
  198. data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
  199. data/test/rails_app/app/views/home/admin_dashboard.html.erb +1 -0
  200. data/test/rails_app/app/views/home/index.html.erb +1 -0
  201. data/test/rails_app/app/views/home/join.html.erb +1 -0
  202. data/test/rails_app/app/views/home/private.html.erb +1 -0
  203. data/test/rails_app/app/views/home/user_dashboard.html.erb +1 -0
  204. data/test/rails_app/app/views/layouts/application.html.erb +24 -0
  205. data/test/rails_app/app/views/users/edit_form.html.erb +1 -0
  206. data/test/rails_app/app/views/users/index.html.erb +1 -0
  207. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +1 -0
  208. data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
  209. data/test/rails_app/bin/bundle +3 -0
  210. data/test/rails_app/bin/rails +4 -0
  211. data/test/rails_app/bin/rake +4 -0
  212. data/test/rails_app/config.ru +4 -0
  213. data/test/rails_app/config/application.rb +40 -0
  214. data/test/rails_app/config/boot.rb +14 -0
  215. data/test/rails_app/config/database.yml +18 -0
  216. data/test/rails_app/config/environment.rb +5 -0
  217. data/test/rails_app/config/environments/development.rb +30 -0
  218. data/test/rails_app/config/environments/production.rb +80 -0
  219. data/test/rails_app/config/environments/test.rb +36 -0
  220. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  221. data/test/rails_app/config/initializers/devise.rb +180 -0
  222. data/test/rails_app/config/initializers/inflections.rb +2 -0
  223. data/test/rails_app/config/initializers/secret_token.rb +8 -0
  224. data/test/rails_app/config/initializers/session_store.rb +1 -0
  225. data/test/rails_app/config/routes.rb +122 -0
  226. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +71 -0
  227. data/test/rails_app/db/schema.rb +55 -0
  228. data/test/rails_app/lib/shared_admin.rb +17 -0
  229. data/test/rails_app/lib/shared_user.rb +29 -0
  230. data/test/rails_app/lib/shared_user_without_omniauth.rb +13 -0
  231. data/test/rails_app/public/404.html +26 -0
  232. data/test/rails_app/public/422.html +26 -0
  233. data/test/rails_app/public/500.html +26 -0
  234. data/test/rails_app/public/favicon.ico +0 -0
  235. data/test/routes_test.rb +264 -0
  236. data/test/support/action_controller/record_identifier.rb +10 -0
  237. data/test/support/assertions.rb +39 -0
  238. data/test/support/helpers.rb +73 -0
  239. data/test/support/integration.rb +92 -0
  240. data/test/support/locale/en.yml +8 -0
  241. data/test/support/mongoid.yml +6 -0
  242. data/test/support/webrat/integrations/rails.rb +24 -0
  243. data/test/test_helper.rb +34 -0
  244. data/test/test_helpers_test.rb +163 -0
  245. data/test/test_models.rb +33 -0
  246. metadata +531 -0
@@ -0,0 +1,196 @@
1
+ require "devise/hooks/lockable"
2
+
3
+ module Devise
4
+ module Models
5
+ # Handles blocking a user access after a certain number of attempts.
6
+ # Lockable accepts two different strategies to unlock a user after it's
7
+ # blocked: email and time. The former will send an email to the user when
8
+ # the lock happens, containing a link to unlock its account. The second
9
+ # will unlock the user automatically after some configured time (ie 2.hours).
10
+ # It's also possible to setup lockable to use both email and time strategies.
11
+ #
12
+ # == Options
13
+ #
14
+ # Lockable adds the following options to +devise+:
15
+ #
16
+ # * +maximum_attempts+: how many attempts should be accepted before blocking the user.
17
+ # * +lock_strategy+: lock the user account by :failed_attempts or :none.
18
+ # * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
19
+ # * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
20
+ # * +unlock_keys+: the keys you want to use when locking and unlocking an account
21
+ #
22
+ module Lockable
23
+ extend ActiveSupport::Concern
24
+
25
+ delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, to: "self.class"
26
+
27
+ def self.required_fields(klass)
28
+ attributes = []
29
+ attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts)
30
+ attributes << :locked_at if klass.unlock_strategy_enabled?(:time)
31
+ attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)
32
+
33
+ attributes
34
+ end
35
+
36
+ # Lock a user setting its locked_at to actual time.
37
+ # * +opts+: Hash options if you don't want to send email
38
+ # when you lock access, you could pass the next hash
39
+ # `{ send_instructions: false } as option`.
40
+ def lock_access!(opts = { })
41
+ self.locked_at = Time.now.utc
42
+
43
+ if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true)
44
+ send_unlock_instructions
45
+ else
46
+ save(validate: false)
47
+ end
48
+ end
49
+
50
+ # Unlock a user by cleaning locked_at and failed_attempts.
51
+ def unlock_access!
52
+ self.locked_at = nil
53
+ self.failed_attempts = 0 if respond_to?(:failed_attempts=)
54
+ self.unlock_token = nil if respond_to?(:unlock_token=)
55
+ save(validate: false)
56
+ end
57
+
58
+ # Verifies whether a user is locked or not.
59
+ def access_locked?
60
+ !!locked_at && !lock_expired?
61
+ end
62
+
63
+ # Send unlock instructions by email
64
+ def send_unlock_instructions
65
+ raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
66
+ self.unlock_token = enc
67
+ self.save(validate: false)
68
+ send_devise_notification(:unlock_instructions, raw, {})
69
+ raw
70
+ end
71
+
72
+ # Resend the unlock instructions if the user is locked.
73
+ def resend_unlock_instructions
74
+ if_access_locked { send_unlock_instructions }
75
+ end
76
+
77
+ # Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes
78
+ # by verifying whether a user is active to sign in or not based on locked?
79
+ def active_for_authentication?
80
+ super && !access_locked?
81
+ end
82
+
83
+ # Overwrites invalid_message from Devise::Models::Authenticatable to define
84
+ # the correct reason for blocking the sign in.
85
+ def inactive_message
86
+ access_locked? ? :locked : super
87
+ end
88
+
89
+ # Overwrites valid_for_authentication? from Devise::Models::Authenticatable
90
+ # for verifying whether a user is allowed to sign in or not. If the user
91
+ # is locked, it should never be allowed.
92
+ def valid_for_authentication?
93
+ return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
94
+
95
+ # Unlock the user if the lock is expired, no matter
96
+ # if the user can login or not (wrong password, etc)
97
+ unlock_access! if lock_expired?
98
+
99
+ if super && !access_locked?
100
+ true
101
+ else
102
+ self.failed_attempts ||= 0
103
+ self.failed_attempts += 1
104
+ if attempts_exceeded?
105
+ lock_access! unless access_locked?
106
+ else
107
+ save(validate: false)
108
+ end
109
+ false
110
+ end
111
+ end
112
+
113
+ def unauthenticated_message
114
+ # If set to paranoid mode, do not show the locked message because it
115
+ # leaks the existence of an account.
116
+ if Devise.paranoid
117
+ super
118
+ elsif access_locked? || (lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?)
119
+ :locked
120
+ elsif lock_strategy_enabled?(:failed_attempts) && last_attempt? && self.class.last_attempt_warning
121
+ :last_attempt
122
+ else
123
+ super
124
+ end
125
+ end
126
+
127
+ protected
128
+
129
+ def attempts_exceeded?
130
+ self.failed_attempts >= self.class.maximum_attempts
131
+ end
132
+
133
+ def last_attempt?
134
+ self.failed_attempts == self.class.maximum_attempts - 1
135
+ end
136
+
137
+ # Tells if the lock is expired if :time unlock strategy is active
138
+ def lock_expired?
139
+ if unlock_strategy_enabled?(:time)
140
+ locked_at && locked_at < self.class.unlock_in.ago
141
+ else
142
+ false
143
+ end
144
+ end
145
+
146
+ # Checks whether the record is locked or not, yielding to the block
147
+ # if it's locked, otherwise adds an error to email.
148
+ def if_access_locked
149
+ if access_locked?
150
+ yield
151
+ else
152
+ self.errors.add(Devise.unlock_keys.first, :not_locked)
153
+ false
154
+ end
155
+ end
156
+
157
+ module ClassMethods
158
+ # Attempt to find a user by its unlock keys. If a record is found, send new
159
+ # unlock instructions to it. If not user is found, returns a new user
160
+ # with an email not found error.
161
+ # Options must contain the user's unlock keys
162
+ def send_unlock_instructions(attributes={})
163
+ lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
164
+ lockable.resend_unlock_instructions if lockable.persisted?
165
+ lockable
166
+ end
167
+
168
+ # Find a user by its unlock token and try to unlock it.
169
+ # If no user is found, returns a new user with an error.
170
+ # If the user is not locked, creates an error for the user
171
+ # Options must have the unlock_token
172
+ def unlock_access_by_token(unlock_token)
173
+ original_token = unlock_token
174
+ unlock_token = Devise.token_generator.digest(self, :unlock_token, unlock_token)
175
+
176
+ lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
177
+ lockable.unlock_access! if lockable.persisted?
178
+ lockable.unlock_token = original_token
179
+ lockable
180
+ end
181
+
182
+ # Is the unlock enabled for the given unlock strategy?
183
+ def unlock_strategy_enabled?(strategy)
184
+ [:both, strategy].include?(self.unlock_strategy)
185
+ end
186
+
187
+ # Is the lock enabled for the given lock strategy?
188
+ def lock_strategy_enabled?(strategy)
189
+ self.lock_strategy == strategy
190
+ end
191
+
192
+ Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys, :last_attempt_warning)
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,27 @@
1
+ require 'devise/omniauth'
2
+
3
+ module Devise
4
+ module Models
5
+ # Adds OmniAuth support to your model.
6
+ #
7
+ # == Options
8
+ #
9
+ # Oauthable adds the following options to devise_for:
10
+ #
11
+ # * +omniauth_providers+: Which providers are available to this model. It expects an array:
12
+ #
13
+ # devise_for :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
14
+ #
15
+ module Omniauthable
16
+ extend ActiveSupport::Concern
17
+
18
+ def self.required_fields(klass)
19
+ []
20
+ end
21
+
22
+ module ClassMethods
23
+ Devise::Models.config(self, :omniauth_providers)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,157 @@
1
+ module Devise
2
+ module Models
3
+
4
+ # Recoverable takes care of resetting the user password and send reset instructions.
5
+ #
6
+ # ==Options
7
+ #
8
+ # Recoverable adds the following options to devise_for:
9
+ #
10
+ # * +reset_password_keys+: the keys you want to use when recovering the password for an account
11
+ #
12
+ # == Examples
13
+ #
14
+ # # resets the user password and save the record, true if valid passwords are given, otherwise false
15
+ # User.find(1).reset_password!('password123', 'password123')
16
+ #
17
+ # # only resets the user password, without saving the record
18
+ # user = User.find(1)
19
+ # user.reset_password('password123', 'password123')
20
+ #
21
+ # # creates a new token and send it with instructions about how to reset the password
22
+ # User.find(1).send_reset_password_instructions
23
+ #
24
+ module Recoverable
25
+ extend ActiveSupport::Concern
26
+
27
+ def self.required_fields(klass)
28
+ [:reset_password_sent_at, :reset_password_token]
29
+ end
30
+
31
+ # Update password saving the record and clearing token. Returns true if
32
+ # the passwords are valid and the record was saved, false otherwise.
33
+ def reset_password!(new_password, new_password_confirmation)
34
+ self.password = new_password
35
+ self.password_confirmation = new_password_confirmation
36
+
37
+ if valid?
38
+ clear_reset_password_token
39
+ after_password_reset
40
+ end
41
+
42
+ save
43
+ end
44
+
45
+ # Resets reset password token and send reset password instructions by email.
46
+ # Returns the token sent in the e-mail.
47
+ def send_reset_password_instructions
48
+ token = set_reset_password_token
49
+ send_reset_password_instructions_notification(token)
50
+
51
+ token
52
+ end
53
+
54
+ # Checks if the reset password token sent is within the limit time.
55
+ # We do this by calculating if the difference between today and the
56
+ # sending date does not exceed the confirm in time configured.
57
+ # Returns true if the resource is not responding to reset_password_sent_at at all.
58
+ # reset_password_within is a model configuration, must always be an integer value.
59
+ #
60
+ # Example:
61
+ #
62
+ # # reset_password_within = 1.day and reset_password_sent_at = today
63
+ # reset_password_period_valid? # returns true
64
+ #
65
+ # # reset_password_within = 5.days and reset_password_sent_at = 4.days.ago
66
+ # reset_password_period_valid? # returns true
67
+ #
68
+ # # reset_password_within = 5.days and reset_password_sent_at = 5.days.ago
69
+ # reset_password_period_valid? # returns false
70
+ #
71
+ # # reset_password_within = 0.days
72
+ # reset_password_period_valid? # will always return false
73
+ #
74
+ def reset_password_period_valid?
75
+ reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
76
+ end
77
+
78
+ protected
79
+
80
+ # Removes reset_password token
81
+ def clear_reset_password_token
82
+ self.reset_password_token = nil
83
+ self.reset_password_sent_at = nil
84
+ end
85
+
86
+ # A callback initiated after password is successfully reset. This can
87
+ # be used to insert your own logic that is only run after the user
88
+ # successfully resets their password.
89
+ #
90
+ # Example:
91
+ #
92
+ # def after_password_reset
93
+ # self.update_attribute(:invite_code, nil)
94
+ # end
95
+ #
96
+ def after_password_reset
97
+ end
98
+
99
+ def set_reset_password_token
100
+ raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
101
+
102
+ self.reset_password_token = enc
103
+ self.reset_password_sent_at = Time.now.utc
104
+ self.save(validate: false)
105
+ raw
106
+ end
107
+
108
+ def send_reset_password_instructions_notification(token)
109
+ send_devise_notification(:reset_password_instructions, token, {})
110
+ end
111
+
112
+ module ClassMethods
113
+ # Attempt to find a user by password reset token. If a user is found, return it
114
+ # If a user is not found, return nil
115
+ def with_reset_password_token(token)
116
+ reset_password_token = Devise.token_generator.digest(self, :reset_password_token, token)
117
+ to_adapter.find_first(reset_password_token: reset_password_token)
118
+ end
119
+
120
+ # Attempt to find a user by its email. If a record is found, send new
121
+ # password instructions to it. If user is not found, returns a new user
122
+ # with an email not found error.
123
+ # Attributes must contain the user's email
124
+ def send_reset_password_instructions(attributes={})
125
+ recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
126
+ recoverable.send_reset_password_instructions if recoverable.persisted?
127
+ recoverable
128
+ end
129
+
130
+ # Attempt to find a user by its reset_password_token to reset its
131
+ # password. If a user is found and token is still valid, reset its password and automatically
132
+ # try saving the record. If not user is found, returns a new user
133
+ # containing an error in reset_password_token attribute.
134
+ # Attributes must contain reset_password_token, password and confirmation
135
+ def reset_password_by_token(attributes={})
136
+ original_token = attributes[:reset_password_token]
137
+ reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
138
+
139
+ recoverable = find_or_initialize_with_error_by(:reset_password_token, reset_password_token)
140
+
141
+ if recoverable.persisted?
142
+ if recoverable.reset_password_period_valid?
143
+ recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
144
+ else
145
+ recoverable.errors.add(:reset_password_token, :expired)
146
+ end
147
+ end
148
+
149
+ recoverable.reset_password_token = original_token if recoverable.reset_password_token.present?
150
+ recoverable
151
+ end
152
+
153
+ Devise::Models.config(self, :reset_password_keys, :reset_password_within)
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,25 @@
1
+ module Devise
2
+ module Models
3
+ # Registerable is responsible for everything related to registering a new
4
+ # resource (ie user sign up).
5
+ module Registerable
6
+ extend ActiveSupport::Concern
7
+
8
+ def self.required_fields(klass)
9
+ []
10
+ end
11
+
12
+ module ClassMethods
13
+ # A convenience method that receives both parameters and session to
14
+ # initialize a user. This can be used by OAuth, for example, to send
15
+ # in the user token and be stored on initialization.
16
+ #
17
+ # By default discards all information sent by the session by calling
18
+ # new with params.
19
+ def new_with_session(params, session)
20
+ new(params)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,142 @@
1
+ require 'devise/strategies/rememberable'
2
+ require 'devise/hooks/rememberable'
3
+ require 'devise/hooks/forgetable'
4
+
5
+ module Devise
6
+ module Models
7
+ # Rememberable manages generating and clearing token for remember the user
8
+ # from a saved cookie. Rememberable also has utility methods for dealing
9
+ # with serializing the user into the cookie and back from the cookie, trying
10
+ # to lookup the record based on the saved information.
11
+ # You probably wouldn't use rememberable methods directly, they are used
12
+ # mostly internally for handling the remember token.
13
+ #
14
+ # == Options
15
+ #
16
+ # Rememberable adds the following options in devise_for:
17
+ #
18
+ # * +remember_for+: the time you want the user will be remembered without
19
+ # asking for credentials. After this time the user will be blocked and
20
+ # will have to enter their credentials again. This configuration is also
21
+ # used to calculate the expires time for the cookie created to remember
22
+ # the user. By default remember_for is 2.weeks.
23
+ #
24
+ # * +extend_remember_period+: if true, extends the user's remember period
25
+ # when remembered via cookie. False by default.
26
+ #
27
+ # * +rememberable_options+: configuration options passed to the created cookie.
28
+ #
29
+ # == Examples
30
+ #
31
+ # User.find(1).remember_me! # regenerating the token
32
+ # User.find(1).forget_me! # clearing the token
33
+ #
34
+ # # generating info to put into cookies
35
+ # User.serialize_into_cookie(user)
36
+ #
37
+ # # lookup the user based on the incoming cookie information
38
+ # User.serialize_from_cookie(cookie_string)
39
+ module Rememberable
40
+ extend ActiveSupport::Concern
41
+
42
+ attr_accessor :remember_me, :extend_remember_period
43
+
44
+ def self.required_fields(klass)
45
+ [:remember_created_at]
46
+ end
47
+
48
+ # Generate a new remember token and save the record without validations
49
+ # if remember expired (token is no longer valid) or extend_remember_period is true
50
+ def remember_me!(extend_period=false)
51
+ self.remember_token = self.class.remember_token if generate_remember_token?
52
+ self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
53
+ save(validate: false) if self.changed?
54
+ end
55
+
56
+ # If the record is persisted, remove the remember token (but only if
57
+ # it exists), and save the record without validations.
58
+ def forget_me!
59
+ return unless persisted?
60
+ self.remember_token = nil if respond_to?(:remember_token=)
61
+ self.remember_created_at = nil if self.class.expire_all_remember_me_on_sign_out
62
+ save(validate: false)
63
+ end
64
+
65
+ # Remember token should be expired if expiration time not overpass now.
66
+ def remember_expired?
67
+ remember_created_at.nil? || (remember_expires_at <= Time.now.utc)
68
+ end
69
+
70
+ # Remember token expires at created time + remember_for configuration
71
+ def remember_expires_at
72
+ remember_created_at + self.class.remember_for
73
+ end
74
+
75
+ def rememberable_value
76
+ if respond_to?(:remember_token)
77
+ remember_token
78
+ elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
79
+ salt
80
+ else
81
+ raise "authenticable_salt returned nil for the #{self.class.name} model. " \
82
+ "In order to use rememberable, you must ensure a password is always set " \
83
+ "or have a remember_token column in your model or implement your own " \
84
+ "rememberable_value in the model with custom logic."
85
+ end
86
+ end
87
+
88
+ def rememberable_options
89
+ self.class.rememberable_options
90
+ end
91
+
92
+ # A callback initiated after successfully being remembered. This can be
93
+ # used to insert your own logic that is only run after the user is
94
+ # remembered.
95
+ #
96
+ # Example:
97
+ #
98
+ # def after_remembered
99
+ # self.update_attribute(:invite_code, nil)
100
+ # end
101
+ #
102
+ def after_remembered
103
+ end
104
+
105
+ protected
106
+
107
+ def generate_remember_token? #:nodoc:
108
+ respond_to?(:remember_token) && remember_expired?
109
+ end
110
+
111
+ # Generate a timestamp if extend_remember_period is true, if no remember_token
112
+ # exists, or if an existing remember token has expired.
113
+ def generate_remember_timestamp?(extend_period) #:nodoc:
114
+ extend_period || remember_created_at.nil? || remember_expired?
115
+ end
116
+
117
+ module ClassMethods
118
+ # Create the cookie key using the record id and remember_token
119
+ def serialize_into_cookie(record)
120
+ [record.to_key, record.rememberable_value]
121
+ end
122
+
123
+ # Recreate the user based on the stored cookie
124
+ def serialize_from_cookie(id, remember_token)
125
+ record = to_adapter.get(id)
126
+ record if record && !record.remember_expired? &&
127
+ Devise.secure_compare(record.rememberable_value, remember_token)
128
+ end
129
+
130
+ # Generate a token checking if one does not already exist in the database.
131
+ def remember_token #:nodoc:
132
+ loop do
133
+ token = Devise.friendly_token
134
+ break token unless to_adapter.find_first({ remember_token: token })
135
+ end
136
+ end
137
+
138
+ Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options, :expire_all_remember_me_on_sign_out)
139
+ end
140
+ end
141
+ end
142
+ end