devise 1.1.9 → 1.2.rc

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (121) hide show
  1. data/CHANGELOG.rdoc +34 -26
  2. data/README.rdoc +134 -100
  3. data/app/controllers/devise/confirmations_controller.rb +1 -1
  4. data/app/controllers/devise/omniauth_callbacks_controller.rb +26 -0
  5. data/app/controllers/devise/passwords_controller.rb +1 -1
  6. data/app/controllers/devise/registrations_controller.rb +59 -6
  7. data/app/controllers/devise/sessions_controller.rb +3 -2
  8. data/app/controllers/devise/unlocks_controller.rb +1 -1
  9. data/app/helpers/devise_helper.rb +4 -2
  10. data/app/mailers/devise/mailer.rb +27 -10
  11. data/app/views/devise/confirmations/new.html.erb +1 -1
  12. data/app/views/devise/passwords/edit.html.erb +2 -2
  13. data/app/views/devise/passwords/new.html.erb +1 -1
  14. data/app/views/devise/registrations/edit.html.erb +1 -1
  15. data/app/views/devise/registrations/new.html.erb +1 -1
  16. data/app/views/devise/sessions/new.html.erb +1 -1
  17. data/app/views/devise/shared/_links.erb +6 -0
  18. data/app/views/devise/unlocks/new.html.erb +1 -1
  19. data/config/locales/en.yml +9 -2
  20. data/lib/devise.rb +116 -58
  21. data/lib/devise/controllers/helpers.rb +103 -107
  22. data/lib/devise/controllers/internal_helpers.rb +23 -7
  23. data/lib/devise/controllers/scoped_views.rb +4 -6
  24. data/lib/devise/controllers/url_helpers.rb +3 -5
  25. data/lib/devise/encryptors/base.rb +1 -1
  26. data/lib/devise/encryptors/restful_authentication_sha1.rb +4 -4
  27. data/lib/devise/failure_app.rb +29 -21
  28. data/lib/devise/hooks/forgetable.rb +2 -1
  29. data/lib/devise/hooks/rememberable.rb +11 -9
  30. data/lib/devise/mapping.rb +12 -5
  31. data/lib/devise/models.rb +0 -14
  32. data/lib/devise/models/authenticatable.rb +40 -30
  33. data/lib/devise/models/confirmable.rb +11 -15
  34. data/lib/devise/models/database_authenticatable.rb +23 -35
  35. data/lib/devise/models/encryptable.rb +65 -0
  36. data/lib/devise/models/lockable.rb +8 -7
  37. data/lib/devise/models/omniauthable.rb +23 -0
  38. data/lib/devise/models/recoverable.rb +5 -3
  39. data/lib/devise/models/registerable.rb +13 -0
  40. data/lib/devise/models/rememberable.rb +38 -30
  41. data/lib/devise/models/timeoutable.rb +20 -3
  42. data/lib/devise/models/token_authenticatable.rb +19 -7
  43. data/lib/devise/models/validatable.rb +16 -4
  44. data/lib/devise/modules.rb +15 -8
  45. data/lib/devise/omniauth.rb +47 -0
  46. data/lib/devise/omniauth/config.rb +30 -0
  47. data/lib/devise/omniauth/test_helpers.rb +57 -0
  48. data/lib/devise/omniauth/url_helpers.rb +29 -0
  49. data/lib/devise/orm/active_record.rb +2 -0
  50. data/lib/devise/orm/mongoid.rb +4 -2
  51. data/lib/devise/rails.rb +26 -46
  52. data/lib/devise/rails/routes.rb +64 -20
  53. data/lib/devise/rails/warden_compat.rb +18 -20
  54. data/lib/devise/schema.rb +13 -14
  55. data/lib/devise/strategies/authenticatable.rb +33 -7
  56. data/lib/devise/strategies/database_authenticatable.rb +1 -1
  57. data/lib/devise/strategies/rememberable.rb +1 -1
  58. data/lib/devise/strategies/token_authenticatable.rb +6 -2
  59. data/lib/devise/test_helpers.rb +11 -1
  60. data/lib/devise/version.rb +1 -1
  61. data/lib/generators/active_record/templates/migration.rb +1 -0
  62. data/lib/generators/devise/orm_helpers.rb +3 -2
  63. data/lib/generators/templates/devise.rb +70 -39
  64. data/test/controllers/helpers_test.rb +43 -67
  65. data/test/controllers/internal_helpers_test.rb +29 -8
  66. data/test/controllers/url_helpers_test.rb +2 -1
  67. data/test/failure_app_test.rb +56 -21
  68. data/test/generators/generators_test_helper.rb +4 -0
  69. data/test/generators/install_generator_test.rb +14 -0
  70. data/test/generators/views_generator_test.rb +37 -0
  71. data/test/integration/authenticatable_test.rb +147 -62
  72. data/test/integration/database_authenticatable_test.rb +22 -0
  73. data/test/integration/http_authenticatable_test.rb +12 -2
  74. data/test/integration/omniauthable_test.rb +107 -0
  75. data/test/integration/recoverable_test.rb +39 -20
  76. data/test/integration/registerable_test.rb +30 -4
  77. data/test/integration/rememberable_test.rb +57 -34
  78. data/test/integration/timeoutable_test.rb +10 -1
  79. data/test/integration/token_authenticatable_test.rb +12 -17
  80. data/test/mailers/confirmation_instructions_test.rb +4 -0
  81. data/test/mailers/reset_password_instructions_test.rb +4 -0
  82. data/test/mailers/unlock_instructions_test.rb +4 -0
  83. data/test/mapping_test.rb +37 -3
  84. data/test/models/confirmable_test.rb +3 -3
  85. data/test/models/database_authenticatable_test.rb +14 -71
  86. data/test/models/encryptable_test.rb +65 -0
  87. data/test/models/lockable_test.rb +17 -1
  88. data/test/models/recoverable_test.rb +17 -0
  89. data/test/models/rememberable_test.rb +186 -125
  90. data/test/models/token_authenticatable_test.rb +1 -13
  91. data/test/models_test.rb +5 -5
  92. data/test/omniauth/url_helpers_test.rb +47 -0
  93. data/test/rails_app/app/active_record/admin.rb +4 -1
  94. data/test/rails_app/app/active_record/user.rb +5 -4
  95. data/test/rails_app/app/controllers/{sessions_controller.rb → admins/sessions_controller.rb} +1 -1
  96. data/test/rails_app/app/controllers/home_controller.rb +9 -0
  97. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +7 -0
  98. data/test/rails_app/app/mongoid/admin.rb +4 -1
  99. data/test/rails_app/app/mongoid/shim.rb +16 -3
  100. data/test/rails_app/app/mongoid/user.rb +5 -5
  101. data/test/rails_app/config/initializers/devise.rb +52 -28
  102. data/test/rails_app/config/routes.rb +14 -6
  103. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +21 -17
  104. data/test/rails_app/db/schema.rb +17 -51
  105. data/test/rails_app/lib/shared_admin.rb +9 -0
  106. data/test/rails_app/lib/shared_user.rb +23 -0
  107. data/test/routes_test.rb +42 -9
  108. data/test/support/integration.rb +3 -3
  109. data/test/support/webrat/integrations/rails.rb +7 -0
  110. data/test/test_helper.rb +2 -0
  111. data/test/test_helpers_test.rb +29 -0
  112. metadata +60 -30
  113. data/Gemfile +0 -27
  114. data/Gemfile.lock +0 -115
  115. data/Rakefile +0 -55
  116. data/TODO +0 -3
  117. data/lib/devise/encryptors/bcrypt.rb +0 -19
  118. data/lib/generators/devise_install_generator.rb +0 -4
  119. data/lib/generators/devise_views_generator.rb +0 -4
  120. data/test/indifferent_hash.rb +0 -33
  121. data/test/support/test_silencer.rb +0 -5
