mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-11 15:58:12 -05:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91ba14e77e | ||
|
|
2cab75d72b | ||
|
|
b37a74533d | ||
|
|
939d0f25c5 | ||
|
|
61929d2e2f | ||
|
|
a7658f9d75 | ||
|
|
033e91b7b9 | ||
|
|
68de34c03e | ||
|
|
94c05e346d | ||
|
|
45298c0a37 | ||
|
|
c12fc1afea | ||
|
|
136b5b0be9 | ||
|
|
9203651110 | ||
|
|
a394ceaef1 | ||
|
|
0ab28ef8ee | ||
|
|
b928b8b3a2 | ||
|
|
075fc96f10 | ||
|
|
15f6255c7c | ||
|
|
2b79519ad1 | ||
|
|
617a8876a6 | ||
|
|
7b7af57813 | ||
|
|
a12f6ec70c | ||
|
|
fffc3b1e0e | ||
|
|
af12ec2b01 | ||
|
|
ecfc7d752a | ||
|
|
bc096994b0 | ||
|
|
ba80074b7b | ||
|
|
f04d883ac1 | ||
|
|
9bf718dd82 | ||
|
|
643d5600b2 | ||
|
|
1edae9c6c1 | ||
|
|
b41e5f5bf6 | ||
|
|
2f6ecc1328 | ||
|
|
b93288875f | ||
|
|
bb4f699d03 | ||
|
|
f1d991fa8b | ||
|
|
4ce7854f44 | ||
|
|
5ef35ee1bd | ||
|
|
6d5bccc050 | ||
|
|
3ac2c1dd18 | ||
|
|
07a41ecf6f | ||
|
|
61e85a578e | ||
|
|
88d68587e1 | ||
|
|
23ae04e6cb | ||
|
|
64c05f2ce9 | ||
|
|
c5cb60a752 | ||
|
|
803e4f5524 | ||
|
|
a909bfaf85 | ||
|
|
bc11e9f300 | ||
|
|
e3412d4207 | ||
|
|
faf8b01ecc | ||
|
|
d7337c5b26 | ||
|
|
2ab1086b80 | ||
|
|
85f2f88c59 | ||
|
|
ce3422e75a | ||
|
|
bee87843b4 | ||
|
|
18aef6ac33 | ||
|
|
890f6031c3 | ||
|
|
f3bace570d | ||
|
|
533511f8c3 | ||
|
|
6489354b0e | ||
|
|
1bbae013cc | ||
|
|
8ac8129fe7 | ||
|
|
9667a38bc9 | ||
|
|
e3df7f033e | ||
|
|
989fd92b84 | ||
|
|
de24170a79 | ||
|
|
5a0548621f | ||
|
|
0f8e472dab | ||
|
|
b190fa38c7 | ||
|
|
b0b01dae81 | ||
|
|
f2b4ba6110 | ||
|
|
d15d0ba6a5 | ||
|
|
fc3af50b55 | ||
|
|
a0a141b457 | ||
|
|
0315ca2701 |
@@ -1,5 +1,4 @@
|
||||
script: "bundle exec rake test"
|
||||
before_install: gem update --system
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
|
||||
@@ -1,4 +1,25 @@
|
||||
== 2.0.3
|
||||
== 2.1.0.dev
|
||||
|
||||
* enhancements
|
||||
* Add check_fields! method on Devise::Models to check if the model includes the fields that Devise uses
|
||||
* Add `skip_reconfirmation!` to skip reconfirmation
|
||||
|
||||
* bug fix
|
||||
* Ensure after sign in hook is not called without a resource
|
||||
* Fix a term: now on Omniauth related flash messages, we say that we're authenticating from an omniauth provider instead of authorizing
|
||||
|
||||
* deprecation
|
||||
* All devise modules should have a required_fields(klass) module method to help gathering missing attributes
|
||||
|
||||
== 2.0.4
|
||||
|
||||
Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
|
||||
|
||||
* bug fix
|
||||
* Fix when :host is used with devise_for (by @mreinsch)
|
||||
* Fix a regression that caused Warden to be initialized too late
|
||||
|
||||
== 2.0.3 (yanked)
|
||||
|
||||
* bug fix
|
||||
* Ensure warning is not shown by mistake on apps with mounted engines
|
||||
@@ -8,8 +29,6 @@
|
||||
|
||||
== 2.0.2
|
||||
|
||||
Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
|
||||
|
||||
* enhancements
|
||||
* Add devise_i18n_options to customize I18n message
|
||||
|
||||
@@ -114,7 +133,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
|
||||
* bug fix
|
||||
* Fix backward incompatible change from 1.4.6 for those using custom controllers
|
||||
|
||||
== 1.4.6
|
||||
== 1.4.6 (yanked)
|
||||
|
||||
* enhancements
|
||||
* Allow devise_for :skip => :all
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
devise (2.0.2)
|
||||
devise (2.0.4)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.0.3)
|
||||
railties (~> 3.1)
|
||||
|
||||
24
README.md
24
README.md
@@ -1,4 +1,4 @@
|
||||
*IMPORTANT:* Devise 2.0.0 is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
|
||||
*IMPORTANT:* Devise 2.0 is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
|
||||
|
||||
## Devise
|
||||
|
||||
@@ -109,6 +109,8 @@ rails generate devise MODEL
|
||||
|
||||
Replace MODEL by the class name used for the applications users, it's frequently 'User' but could also be 'Admin'. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run "rake db:migrate" as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file to point to Devise controller.
|
||||
|
||||
Note that you should re-start your app here if you've already started it. Otherwise you'll run into strange errors like users being unable to login and the route helpers being undefined.
|
||||
|
||||
### Controller filters and helpers
|
||||
|
||||
Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_filter:
|
||||
@@ -135,13 +137,13 @@ You can access the session for this scope:
|
||||
user_session
|
||||
```
|
||||
|
||||
After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect. Example: For a :user resource, it will use +user_root_path+ if it exists, otherwise default +root_path+ will be used. This means that you need to set the root inside your routes:
|
||||
After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect. Example: For a :user resource, it will use `user_root_path` if it exists, otherwise default `root_path` will be used. This means that you need to set the root inside your routes:
|
||||
|
||||
```ruby
|
||||
root :to => "home#index"
|
||||
```
|
||||
|
||||
You can also overwrite +after_sign_in_path_for+ and +after_sign_out_path_for+ to customize your redirect hooks.
|
||||
You can also overwrite `after_sign_in_path_for` and `after_sign_out_path_for` to customize your redirect hooks.
|
||||
|
||||
Finally, you need to set up default url options for the mailer in each environment. Here is the configuration for "config/environments/development.rb":
|
||||
|
||||
@@ -247,9 +249,9 @@ Devise also ships with default routes. If you need to customize them, you should
|
||||
devise_for :users, :path => "usuarios", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
|
||||
```
|
||||
|
||||
Be sure to check +devise_for+ documentation for details.
|
||||
Be sure to check `devise_for` documentation for details.
|
||||
|
||||
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a +devise_scope+ block in the router:
|
||||
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a `devise_scope` block in the router:
|
||||
|
||||
```ruby
|
||||
devise_scope :user do
|
||||
@@ -257,15 +259,7 @@ devise_scope :user do
|
||||
end
|
||||
```
|
||||
|
||||
This way you tell devise to use the scope :user when "/sign_in" is accessed. Notice +devise_scope+ is also aliased as +as+ and you can also give a block to +devise_for+, resulting in the same behavior:
|
||||
|
||||
```ruby
|
||||
devise_for :users do
|
||||
get "sign_in", :to => "devise/sessions#new"
|
||||
end
|
||||
```
|
||||
|
||||
Feel free to choose the one you prefer!
|
||||
This way you tell devise to use the scope :user when "/sign_in" is accessed. Notice `devise_scope` is also aliased as `as` in your router.
|
||||
|
||||
### I18n
|
||||
|
||||
@@ -327,7 +321,7 @@ class ActionController::TestCase
|
||||
end
|
||||
```
|
||||
|
||||
If you're using RSpec and want the helpers automatically included within all +describe+ blocks, add a file called spec/support/devise.rb with the following contents:
|
||||
If you're using RSpec and want the helpers automatically included within all `describe` blocks, add a file called spec/support/devise.rb with the following contents:
|
||||
|
||||
```ruby
|
||||
RSpec.configure do |config|
|
||||
|
||||
@@ -89,8 +89,7 @@ MESSAGE
|
||||
warden.authenticated?(resource_name)
|
||||
end
|
||||
|
||||
if authenticated
|
||||
resource = warden.user(resource_name)
|
||||
if authenticated && resource = warden.user(resource_name)
|
||||
flash[:alert] = I18n.t("devise.failure.already_authenticated")
|
||||
redirect_to after_sign_in_path_for(resource)
|
||||
end
|
||||
@@ -162,4 +161,4 @@ MESSAGE
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,25 +1,3 @@
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% ActiveSupport::Deprecation.warn "Rendering partials devise/_links.erb is deprecated" \
|
||||
"please use devise/shared/_links.erb instead."%>
|
||||
<%= render "shared/links" %>
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
<div><%= f.submit "Resend confirmation instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -13,4 +13,4 @@
|
||||
<div><%= f.submit "Change my password" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -9,4 +9,4 @@
|
||||
<div><%= f.submit "Send me reset password instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -15,4 +15,4 @@
|
||||
<div><%= f.submit "Sign up" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
<div><%= f.submit "Sign in" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -1,3 +1,25 @@
|
||||
<% ActiveSupport::Deprecation.warn "Rendering partials devise/shared/_links.erb is deprecated" \
|
||||
"please use devise/_links.erb instead." %>
|
||||
<%= render "links" %>
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
@@ -9,4 +9,4 @@
|
||||
<div><%= f.submit "Resend unlock instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -46,8 +46,8 @@ en:
|
||||
unlocked: 'Your account has been unlocked successfully. Please sign in to continue.'
|
||||
send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.'
|
||||
omniauth_callbacks:
|
||||
success: 'Successfully authorized from %{kind} account.'
|
||||
failure: 'Could not authorize you from %{kind} because "%{reason}".'
|
||||
success: 'Successfully authenticated from %{kind} account.'
|
||||
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
|
||||
mailer:
|
||||
confirmation_instructions:
|
||||
subject: 'Confirmation instructions'
|
||||
|
||||
@@ -23,6 +23,7 @@ module Devise
|
||||
module Encryptors
|
||||
autoload :Base, 'devise/encryptors/base'
|
||||
autoload :AuthlogicSha512, 'devise/encryptors/authlogic_sha512'
|
||||
autoload :BCrypt, 'devise/encryptors/bcrypt'
|
||||
autoload :ClearanceSha1, 'devise/encryptors/clearance_sha1'
|
||||
autoload :RestfulAuthenticationSha1, 'devise/encryptors/restful_authentication_sha1'
|
||||
autoload :Sha512, 'devise/encryptors/sha512'
|
||||
|
||||
@@ -208,7 +208,7 @@ module Devise
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
# publisher_url
|
||||
# else
|
||||
# signed_in_root_path(resource)
|
||||
# super
|
||||
# end
|
||||
# end
|
||||
#
|
||||
|
||||
@@ -15,6 +15,10 @@ module Devise
|
||||
def self.salt(stretches)
|
||||
Devise.friendly_token[0,20]
|
||||
end
|
||||
|
||||
def self.compare(encrypted_password, password, stretches, salt, pepper)
|
||||
Devise.secure_compare(encrypted_password, digest(password, stretches, salt, pepper))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
14
lib/devise/encryptors/bcrypt.rb
Normal file
14
lib/devise/encryptors/bcrypt.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Devise
|
||||
module Encryptors
|
||||
class BCrypt < Base
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
::BCrypt::Engine.hash_secret("#{password}#{pepper}",salt, stretches)
|
||||
end
|
||||
|
||||
def self.compare(encrypted_password, password, stretches, salt, pepper)
|
||||
salt = ::BCrypt::Password.new(encrypted_password).salt
|
||||
Devise.secure_compare(encrypted_password, digest(password, stretches, salt, pepper))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -88,6 +88,7 @@ module Devise
|
||||
opts = {}
|
||||
route = :"new_#{scope}_session_path"
|
||||
opts[:format] = request_format unless skip_format?
|
||||
opts[:script_name] = nil
|
||||
|
||||
context = send(Devise.available_router_name)
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
module Devise
|
||||
module Models
|
||||
class MissingAttribute < StandardError
|
||||
def initialize(attributes)
|
||||
@attributes = attributes
|
||||
end
|
||||
|
||||
def message
|
||||
"The following attribute(s) is (are) missing on your model: #{@attributes.join(", ")}"
|
||||
end
|
||||
end
|
||||
|
||||
# Creates configuration values for Devise and for the given module.
|
||||
#
|
||||
# Devise::Models.config(Devise::Authenticatable, :stretches, 10)
|
||||
@@ -39,6 +49,26 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
def self.check_fields!(klass)
|
||||
failed_attributes = []
|
||||
|
||||
klass.devise_modules.each do |mod|
|
||||
instance = klass.new
|
||||
|
||||
if const_get(mod.to_s.classify).respond_to?(:required_fields)
|
||||
const_get(mod.to_s.classify).required_fields(klass).each do |field|
|
||||
failed_attributes << field unless instance.respond_to?(field)
|
||||
end
|
||||
else
|
||||
ActiveSupport::Deprecation.warn "The module #{mod} doesn't implement self.required_fields(klass). Devise uses required_fields to warn developers of any missing fields in their models. Please implement #{mod}.required_fields(klass) that returns an array of symbols with the required fields."
|
||||
end
|
||||
end
|
||||
|
||||
if failed_attributes.any?
|
||||
fail Devise::Models::MissingAttribute.new(failed_attributes)
|
||||
end
|
||||
end
|
||||
|
||||
# Include the chosen devise modules in your model:
|
||||
#
|
||||
# devise :database_authenticatable, :confirmable, :recoverable
|
||||
@@ -66,7 +96,7 @@ module Devise
|
||||
if class_mod.respond_to?(:available_configs)
|
||||
available_configs = class_mod.available_configs
|
||||
available_configs.each do |config|
|
||||
next unless options.key?(config)
|
||||
next unless options.key?(config)
|
||||
send(:"#{config}=", options.delete(config))
|
||||
end
|
||||
end
|
||||
@@ -88,4 +118,4 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
require 'devise/models/authenticatable'
|
||||
require 'devise/models/authenticatable'
|
||||
|
||||
@@ -64,6 +64,10 @@ module Devise
|
||||
before_validation :strip_whitespace
|
||||
end
|
||||
|
||||
def self.required_fields(klass)
|
||||
[]
|
||||
end
|
||||
|
||||
# Check if the current object is valid for authentication. This method and
|
||||
# find_for_authentication are the methods used in a Warden::Strategy to check
|
||||
# if a model should be signed in or not.
|
||||
@@ -74,6 +78,10 @@ module Devise
|
||||
block_given? ? yield : true
|
||||
end
|
||||
|
||||
def unauthenticated_message
|
||||
:invalid
|
||||
end
|
||||
|
||||
def active_for_authentication?
|
||||
true
|
||||
end
|
||||
@@ -210,4 +218,4 @@ module Devise
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,15 @@ module Devise
|
||||
after_update :send_confirmation_instructions, :if => :reconfirmation_required?
|
||||
end
|
||||
|
||||
def self.required_fields(klass)
|
||||
required_methods = [:confirmation_token, :confirmed_at, :confirmation_sent_at]
|
||||
if klass.reconfirmable
|
||||
required_methods << :unconfirmed_email
|
||||
end
|
||||
|
||||
required_methods
|
||||
end
|
||||
|
||||
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
||||
# is already confirmed, add an error to email field. If the user is invalid
|
||||
# add errors
|
||||
@@ -45,7 +54,7 @@ module Devise
|
||||
self.confirmed_at = Time.now.utc
|
||||
|
||||
if self.class.reconfirmable && unconfirmed_email.present?
|
||||
@bypass_postpone = true
|
||||
skip_reconfirmation!
|
||||
self.email = unconfirmed_email
|
||||
self.unconfirmed_email = nil
|
||||
|
||||
@@ -99,6 +108,12 @@ module Devise
|
||||
self.confirmed_at = Time.now.utc
|
||||
end
|
||||
|
||||
# If you don't want reconfirmation to be sent, neither a code
|
||||
# to be generated, call skip_reconfirmation!
|
||||
def skip_reconfirmation!
|
||||
@bypass_postpone = true
|
||||
end
|
||||
|
||||
def headers_for(action)
|
||||
headers = super
|
||||
if action == :confirmation_instructions && pending_reconfirmation?
|
||||
|
||||
@@ -27,6 +27,10 @@ module Devise
|
||||
attr_accessor :password_confirmation
|
||||
end
|
||||
|
||||
def self.required_fields(klass)
|
||||
[:encrypted_password] + klass.authentication_keys
|
||||
end
|
||||
|
||||
# Generates password encryption based on the given value.
|
||||
def password=(new_password)
|
||||
@password = new_password
|
||||
@@ -36,9 +40,7 @@ module Devise
|
||||
# Verifies whether an password (ie from sign in) is the user password.
|
||||
def valid_password?(password)
|
||||
return false if encrypted_password.blank?
|
||||
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
|
||||
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
|
||||
Devise.secure_compare(password, self.encrypted_password)
|
||||
encryptor_class.compare(encrypted_password, password, self.class.stretches, authenticatable_salt, self.class.pepper)
|
||||
end
|
||||
|
||||
# Set password and password confirmation to nil
|
||||
@@ -96,14 +98,18 @@ module Devise
|
||||
|
||||
# A reliable way to expose the salt regardless of the implementation.
|
||||
def authenticatable_salt
|
||||
self.encrypted_password[0,29] if self.encrypted_password
|
||||
encrypted_password[0,29] if encrypted_password
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Digests the password using bcrypt.
|
||||
def password_digest(password)
|
||||
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
|
||||
encryptor_class.digest(password, self.class.stretches, ::BCrypt::Engine.generate_salt, self.class.pepper)
|
||||
end
|
||||
|
||||
def encryptor_class
|
||||
Devise::Encryptors::BCrypt
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -2,7 +2,8 @@ require 'devise/strategies/database_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Encryptable Module adds support to several encryptors.
|
||||
# Encryptable module adds support to several encryptors wrapping
|
||||
# them in a salt and pepper mechanism to increase security.
|
||||
#
|
||||
# == Options
|
||||
#
|
||||
@@ -24,30 +25,37 @@ module Devise
|
||||
attr_accessor :password_confirmation
|
||||
end
|
||||
|
||||
# Generates password salt.
|
||||
def self.required_fields(klass)
|
||||
[:password_salt]
|
||||
end
|
||||
|
||||
# Generates password salt when setting the password.
|
||||
def password=(new_password)
|
||||
self.password_salt = self.class.password_salt if new_password.present?
|
||||
super
|
||||
end
|
||||
|
||||
# Overrides authenticatable salt to use the new password_salt
|
||||
# column. authenticatable_salt is used by `valid_password?`
|
||||
# and by other modules whenever there is a need for a random
|
||||
# token based on the user password.
|
||||
def authenticatable_salt
|
||||
self.password_salt
|
||||
end
|
||||
|
||||
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
||||
def valid_password?(incoming_password)
|
||||
Devise.secure_compare(password_digest(incoming_password), self.encrypted_password)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Digests the password using the configured encryptor.
|
||||
def password_digest(password)
|
||||
if self.password_salt.present?
|
||||
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
||||
if password_salt.present?
|
||||
encryptor_class.digest(password, self.class.stretches, authenticatable_salt, self.class.pepper)
|
||||
end
|
||||
end
|
||||
|
||||
def encryptor_class
|
||||
self.class.encryptor_class
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :encryptor)
|
||||
|
||||
|
||||
@@ -22,6 +22,15 @@ module Devise
|
||||
|
||||
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
||||
|
||||
def self.required_fields(klass)
|
||||
attributes = []
|
||||
attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts)
|
||||
attributes << :unlock_at if klass.unlock_strategy_enabled?(:time)
|
||||
attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
# Lock a user setting its locked_at to actual time.
|
||||
def lock_access!
|
||||
self.locked_at = Time.now.utc
|
||||
@@ -88,7 +97,6 @@ module Devise
|
||||
self.failed_attempts += 1
|
||||
if attempts_exceeded?
|
||||
lock_access! unless access_locked?
|
||||
return :locked
|
||||
else
|
||||
save(:validate => false)
|
||||
end
|
||||
@@ -96,6 +104,14 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
def unauthenticated_message
|
||||
if lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
|
||||
:locked
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def attempts_exceeded?
|
||||
|
||||
@@ -15,6 +15,10 @@ module Devise
|
||||
module Omniauthable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.required_fields(klass)
|
||||
[]
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :omniauth_providers)
|
||||
end
|
||||
|
||||
@@ -24,6 +24,10 @@ module Devise
|
||||
module Recoverable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.required_fields(klass)
|
||||
[:reset_password_sent_at, :reset_password_token]
|
||||
end
|
||||
|
||||
# Update password saving the record and clearing token. Returns true if
|
||||
# the passwords are valid and the record was saved, false otherwise.
|
||||
def reset_password!(new_password, new_password_confirmation)
|
||||
|
||||
@@ -5,6 +5,10 @@ module Devise
|
||||
module Registerable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.required_fields(klass)
|
||||
[]
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# A convenience method that receives both parameters and session to
|
||||
# initialize a user. This can be used by OAuth, for example, to send
|
||||
|
||||
@@ -24,7 +24,7 @@ module Devise
|
||||
# * +extend_remember_period+: if true, extends the user's remember period
|
||||
# when remembered via cookie. False by default.
|
||||
#
|
||||
# * +cookie_options+: configuration options passed to the created cookie.
|
||||
# * +rememberable_options+: configuration options passed to the created cookie.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
@@ -41,6 +41,10 @@ module Devise
|
||||
|
||||
attr_accessor :remember_me, :extend_remember_period
|
||||
|
||||
def self.required_fields(klass)
|
||||
[:remember_created_at, :remember_token]
|
||||
end
|
||||
|
||||
# Generate a new remember token and save the record without validations
|
||||
# unless remember_across_browsers is true and the user already has a valid token.
|
||||
def remember_me!(extend_period=false)
|
||||
@@ -71,7 +75,7 @@ module Devise
|
||||
def rememberable_value
|
||||
if respond_to?(:remember_token)
|
||||
remember_token
|
||||
elsif salt = authenticatable_salt
|
||||
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
|
||||
salt
|
||||
else
|
||||
raise "authenticable_salt returned nil for the #{self.class.name} model. " \
|
||||
|
||||
@@ -20,6 +20,10 @@ module Devise
|
||||
module Timeoutable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.required_fields(klass)
|
||||
[]
|
||||
end
|
||||
|
||||
# Checks whether the user session has expired based on configured time.
|
||||
def timedout?(last_access)
|
||||
return false if remember_exists_and_not_expired?
|
||||
|
||||
@@ -27,6 +27,10 @@ module Devise
|
||||
module TokenAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.required_fields(klass)
|
||||
[:authentication_token]
|
||||
end
|
||||
|
||||
# Generate new authentication token (a.k.a. "single access token").
|
||||
def reset_authentication_token
|
||||
self.authentication_token = self.class.authentication_token
|
||||
@@ -52,6 +56,7 @@ module Devise
|
||||
def after_token_authentication
|
||||
end
|
||||
|
||||
|
||||
module ClassMethods
|
||||
def find_for_token_authentication(conditions)
|
||||
find_for_authentication(:authentication_token => conditions[token_authentication_key])
|
||||
|
||||
@@ -11,6 +11,10 @@ module Devise
|
||||
# * last_sign_in_ip - Holds the remote ip of the previous sign in
|
||||
#
|
||||
module Trackable
|
||||
def self.required_fields(klass)
|
||||
[:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count]
|
||||
end
|
||||
|
||||
def update_tracked_fields!(request)
|
||||
old_current, new_current = self.current_sign_in_at, Time.now.utc
|
||||
self.last_sign_in_at = old_current || new_current
|
||||
|
||||
@@ -17,6 +17,10 @@ module Devise
|
||||
VALIDATIONS = [ :validates_presence_of, :validates_uniqueness_of, :validates_format_of,
|
||||
:validates_confirmation_of, :validates_length_of ].freeze
|
||||
|
||||
def self.required_fields(klass)
|
||||
[]
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
assert_validations_api!(base)
|
||||
|
||||
@@ -87,8 +87,6 @@ module Devise
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
Devise.configure_warden!
|
||||
|
||||
example = <<-YAML
|
||||
en:
|
||||
devise:
|
||||
|
||||
@@ -7,11 +7,8 @@ module ActionDispatch::Routing
|
||||
def finalize_with_devise!
|
||||
result = finalize_without_devise!
|
||||
|
||||
# If @devise_finalized was defined, it means devise_for was invoked
|
||||
# in this router, so we proceed to generate devise helpers unless
|
||||
# they were already defined (which then @devise_finalizd would be true).
|
||||
if defined?(@devise_finalized) && !@devise_finalized
|
||||
if Devise.router_name.nil? && self != Rails.application.try(:routes)
|
||||
@devise_finalized ||= begin
|
||||
if Devise.router_name.nil? && defined?(@devise_finalized) && self != Rails.application.try(:routes)
|
||||
warn "[DEVISE] We have detected that you are using devise_for inside engine routes. " \
|
||||
"In this case, you probably want to set Devise.router_name = MOUNT_POINT, where " \
|
||||
"MOUNT_POINT is a symbol representing where this engine will be mounted at. For " \
|
||||
@@ -19,8 +16,9 @@ module ActionDispatch::Routing
|
||||
" to :main_app as well in case you want to keep the current behavior."
|
||||
end
|
||||
|
||||
Devise.configure_warden!
|
||||
Devise.regenerate_helpers!
|
||||
@devise_finalized = true
|
||||
true
|
||||
end
|
||||
|
||||
result
|
||||
@@ -186,7 +184,7 @@ module ActionDispatch::Routing
|
||||
#
|
||||
# In order to get Devise to recognize the deactivate action, your devise_for entry should look like this,
|
||||
#
|
||||
# devise_for :owners, :controllers => { :registrations => "registrations" } do
|
||||
# devise_scope :owner do
|
||||
# post "deactivate", :to => "registrations#deactivate", :as => "deactivate_registration"
|
||||
# end
|
||||
#
|
||||
@@ -200,7 +198,8 @@ module ActionDispatch::Routing
|
||||
options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {})
|
||||
options[:constraints] = (@scope[:constraints] || {}).merge(options[:constraints] || {})
|
||||
options[:defaults] = (@scope[:defaults] || {}).merge(options[:defaults] || {})
|
||||
options[:options] = (@scope[:options] || {}).merge({:format => false}) if options[:format] == false
|
||||
options[:options] = @scope[:options] || {}
|
||||
options[:options][:format] = false if options[:format] == false
|
||||
|
||||
resources.map!(&:to_sym)
|
||||
|
||||
|
||||
@@ -23,14 +23,20 @@ module Devise
|
||||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
case result
|
||||
when String, Symbol
|
||||
when Symbol, String
|
||||
ActiveSupport::Deprecation.warn "valid_for_authentication should return a boolean value"
|
||||
fail!(result)
|
||||
false
|
||||
when TrueClass
|
||||
return false
|
||||
end
|
||||
|
||||
if result
|
||||
decorate(resource)
|
||||
true
|
||||
else
|
||||
result
|
||||
if resource
|
||||
fail!(resource.unauthenticated_message)
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Devise
|
||||
VERSION = "2.0.3".freeze
|
||||
VERSION = "2.1.0.rc".freeze
|
||||
end
|
||||
|
||||
@@ -39,6 +39,18 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
class SharedViewsGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
desc "Copies shared Devise views to your application."
|
||||
hide!
|
||||
|
||||
# Override copy_views to just copy mailer and shared.
|
||||
def copy_views
|
||||
view_directory :shared
|
||||
end
|
||||
end
|
||||
|
||||
class FormForGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
@@ -80,15 +92,12 @@ module Devise
|
||||
end
|
||||
|
||||
class ViewsGenerator < Rails::Generators::Base
|
||||
include ViewPathTemplates
|
||||
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
desc "Copies Devise views to your application."
|
||||
|
||||
def copy_views
|
||||
copy_file "_links.erb", "#{target_path}/_links.erb"
|
||||
end
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
invoke SharedViewsGenerator
|
||||
hook_for :form_builder, :aliases => "-b",
|
||||
:desc => "Form builder to be used",
|
||||
:default => defined?(SimpleForm) ? "simple_form_for" : "form_for"
|
||||
|
||||
@@ -117,7 +117,7 @@ Devise.setup do |config|
|
||||
|
||||
# Options to be passed to the created cookie. For instance, you can set
|
||||
# :secure => true in order to force SSL only cookies.
|
||||
# config.cookie_options = {}
|
||||
# config.rememberable_options = {}
|
||||
|
||||
# ==> Configuration for :validatable
|
||||
# Range for password length. Default is 6..128.
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -16,4 +16,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -12,4 +12,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -14,4 +14,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -12,4 +12,4 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "links" %>
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -46,7 +46,7 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
|
||||
assert_file "app/views/#{scope}/registrations/new.html.erb"
|
||||
assert_file "app/views/#{scope}/registrations/edit.html.erb"
|
||||
assert_file "app/views/#{scope}/sessions/new.html.erb"
|
||||
assert_file "app/views/#{scope}/shared/_links.erb"
|
||||
assert_file "app/views/#{scope}/unlocks/new.html.erb"
|
||||
assert_file "app/views/#{scope}/_links.erb"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -118,7 +118,7 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
|
||||
OmniAuth.config.mock_auth[:facebook] = :access_denied
|
||||
visit "/users/auth/facebook/callback?error=access_denied"
|
||||
assert_current_url "/users/sign_in"
|
||||
assert_contain 'Could not authorize you from Facebook because "Access denied".'
|
||||
assert_contain 'Could not authenticate you from Facebook because "Access denied".'
|
||||
end
|
||||
|
||||
test "handles other exceptions from omniauth" do
|
||||
@@ -128,6 +128,6 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
|
||||
click_link "Sign in with Facebook"
|
||||
|
||||
assert_current_url "/users/sign_in"
|
||||
assert_contain 'Could not authorize you from Facebook because "Invalid credentials".'
|
||||
assert_contain 'Could not authenticate you from Facebook because "Invalid credentials".'
|
||||
end
|
||||
end
|
||||
|
||||
7
test/models/authenticatable_test.rb
Normal file
7
test/models/authenticatable_test.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class AuthenticatableTest < ActiveSupport::TestCase
|
||||
test 'required_fields should be an empty array' do
|
||||
assert_equal Devise::Models::Validatable.required_fields(User), []
|
||||
end
|
||||
end
|
||||
@@ -252,6 +252,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
|
||||
assert_not_nil admin.confirmation_token
|
||||
end
|
||||
|
||||
test 'should not generate confirmation token if skipping reconfirmation after changing email' do
|
||||
admin = create_admin
|
||||
assert admin.confirm!
|
||||
admin.skip_reconfirmation!
|
||||
assert admin.update_attributes(:email => 'new_test@example.com')
|
||||
assert_nil admin.confirmation_token
|
||||
end
|
||||
|
||||
|
||||
test 'should regenerate confirmation token after changing email' do
|
||||
admin = create_admin
|
||||
assert admin.confirm!
|
||||
@@ -328,4 +337,21 @@ class ReconfirmableTest < ActiveSupport::TestCase
|
||||
admin = Admin.find_by_unconfirmed_email_with_errors(:email => "new_test@email.com")
|
||||
assert admin.persisted?
|
||||
end
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Confirmable.required_fields(User), [
|
||||
:confirmation_sent_at,
|
||||
:confirmation_token,
|
||||
:confirmed_at
|
||||
]
|
||||
end
|
||||
|
||||
test 'required_fields should also contain unconfirmable when reconfirmable_email is true' do
|
||||
assert_same_content Devise::Models::Confirmable.required_fields(Admin), [
|
||||
:confirmation_sent_at,
|
||||
:confirmation_token,
|
||||
:confirmed_at,
|
||||
:unconfirmed_email
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
user.save!
|
||||
assert_equal email.downcase, user.email
|
||||
end
|
||||
|
||||
|
||||
test 'should remove whitespace from strip whitespace keys when saving' do
|
||||
# strip_whitespace_keys is set to :email by default.
|
||||
email = ' foo@bar.com '
|
||||
@@ -92,14 +92,14 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
:password => 'pass321', :password_confirmation => 'pass321')
|
||||
assert user.reload.valid_password?('pass321')
|
||||
end
|
||||
|
||||
|
||||
test 'should update password with valid current password and :as option' do
|
||||
user = create_user
|
||||
assert user.update_with_password(:current_password => '123456',
|
||||
:password => 'pass321', :password_confirmation => 'pass321', :as => :admin)
|
||||
assert user.reload.valid_password?('pass321')
|
||||
end
|
||||
|
||||
|
||||
test 'should add an error to current password when it is invalid' do
|
||||
user = create_user
|
||||
assert_not user.update_with_password(:current_password => 'other',
|
||||
@@ -151,7 +151,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
user.update_without_password(:email => 'new@example.com')
|
||||
assert_equal 'new@example.com', user.email
|
||||
end
|
||||
|
||||
|
||||
test 'should update the user without password with :as option' do
|
||||
user = create_user
|
||||
user.update_without_password(:email => 'new@example.com', :as => :admin)
|
||||
@@ -170,4 +170,20 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
user = User.create(:email => "HEllO@example.com", :password => "123456")
|
||||
assert !user.valid?
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fiels should be encryptable_password and the email field by default' do
|
||||
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
|
||||
:email,
|
||||
:encrypted_password
|
||||
]
|
||||
end
|
||||
|
||||
test 'required_fields should be encryptable_password and the login when the login is on authentication_keys' do
|
||||
swap Devise, :authentication_keys => [:login] do
|
||||
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
|
||||
:encrypted_password,
|
||||
:login
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -64,4 +64,10 @@ class EncryptableTest < ActiveSupport::TestCase
|
||||
admin.save
|
||||
assert_not admin.valid_password?('123456')
|
||||
end
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Encryptable.required_fields(User), [
|
||||
:password_salt
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -235,4 +235,38 @@ class LockableTest < ActiveSupport::TestCase
|
||||
assert_nil user.locked_at
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should contain the all the fields when all the strategies are enabled' do
|
||||
swap Devise, :unlock_strategy => :both do
|
||||
swap Devise, :lock_strategy => :failed_attempts do
|
||||
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
||||
:failed_attempts,
|
||||
:unlock_at,
|
||||
:unlock_token
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should contain only failed_attempts and unlock_at when the strategies are time and failed_attempts are enabled' do
|
||||
swap Devise, :unlock_strategy => :time do
|
||||
swap Devise, :lock_strategy => :failed_attempts do
|
||||
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
||||
:failed_attempts,
|
||||
:unlock_at
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should contain only failed_attempts and unlock_token when the strategies are token and failed_attempts are enabled' do
|
||||
swap Devise, :unlock_strategy => :email do
|
||||
swap Devise, :lock_strategy => :failed_attempts do
|
||||
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
||||
:failed_attempts,
|
||||
:unlock_token
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
7
test/models/omniauthable_test.rb
Normal file
7
test/models/omniauthable_test.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class OmniauthableTest < ActiveSupport::TestCase
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Omniauthable.required_fields(User), []
|
||||
end
|
||||
end
|
||||
@@ -195,4 +195,11 @@ class RecoverableTest < ActiveSupport::TestCase
|
||||
assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Recoverable.required_fields(User), [
|
||||
:reset_password_sent_at,
|
||||
:reset_password_token
|
||||
]
|
||||
end
|
||||
end
|
||||
7
test/models/registerable_test.rb
Normal file
7
test/models/registerable_test.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class RegisterableTest < ActiveSupport::TestCase
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Registerable.required_fields(User), []
|
||||
end
|
||||
end
|
||||
@@ -54,7 +54,7 @@ class RememberableTest < ActiveSupport::TestCase
|
||||
resource.forget_me!
|
||||
assert resource.remember_created_at.nil?
|
||||
end
|
||||
|
||||
|
||||
test 'forget_me should not try to update resource if it has been destroyed' do
|
||||
resource = create_resource
|
||||
resource.destroy
|
||||
@@ -165,4 +165,11 @@ class RememberableTest < ActiveSupport::TestCase
|
||||
assert_not_equal old, resource.remember_created_at
|
||||
end
|
||||
end
|
||||
|
||||
test 'should have the required_fiels array' do
|
||||
assert_same_content Devise::Models::Rememberable.required_fields(User), [
|
||||
:remember_created_at,
|
||||
:remember_token
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,4 +39,8 @@ class TimeoutableTest < ActiveSupport::TestCase
|
||||
assert user.timedout?(6.minutes.ago)
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Timeoutable.required_fields(User), []
|
||||
end
|
||||
end
|
||||
|
||||
@@ -46,4 +46,10 @@ class TokenAuthenticatableTest < ActiveSupport::TestCase
|
||||
user = User.find_for_token_authentication(:auth_token => {'$ne' => user1.authentication_token})
|
||||
assert_nil user
|
||||
end
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::TokenAuthenticatable.required_fields(User), [
|
||||
:authentication_token
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
require 'test_helper'
|
||||
|
||||
class TrackableTest < ActiveSupport::TestCase
|
||||
|
||||
test 'required_fields should contain the fields that Devise uses' do
|
||||
assert_same_content Devise::Models::Trackable.required_fields(User), [
|
||||
:current_sign_in_at,
|
||||
:current_sign_in_ip,
|
||||
:last_sign_in_at,
|
||||
:last_sign_in_ip,
|
||||
:sign_in_count
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -105,9 +105,13 @@ class ValidatableTest < ActiveSupport::TestCase
|
||||
assert_equal 'is too long (maximum is 128 characters)', user.errors[:password].join
|
||||
end
|
||||
|
||||
test 'shuold not be included in objects with invalid API' do
|
||||
test 'should not be included in objects with invalid API' do
|
||||
assert_raise RuntimeError do
|
||||
Class.new.send :include, Devise::Models::Validatable
|
||||
end
|
||||
end
|
||||
|
||||
test 'required_fields should be an empty array' do
|
||||
assert_equal Devise::Models::Validatable.required_fields(User), []
|
||||
end
|
||||
end
|
||||
|
||||
@@ -107,3 +107,73 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
||||
Admin.create!
|
||||
end
|
||||
end
|
||||
|
||||
class CheckFieldsTest < ActiveSupport::TestCase
|
||||
test 'checks if the class respond_to the required fields' do
|
||||
Player = Class.new do
|
||||
extend Devise::Models
|
||||
|
||||
def self.before_validation(instance)
|
||||
end
|
||||
|
||||
devise :database_authenticatable
|
||||
|
||||
attr_accessor :encrypted_password, :email
|
||||
end
|
||||
|
||||
assert_nothing_raised Devise::Models::MissingAttribute do
|
||||
Devise::Models.check_fields!(Player)
|
||||
end
|
||||
end
|
||||
|
||||
test 'raises Devise::Models::MissingAtrribute and shows the missing attribute if the class doesn\'t respond_to one of the attributes' do
|
||||
Clown = Class.new do
|
||||
extend Devise::Models
|
||||
|
||||
def self.before_validation(instance)
|
||||
end
|
||||
|
||||
devise :database_authenticatable
|
||||
|
||||
attr_accessor :encrypted_password
|
||||
end
|
||||
|
||||
assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: email" do
|
||||
Devise::Models.check_fields!(Clown)
|
||||
end
|
||||
end
|
||||
|
||||
test 'raises Devise::Models::MissingAtrribute with all the missing attributes if there is more than one' do
|
||||
Magician = Class.new do
|
||||
extend Devise::Models
|
||||
|
||||
def self.before_validation(instance)
|
||||
end
|
||||
|
||||
devise :database_authenticatable
|
||||
end
|
||||
|
||||
exception = assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: encrypted_password, email" do
|
||||
Devise::Models.check_fields!(Magician)
|
||||
end
|
||||
end
|
||||
|
||||
test "doesn't raise a NoMethodError exception when the module doesn't have a required_field(klass) class method" do
|
||||
driver = Class.new do
|
||||
extend Devise::Models
|
||||
|
||||
def self.before_validation(instance)
|
||||
end
|
||||
|
||||
attr_accessor :encrypted_password, :email
|
||||
|
||||
devise :database_authenticatable
|
||||
end
|
||||
|
||||
swap_module_method_existence Devise::Models::DatabaseAuthenticatable, :required_fields do
|
||||
assert_deprecated do
|
||||
Devise::Models.check_fields!(driver)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -58,6 +58,10 @@ Rails.application.routes.draw do
|
||||
# Other routes for routing_test.rb
|
||||
devise_for :reader, :class_name => "User", :only => :passwords
|
||||
|
||||
scope :host => "sub.example.com" do
|
||||
devise_for :sub_admin, :class_name => "Admin"
|
||||
end
|
||||
|
||||
namespace :publisher, :path_names => { :sign_in => "i_dont_care", :sign_out => "get_out" } do
|
||||
devise_for :accounts, :class_name => "Admin", :path_names => { :sign_in => "get_in" }
|
||||
end
|
||||
|
||||
@@ -128,6 +128,10 @@ class CustomizedRoutingTest < ActionController::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test 'subdomain admin' do
|
||||
assert_recognizes({"host"=>"sub.example.com", :controller => 'devise/sessions', :action => 'new'}, {:host => "sub.example.com", :path => '/sub_admin/sign_in', :method => :get})
|
||||
end
|
||||
|
||||
test 'does only map reader password' do
|
||||
assert_raise ActionController::RoutingError do
|
||||
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, 'reader/sessions/new')
|
||||
|
||||
@@ -24,4 +24,19 @@ class ActiveSupport::TestCase
|
||||
def assert_email_not_sent(&block)
|
||||
assert_no_difference('ActionMailer::Base.deliveries.size') { yield }
|
||||
end
|
||||
|
||||
def assert_same_content(result, expected)
|
||||
assert expected.size == result.size, "the arrays doesn't have the same size"
|
||||
expected.each do |element|
|
||||
assert result.include?(element), "The array doesn't include '#{element}'."
|
||||
end
|
||||
end
|
||||
|
||||
def assert_raise_with_message(exception_klass, message)
|
||||
exception = assert_raise exception_klass do
|
||||
yield
|
||||
end
|
||||
|
||||
assert_equal exception.message, message, "The expected message was #{message} but your exception throwed #{exception.message}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,4 +67,25 @@ class ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def swap_module_method_existence(klass, method)
|
||||
klass.module_eval %Q[
|
||||
class << self
|
||||
alias #{method}_referenced #{method}
|
||||
undef #{method}
|
||||
end
|
||||
]
|
||||
|
||||
begin
|
||||
yield if block_given?
|
||||
ensure
|
||||
|
||||
klass.module_eval %Q[
|
||||
class << self
|
||||
alias #{method} #{method}_referenced
|
||||
undef #{method}_referenced
|
||||
end
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user