@@ -4,7 +4,7 @@ class Devise::PasswordsController < ApplicationController
4
4
 
5
5
  # GET /resource/password/new
6
6
  def new
7
- build_resource
7
+ build_resource({})
8
8
  render_with_scope :new
9
9
  end
10
10
 
@@ -1,5 +1,5 @@
1
1
  class Devise::RegistrationsController < ApplicationController
2
- prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
2
+ prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
3
3
  prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
4
4
  include Devise::Controllers::InternalHelpers
5
5
 
@@ -9,13 +9,19 @@ class Devise::RegistrationsController < ApplicationController
9
9
  render_with_scope :new
10
10
  end
11
11
 
12
- # POST /resource
12
+ # POST /resource/sign_up
13
13
  def create
14
14
  build_resource
15
15
 
16
16
  if resource.save
17
- set_flash_message :notice, :signed_up
18
- sign_in_and_redirect(resource_name, resource)
17
+ if resource.active?
18
+ set_flash_message :notice, :signed_up
19
+ sign_in_and_redirect(resource_name, resource)
20
+ else
21
+ set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s
22
+ expire_session_data_after_sign_in!
23
+ redirect_to after_inactive_sign_up_path_for(resource)
24
+ end
19
25
  else
20
26
  clean_up_passwords(resource)
21
27
  render_with_scope :new
@@ -31,6 +37,7 @@ class Devise::RegistrationsController < ApplicationController
31
37
  def update
32
38
  if resource.update_with_password(params[resource_name])
33
39
  set_flash_message :notice, :updated
40
+ sign_in resource_name, resource, :bypass => true
34
41
  redirect_to after_update_path_for(resource)
35
42
  else
36
43
  clean_up_passwords(resource)
@@ -41,17 +48,63 @@ class Devise::RegistrationsController < ApplicationController
41
48
  # DELETE /resource
42
49
  def destroy
43
50
  resource.destroy
44
- set_flash_message :notice, :destroyed
45
51
  sign_out_and_redirect(self.resource)
52
+ set_flash_message :notice, :destroyed
53
+ end
54
+
55
+ # GET /resource/cancel
56
+ # Forces the session data which is usually expired after sign
57
+ # in to be expired now. This is useful if the user wants to
58
+ # cancel oauth signing in/up in the middle of the process,
59
+ # removing all OAuth session data.
60
+ def cancel
61
+ expire_session_data_after_sign_in!
62
+ redirect_to new_registration_path(resource_name)
46
63
  end
47
64
 
48
65
  protected
49
66
 
67
+ # Build a devise resource passing in the session. Useful to move
68
+ # temporary session data to the newly created user.
69
+ def build_resource(hash=nil)
70
+ hash ||= params[resource_name] || {}
71
+ self.resource = resource_class.new_with_session(hash, session)
72
+ end
73
+
74
+ # The path used after sign up. You need to overwrite this method
75
+ # in your own RegistrationsController.
76
+ def after_sign_up_path_for(resource)
77
+ after_sign_in_path_for(resource)
78
+ end
79
+
80
+ # Overwrite redirect_for_sign_in so it takes uses after_sign_up_path_for.
81
+ def redirect_for_sign_in(scope, resource) #:nodoc:
82
+ redirect_to stored_location_for(scope) || after_sign_up_path_for(resource)
83
+ end
84
+
85
+ # The path used after sign up for inactive accounts. You need to overwrite
86
+ # this method in your own RegistrationsController.
87
+ def after_inactive_sign_up_path_for(resource)
88
+ root_path
89
+ end
90
+
91
+ # The default url to be used after updating a resource. You need to overwrite
92
+ # this method in your own RegistrationsController.
93
+ def after_update_path_for(resource)
94
+ if defined?(super)
95
+ ActiveSupport::Deprecation.warn "Defining after_update_path_for in ApplicationController " <<
96
+ "is deprecated. Please add a RegistrationsController to your application and define it there."
97
+ super
98
+ else
99
+ after_sign_in_path_for(resource)
100
+ end
101
+ end
102
+
50
103
  # Authenticates the current scope and gets a copy of the current resource.
51
104
  # We need to use a copy because we don't want actions like update changing
52
105
  # the current user in place.
53
106
  def authenticate_scope!
54
107
  send(:"authenticate_#{resource_name}!")
55
- self.resource = resource_class.find(send(:"current_#{resource_name}").id)
108
+ self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
56
109
  end
57
110
  end
@@ -10,14 +10,15 @@ class Devise::SessionsController < ApplicationController
10
10
 
11
11
  # POST /resource/sign_in
12
12
  def create
13
- resource = warden.authenticate!(:scope => resource_name, :recall => "new")
13
+ resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
14
14
  set_flash_message :notice, :signed_in
15
15
  sign_in_and_redirect(resource_name, resource)
16
16
  end
17
17
 
18
18
  # GET /resource/sign_out
19
19
  def destroy
20
- set_flash_message :notice, :signed_out if signed_in?(resource_name)
20
+ signed_in = signed_in?(resource_name)
21
21
  sign_out_and_redirect(resource_name)
22
+ set_flash_message :notice, :signed_out if signed_in
22
23
  end
23
24
  end
@@ -4,7 +4,7 @@ class Devise::UnlocksController < ApplicationController
4
4
 
5
5
  # GET /resource/unlock/new
6
6
  def new
7
- build_resource
7
+ build_resource({})
8
8
  render_with_scope :new
9
9
  end
10
10
 
@@ -3,7 +3,9 @@ module DeviseHelper
3
3
  return "" if resource.errors.empty?
4
4
 
5
5
  messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
6
- sentence = "#{pluralize(resource.errors.count, "error")} prohibited this #{resource_name} from being saved:"
6
+ sentence = I18n.t("errors.messages.not_saved",
7
+ :count => resource.errors.count,
8
+ :resource => resource_name)
7
9
 
8
10
  html = <<-HTML
9
11
  <div id="error_explanation">
@@ -14,4 +16,4 @@ module DeviseHelper
14
16
 
15
17
  html.html_safe
16
18
  end
17
- end
19
+ end
@@ -1,6 +1,6 @@
1
1
  class Devise::Mailer < ::ActionMailer::Base
2
2
  include Devise::Controllers::ScopedViews
3
- attr_reader :devise_mapping, :resource
3
+ attr_reader :scope_name, :resource
4
4
 
5
5
  def confirmation_instructions(record)
6
6
  setup_mail(record, :confirmation_instructions)
@@ -18,19 +18,36 @@ class Devise::Mailer < ::ActionMailer::Base
18
18
 
19
19
  # Configure default email options
20
20
  def setup_mail(record, action)
21
- @scope_name = Devise::Mapping.find_scope!(record)
22
- @devise_mapping = Devise.mappings[@scope_name]
23
- @resource = instance_variable_set("@#{@devise_mapping.name}", record)
21
+ initialize_from_record(record)
22
+ mail headers_for(action)
23
+ end
24
+
25
+ def initialize_from_record(record)
26
+ @scope_name = Devise::Mapping.find_scope!(record)
27
+ @resource = instance_variable_set("@#{devise_mapping.name}", record)
28
+ end
29
+
30
+ def devise_mapping
31
+ @devise_mapping ||= Devise.mappings[scope_name]
32
+ end
24
33
 
34
+ def headers_for(action)
25
35
  headers = {
26
- :subject => translate(@devise_mapping, action),
27
- :from => mailer_sender(@devise_mapping),
28
- :to => record.email,
36
+ :subject => translate(devise_mapping, action),
37
+ :from => mailer_sender(devise_mapping),
38
+ :to => resource.email,
29
39
  :template_path => template_paths
30
40
  }
31
41
 
32
- headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
33
- mail(headers)
42
+ if resource.respond_to?(:headers_for)
43
+ headers.merge!(resource.headers_for(action))
44
+ end
45
+
46
+ unless headers.key?(:reply_to)
47
+ headers[:reply_to] = headers[:from]
48
+ end
49
+
50
+ headers
34
51
  end
35
52
 
36
53
  def mailer_sender(mapping)
@@ -43,7 +60,7 @@ class Devise::Mailer < ::ActionMailer::Base
43
60
 
44
61
  def template_paths
45
62
  template_path = [self.class.mailer_name]
46
- template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
63
+ template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
47
64
  template_path
48
65
  end
49
66
 
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Resend confirmation instructions" %></p>
10
10
  <% end %>
@@ -4,10 +4,10 @@
4
4
  <%= devise_error_messages! %>
5
5
  <%= f.hidden_field :reset_password_token %>
6
6
 
7
- <p><%= f.label :password %><br />
7
+ <p><%= f.label :password, "New password" %><br />
8
8
  <%= f.password_field :password %></p>
9
9
 
10
- <p><%= f.label :password_confirmation %><br />
10
+ <p><%= f.label :password_confirmation, "Confirm new password" %><br />
11
11
  <%= f.password_field :password_confirmation %></p>
12
12
 
13
13
  <p><%= f.submit "Change my password" %></p>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Send me reset password instructions" %></p>
10
10
  <% end %>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
10
10
  <%= f.password_field :password %></p>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.label :password %><br />
10
10
  <%= f.password_field :password %></p>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
4
4
  <p><%= f.label :email %><br />
5
- <%= f.text_field :email %></p>
5
+ <%= f.email_field :email %></p>
6
6
 
7
7
  <p><%= f.label :password %><br />
8
8
  <%= f.password_field :password %></p>
@@ -17,3 +17,9 @@
17
17
  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18
18
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
19
19
  <% end -%>
20
+
21
+ <%- if devise_mapping.omniauthable? %>
22
+ <%- resource_class.omniauth_providers.each do |provider| %>
23
+ <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
24
+ <% end -%>
25
+ <% end -%>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Resend unlock instructions" %></p>
10
10
  <% end %>
@@ -2,8 +2,11 @@ en:
2
2
  errors:
3
3
  messages:
4
4
  not_found: "not found"
5
- already_confirmed: "was already confirmed"
5
+ already_confirmed: "was already confirmed, please try signing in"
6
6
  not_locked: "was not locked"
7
+ not_saved:
8
+ one: "1 error prohibited this %{resource} from being saved:"
9
+ other: "%{count} errors prohibited this %{resource} from being saved:"
7
10
 
8
11
  devise:
9
12
  failure:
@@ -24,12 +27,16 @@ en:
24
27
  send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
25
28
  confirmed: 'Your account was successfully confirmed. You are now signed in.'
26
29
  registrations:
27
- signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
30
+ signed_up: 'Welcome! You have signed up successfully.'
31
+ inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
28
32
  updated: 'You updated your account successfully.'
29
33
  destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
30
34
  unlocks:
31
35
  send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
32
36
  unlocked: 'Your account was successfully unlocked. You are now signed in.'
37
+ omniauth_callbacks:
38
+ success: 'Successfully authorized from %{kind} account.'
39
+ failure: 'Could not authorize you from %{kind} because "%{reason}".'
33
40
  mailer:
34
41
  confirmation_instructions:
35
42
  subject: 'Confirmation instructions'
@@ -1,8 +1,11 @@
1
1
  require 'active_support/core_ext/numeric/time'
2
2
  require 'active_support/dependencies'
3
+ require 'orm_adapter'
4
+ require 'set'
3
5
 
4
6
  module Devise
5
7
  autoload :FailureApp, 'devise/failure_app'
8
+ autoload :OmniAuth, 'devise/omniauth'
6
9
  autoload :PathChecker, 'devise/path_checker'
7
10
  autoload :Schema, 'devise/schema'
8
11
  autoload :TestHelpers, 'devise/test_helpers'
@@ -16,7 +19,6 @@ module Devise
16
19
 
17
20
  module Encryptors
18
21
  autoload :Base, 'devise/encryptors/base'
19
- autoload :Bcrypt, 'devise/encryptors/bcrypt'
20
22
  autoload :AuthlogicSha512, 'devise/encryptors/authlogic_sha512'
21
23
  autoload :ClearanceSha1, 'devise/encryptors/clearance_sha1'
22
24
  autoload :RestfulAuthenticationSha1, 'devise/encryptors/restful_authentication_sha1'
@@ -30,11 +32,12 @@ module Devise
30
32
  end
31
33
 
32
34
  # Constants which holds devise configuration for extensions. Those should
33
- # not be modified by the "end user".
35
+ # not be modified by the "end user" (this is why they are constants).
34
36
  ALL = []
35
37
  CONTROLLERS = ActiveSupport::OrderedHash.new
36
38
  ROUTES = ActiveSupport::OrderedHash.new
37
39
  STRATEGIES = ActiveSupport::OrderedHash.new
40
+ URL_HELPERS = ActiveSupport::OrderedHash.new
38
41
 
39
42
  # True values used to check params
40
43
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
@@ -45,31 +48,34 @@ module Devise
45
48
  :sha512 => 128,
46
49
  :clearance_sha1 => 40,
47
50
  :restful_authentication_sha1 => 40,
48
- :authlogic_sha512 => 128,
49
- :bcrypt => 60
51
+ :authlogic_sha512 => 128
50
52
  }
51
53
 
52
54
  # Custom domain for cookies. Not set by default
53
- mattr_accessor :cookie_domain
54
- @@cookie_domain = false
55
-
56
- # Used to encrypt password. Please generate one with rake secret.
57
- mattr_accessor :pepper
58
- @@pepper = nil
55
+ mattr_accessor :cookie_options
56
+ @@cookie_options = {}
59
57
 
60
58
  # The number of times to encrypt password.
61
59
  mattr_accessor :stretches
62
60
  @@stretches = 10
63
61
 
64
- # Keys used when authenticating an user.
62
+ # Keys used when authenticating a user.
65
63
  mattr_accessor :authentication_keys
66
64
  @@authentication_keys = [ :email ]
67
65
 
66
+ # Request keys used when authenticating a user.
67
+ mattr_accessor :request_keys
68
+ @@request_keys = []
69
+
70
+ # Keys that should be case-insensitive.
71
+ mattr_accessor :case_insensitive_keys
72
+ @@case_insensitive_keys = [ :email ]
73
+
68
74
  # If http authentication is enabled by default.
69
75
  mattr_accessor :http_authenticatable
70
76
  @@http_authenticatable = false
71
77
 
72
- # If http authentication is used for ajax requests. True by default.
78
+ # If http headers should be returned for ajax requests. True by default.
73
79
  mattr_accessor :http_authenticatable_on_xhr
74
80
  @@http_authenticatable_on_xhr = true
75
81
 
@@ -83,7 +89,7 @@ module Devise
83
89
 
84
90
  # Email regex used to validate email formats. Adapted from authlogic.
85
91
  mattr_accessor :email_regexp
86
- @@email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
92
+ @@email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
87
93
 
88
94
  # Range validation for password length
89
95
  mattr_accessor :password_length
@@ -101,6 +107,11 @@ module Devise
101
107
  mattr_accessor :extend_remember_period
102
108
  @@extend_remember_period = false
103
109
 
110
+ # If true, uses salt as remember token and does not create it in the database.
111
+ # By default is false for backwards compatibility.
112
+ mattr_accessor :use_salt_as_remember_token
113
+ @@use_salt_as_remember_token = false
114
+
104
115
  # Time interval you can access your account before confirming your account.
105
116
  mattr_accessor :confirm_within
106
117
  @@confirm_within = 0.days
@@ -109,14 +120,14 @@ module Devise
109
120
  mattr_accessor :timeout_in
110
121
  @@timeout_in = 30.minutes
111
122
 
123
+ # Used to encrypt password. Please generate one with rake secret.
124
+ mattr_accessor :pepper
125
+ @@pepper = nil
126
+
112
127
  # Used to define the password encryption algorithm.
113
128
  mattr_accessor :encryptor
114
129
  @@encryptor = nil
115
130
 
116
- # Store scopes mappings.
117
- mattr_accessor :mappings
118
- @@mappings = ActiveSupport::OrderedHash.new
119
-
120
131
  # Tells if devise should apply the schema in ORMs where devise declaration
121
132
  # and schema belongs to the same class (as Datamapper and Mongoid).
122
133
  mattr_accessor :apply_schema
@@ -157,32 +168,58 @@ module Devise
157
168
  mattr_accessor :token_authentication_key
158
169
  @@token_authentication_key = :auth_token
159
170
 
171
+ # If true, authentication through token does not store user in session
172
+ mattr_accessor :stateless_token
173
+ @@stateless_token = false
174
+
160
175
  # Which formats should be treated as navigational.
161
176
  mattr_accessor :navigational_formats
162
- @@navigational_formats = [:html]
177
+ @@navigational_formats = [:"*/*", :html]
178
+
179
+ # When set to true, signing out an user signs out all other scopes.
180
+ mattr_accessor :sign_out_all_scopes
181
+ @@sign_out_all_scopes = true
182
+
183
+ # The default method used while signing out
184
+ mattr_accessor :sign_out_via
185
+ @@sign_out_via = :get
186
+
187
+ # PRIVATE CONFIGURATION
188
+
189
+ # Store scopes mappings.
190
+ mattr_reader :mappings
191
+ @@mappings = ActiveSupport::OrderedHash.new
192
+
193
+ # Omniauth configurations.
194
+ mattr_reader :omniauth_configs
195
+ @@omniauth_configs = ActiveSupport::OrderedHash.new
196
+
197
+ # Define a set of modules that are called when a mapping is added.
198
+ mattr_reader :helpers
199
+ @@helpers = Set.new
200
+ @@helpers << Devise::Controllers::Helpers
163
201
 
164
202
  # Private methods to interface with Warden.
165
203
  mattr_accessor :warden_config
166
204
  @@warden_config = nil
167
205
  @@warden_config_block = nil
168
206
 
169
- # When set to true, signing out an user signs out all other scopes.
170
- mattr_accessor :sign_out_all_scopes
171
- @@sign_out_all_scopes = false
172
-
173
- def self.use_default_scope=(*)
174
- ActiveSupport::Deprecation.warn "config.use_default_scope is deprecated and removed from Devise. " <<
175
- "If you are using non conventional routes in Devise, all you need to do is to pass the devise " <<
176
- "scope in the router DSL:\n\n as :user do\n get \"sign_in\", :to => \"devise/sessions\"\n end\n\n" <<
177
- "The method :as is also aliased to :devise_scope. Choose the one you prefer.", caller
178
- end
179
-
180
207
  # Default way to setup Devise. Run rails generate devise_install to create
181
208
  # a fresh initializer with all configuration values.
182
209
  def self.setup
183
210
  yield self
184
211
  end
185
212
 
213
+ def self.omniauth_providers
214
+ omniauth_configs.keys
215
+ end
216
+
217
+ def self.cookie_domain=(value)
218
+ ActiveSupport::Deprecation.warn "Devise.cookie_domain=(value) is deprecated. "
219
+ "Please use Devise.cookie_options = { :domain => value } instead."
220
+ self.cookie_options[:domain] = value
221
+ end
222
+
186
223
  # Get the mailer class from the mailer reference object.
187
224
  def self.mailer
188
225
  @@mailer_ref.get
@@ -197,19 +234,19 @@ module Devise
197
234
  # Small method that adds a mapping to Devise.
198
235
  def self.add_mapping(resource, options)
199
236
  mapping = Devise::Mapping.new(resource, options)
200
- self.mappings[mapping.name] = mapping
201
- self.default_scope ||= mapping.name
237
+ @@mappings[mapping.name] = mapping
238
+ @@default_scope ||= mapping.name
239
+ @@helpers.each { |h| h.define_helpers(mapping) }
202
240
  mapping
203
241
  end
204
242
 
205
- # Make Devise aware of an 3rd party Devise-module. For convenience.
243
+ # Make Devise aware of an 3rd party Devise-module (like invitable). For convenience.
206
244
  #
207
245
  # == Options:
208
246
  #
209
247
  # +model+ - String representing the load path to a custom *model* for this module (to autoload.)
210
248
  # +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
211
249
  # +route+ - Symbol representing the named *route* helper for this module.
212
- # +flash+ - Symbol representing the *flash messages* used by this helper.
213
250
  # +strategy+ - Symbol representing if this module got a custom *strategy*.
214
251
  #
215
252
  # All values, except :model, accept also a boolean and will have the same name as the given module
@@ -225,26 +262,36 @@ module Devise
225
262
  ALL << module_name
226
263
  options.assert_valid_keys(:strategy, :model, :controller, :route)
227
264
 
228
- config = {
229
- :strategy => STRATEGIES,
230
- :route => ROUTES,
231
- :controller => CONTROLLERS
232
- }
265
+ if strategy = options[:strategy]
266
+ STRATEGIES[module_name] = (strategy == true ? module_name : strategy)
267
+ end
233
268
 
234
- config.each do |key, value|
235
- next unless options[key]
236
- name = (options[key] == true ? module_name : options[key])
269
+ if controller = options[:controller]
270
+ CONTROLLERS[module_name] = (controller == true ? module_name : controller)
271
+ end
237
272
 
238
- if value.is_a?(Hash)
239
- value[module_name] = name
273
+ if route = options[:route]
274
+ case route
275
+ when TrueClass
276
+ key, value = module_name, []
277
+ when Symbol
278
+ key, value = route, []
279
+ when Hash
280
+ key, value = route.keys.first, route.values.flatten
240
281
  else
241
- value << name unless value.include?(name)
282
+ raise ArgumentError, ":route should be true, a Symbol or a Hash"
242
283
  end
284
+
285
+ URL_HELPERS[key] ||= []
286
+ URL_HELPERS[key].concat(value)
287
+ URL_HELPERS[key].uniq!
288
+
289
+ ROUTES[module_name] = key
243
290
  end
244
291
 
245
292
  if options[:model]
246
- model_path = (options[:model] == true ? "devise/models/#{module_name}" : options[:model])
247
- Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path)
293
+ path = (options[:model] == true ? "devise/models/#{module_name}" : options[:model])
294
+ Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, path)
248
295
  end
249
296
 
250
297
  Devise::Mapping.add_module module_name
@@ -265,6 +312,27 @@ module Devise
265
312
  @@warden_config_block = block
266
313
  end
267
314
 
315
+ # Specify an omniauth provider.
316
+ #
317
+ # config.omniauth :github, APP_ID, APP_SECRET
318
+ #
319
+ def self.omniauth(provider, *args)
320
+ @@helpers << Devise::OmniAuth::UrlHelpers
321
+ @@omniauth_configs[provider] = Devise::OmniAuth::Config.new(provider, args)
322
+ end
323
+
324
+ # Include helpers in the given scope to AC and AV.
325
+ def self.include_helpers(scope)
326
+ ActiveSupport.on_load(:action_controller) do
327
+ include scope::Helpers if defined?(scope::Helpers)
328
+ include scope::UrlHelpers
329
+ end
330
+
331
+ ActiveSupport.on_load(:action_view) do
332
+ include scope::UrlHelpers
333
+ end
334
+ end
335
+
268
336
  # Returns true if Rails version is bigger than 3.0.x
269
337
  def self.rack_session?
270
338
  Rails::VERSION::STRING[0,3] != "3.0"
@@ -276,6 +344,7 @@ module Devise
276
344
  @@warden_configured ||= begin
277
345
  warden_config.failure_app = Devise::FailureApp
278
346
  warden_config.default_scope = Devise.default_scope
347
+ warden_config.intercept_401 = false
279
348
 
280
349
  Devise.mappings.each_value do |mapping|
281
350
  warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
@@ -288,18 +357,7 @@ module Devise
288
357
 
289
358
  # Generate a friendly string randomically to be used as token.
290
359
  def self.friendly_token
291
- ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
292
- end
293
-
294
- # constant-time comparison algorithm to prevent timing attacks
295
- def self.secure_compare(a, b)
296
- return false unless a.present? && b.present?
297
- return false unless a.bytesize == b.bytesize
298
- l = a.unpack "C#{a.bytesize}"
299
-
300
- res = 0
301
- b.each_byte { |byte| res |= byte ^ l.shift }
302
- res == 0
360
+ ActiveSupport::SecureRandom.base64(44).tr('+/=', 'xyz')
303
361
  end
304
362
  end
305
363