devise 3.2.0 → 4.7.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +260 -949
- data/MIT-LICENSE +1 -1
- data/README.md +383 -100
- data/app/controllers/devise/confirmations_controller.rb +13 -5
- data/app/controllers/devise/omniauth_callbacks_controller.rb +12 -6
- data/app/controllers/devise/passwords_controller.rb +23 -8
- data/app/controllers/devise/registrations_controller.rb +60 -24
- data/app/controllers/devise/sessions_controller.rb +48 -16
- data/app/controllers/devise/unlocks_controller.rb +11 -4
- data/app/controllers/devise_controller.rb +67 -31
- data/app/helpers/devise_helper.rb +12 -19
- data/app/mailers/devise/mailer.rb +10 -0
- data/app/views/devise/confirmations/new.html.erb +9 -5
- data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
- data/app/views/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/devise/mailer/password_change.html.erb +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
- data/app/views/devise/mailer/unlock_instructions.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +16 -7
- data/app/views/devise/passwords/new.html.erb +9 -5
- data/app/views/devise/registrations/edit.html.erb +29 -15
- data/app/views/devise/registrations/new.html.erb +20 -9
- data/app/views/devise/sessions/new.html.erb +19 -10
- data/app/views/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/devise/shared/{_links.erb → _links.html.erb} +9 -9
- data/app/views/devise/unlocks/new.html.erb +9 -5
- data/config/locales/en.yml +23 -17
- data/lib/devise/controllers/helpers.rb +113 -49
- data/lib/devise/controllers/rememberable.rb +15 -6
- data/lib/devise/controllers/scoped_views.rb +3 -1
- data/lib/devise/controllers/sign_in_out.rb +42 -26
- data/lib/devise/controllers/store_location.rb +76 -0
- data/lib/devise/controllers/url_helpers.rb +9 -7
- data/lib/devise/delegator.rb +2 -0
- data/lib/devise/encryptor.rb +24 -0
- data/lib/devise/failure_app.rb +122 -40
- data/lib/devise/hooks/activatable.rb +7 -6
- data/lib/devise/hooks/csrf_cleaner.rb +5 -1
- data/lib/devise/hooks/forgetable.rb +2 -0
- data/lib/devise/hooks/lockable.rb +7 -2
- data/lib/devise/hooks/proxy.rb +4 -2
- data/lib/devise/hooks/rememberable.rb +4 -2
- data/lib/devise/hooks/timeoutable.rb +16 -9
- data/lib/devise/hooks/trackable.rb +3 -1
- data/lib/devise/mailers/helpers.rb +15 -12
- data/lib/devise/mapping.rb +8 -2
- data/lib/devise/models/authenticatable.rb +81 -56
- data/lib/devise/models/confirmable.rb +137 -42
- data/lib/devise/models/database_authenticatable.rb +114 -28
- data/lib/devise/models/lockable.rb +30 -17
- data/lib/devise/models/omniauthable.rb +3 -1
- data/lib/devise/models/recoverable.rb +62 -26
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +62 -33
- data/lib/devise/models/timeoutable.rb +4 -8
- data/lib/devise/models/trackable.rb +20 -4
- data/lib/devise/models/validatable.rb +16 -9
- data/lib/devise/models.rb +3 -1
- data/lib/devise/modules.rb +12 -10
- data/lib/devise/omniauth/config.rb +2 -0
- data/lib/devise/omniauth/url_helpers.rb +14 -5
- data/lib/devise/omniauth.rb +2 -0
- data/lib/devise/orm/active_record.rb +5 -1
- data/lib/devise/orm/mongoid.rb +6 -2
- data/lib/devise/parameter_filter.rb +4 -0
- data/lib/devise/parameter_sanitizer.rb +139 -65
- data/lib/devise/rails/routes.rb +150 -104
- data/lib/devise/rails/warden_compat.rb +3 -10
- data/lib/devise/rails.rb +10 -13
- data/lib/devise/secret_key_finder.rb +27 -0
- data/lib/devise/strategies/authenticatable.rb +21 -10
- data/lib/devise/strategies/base.rb +3 -1
- data/lib/devise/strategies/database_authenticatable.rb +15 -4
- data/lib/devise/strategies/rememberable.rb +15 -3
- data/lib/devise/test/controller_helpers.rb +165 -0
- data/lib/devise/test/integration_helpers.rb +63 -0
- data/lib/devise/test_helpers.rb +7 -124
- data/lib/devise/time_inflector.rb +4 -2
- data/lib/devise/token_generator.rb +3 -41
- data/lib/devise/version.rb +3 -1
- data/lib/devise.rb +111 -83
- data/lib/generators/active_record/devise_generator.rb +49 -12
- data/lib/generators/active_record/templates/migration.rb +9 -7
- data/lib/generators/active_record/templates/migration_existing.rb +9 -7
- data/lib/generators/devise/controllers_generator.rb +46 -0
- data/lib/generators/devise/devise_generator.rb +9 -5
- data/lib/generators/devise/install_generator.rb +22 -0
- data/lib/generators/devise/orm_helpers.rb +10 -21
- data/lib/generators/devise/views_generator.rb +51 -28
- data/lib/generators/mongoid/devise_generator.rb +22 -19
- data/lib/generators/templates/README +5 -12
- data/lib/generators/templates/controllers/README +14 -0
- data/lib/generators/templates/controllers/confirmations_controller.rb +30 -0
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +30 -0
- data/lib/generators/templates/controllers/passwords_controller.rb +34 -0
- data/lib/generators/templates/controllers/registrations_controller.rb +62 -0
- data/lib/generators/templates/controllers/sessions_controller.rb +27 -0
- data/lib/generators/templates/controllers/unlocks_controller.rb +30 -0
- data/lib/generators/templates/devise.rb +81 -36
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +3 -0
- data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +6 -2
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +12 -4
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +5 -2
- data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +14 -6
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +12 -4
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +11 -6
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +5 -2
- metadata +46 -280
- data/.gitignore +0 -10
- data/.travis.yml +0 -20
- data/.yardopts +0 -9
- data/CONTRIBUTING.md +0 -14
- data/Gemfile +0 -31
- data/Gemfile.lock +0 -160
- data/Rakefile +0 -35
- data/devise.gemspec +0 -27
- data/devise.png +0 -0
- data/gemfiles/Gemfile.rails-3.2.x +0 -31
- data/gemfiles/Gemfile.rails-3.2.x.lock +0 -159
- data/test/controllers/custom_strategy_test.rb +0 -62
- data/test/controllers/helpers_test.rb +0 -253
- data/test/controllers/internal_helpers_test.rb +0 -120
- data/test/controllers/passwords_controller_test.rb +0 -31
- data/test/controllers/sessions_controller_test.rb +0 -99
- data/test/controllers/url_helpers_test.rb +0 -59
- data/test/delegator_test.rb +0 -19
- data/test/devise_test.rb +0 -94
- data/test/failure_app_test.rb +0 -232
- data/test/generators/active_record_generator_test.rb +0 -103
- data/test/generators/devise_generator_test.rb +0 -39
- data/test/generators/install_generator_test.rb +0 -13
- data/test/generators/mongoid_generator_test.rb +0 -23
- data/test/generators/views_generator_test.rb +0 -67
- data/test/helpers/devise_helper_test.rb +0 -51
- data/test/integration/authenticatable_test.rb +0 -713
- data/test/integration/confirmable_test.rb +0 -284
- data/test/integration/database_authenticatable_test.rb +0 -84
- data/test/integration/http_authenticatable_test.rb +0 -105
- data/test/integration/lockable_test.rb +0 -239
- data/test/integration/omniauthable_test.rb +0 -133
- data/test/integration/recoverable_test.rb +0 -334
- data/test/integration/registerable_test.rb +0 -349
- data/test/integration/rememberable_test.rb +0 -167
- data/test/integration/timeoutable_test.rb +0 -178
- data/test/integration/trackable_test.rb +0 -92
- data/test/mailers/confirmation_instructions_test.rb +0 -115
- data/test/mailers/reset_password_instructions_test.rb +0 -96
- data/test/mailers/unlock_instructions_test.rb +0 -91
- data/test/mapping_test.rb +0 -127
- data/test/models/authenticatable_test.rb +0 -13
- data/test/models/confirmable_test.rb +0 -454
- data/test/models/database_authenticatable_test.rb +0 -244
- data/test/models/lockable_test.rb +0 -298
- data/test/models/omniauthable_test.rb +0 -7
- data/test/models/recoverable_test.rb +0 -184
- data/test/models/registerable_test.rb +0 -7
- data/test/models/rememberable_test.rb +0 -183
- data/test/models/serializable_test.rb +0 -49
- data/test/models/timeoutable_test.rb +0 -51
- data/test/models/trackable_test.rb +0 -13
- data/test/models/validatable_test.rb +0 -127
- data/test/models_test.rb +0 -144
- data/test/omniauth/config_test.rb +0 -57
- data/test/omniauth/url_helpers_test.rb +0 -54
- data/test/orm/active_record.rb +0 -10
- data/test/orm/mongoid.rb +0 -13
- data/test/parameter_sanitizer_test.rb +0 -81
- data/test/rails_app/Rakefile +0 -6
- data/test/rails_app/app/active_record/admin.rb +0 -6
- data/test/rails_app/app/active_record/shim.rb +0 -2
- data/test/rails_app/app/active_record/user.rb +0 -6
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
- data/test/rails_app/app/controllers/admins_controller.rb +0 -11
- data/test/rails_app/app/controllers/application_controller.rb +0 -9
- data/test/rails_app/app/controllers/home_controller.rb +0 -25
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
- data/test/rails_app/app/controllers/users_controller.rb +0 -31
- data/test/rails_app/app/helpers/application_helper.rb +0 -3
- data/test/rails_app/app/mailers/users/mailer.rb +0 -12
- data/test/rails_app/app/mongoid/admin.rb +0 -29
- data/test/rails_app/app/mongoid/shim.rb +0 -23
- data/test/rails_app/app/mongoid/user.rb +0 -39
- data/test/rails_app/app/views/admins/index.html.erb +0 -1
- data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
- data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/home/index.html.erb +0 -1
- data/test/rails_app/app/views/home/join.html.erb +0 -1
- data/test/rails_app/app/views/home/private.html.erb +0 -1
- data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/layouts/application.html.erb +0 -24
- data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
- data/test/rails_app/app/views/users/index.html.erb +0 -1
- data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
- data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
- data/test/rails_app/bin/bundle +0 -3
- data/test/rails_app/bin/rails +0 -4
- data/test/rails_app/bin/rake +0 -4
- data/test/rails_app/config/application.rb +0 -40
- data/test/rails_app/config/boot.rb +0 -8
- data/test/rails_app/config/database.yml +0 -18
- data/test/rails_app/config/environment.rb +0 -5
- data/test/rails_app/config/environments/development.rb +0 -34
- data/test/rails_app/config/environments/production.rb +0 -84
- data/test/rails_app/config/environments/test.rb +0 -36
- data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
- data/test/rails_app/config/initializers/devise.rb +0 -181
- data/test/rails_app/config/initializers/inflections.rb +0 -2
- data/test/rails_app/config/initializers/secret_token.rb +0 -8
- data/test/rails_app/config/initializers/session_store.rb +0 -1
- data/test/rails_app/config/routes.rb +0 -104
- data/test/rails_app/config.ru +0 -4
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
- data/test/rails_app/db/schema.rb +0 -51
- data/test/rails_app/lib/shared_admin.rb +0 -17
- data/test/rails_app/lib/shared_user.rb +0 -29
- data/test/rails_app/public/404.html +0 -26
- data/test/rails_app/public/422.html +0 -26
- data/test/rails_app/public/500.html +0 -26
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/routes_test.rb +0 -250
- data/test/support/assertions.rb +0 -40
- data/test/support/helpers.rb +0 -70
- data/test/support/integration.rb +0 -92
- data/test/support/locale/en.yml +0 -8
- data/test/support/webrat/integrations/rails.rb +0 -24
- data/test/test_helper.rb +0 -34
- data/test/test_helpers_test.rb +0 -173
- data/test/test_models.rb +0 -26
data/lib/devise.rb
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'rails'
|
|
2
4
|
require 'active_support/core_ext/numeric/time'
|
|
3
5
|
require 'active_support/dependencies'
|
|
4
6
|
require 'orm_adapter'
|
|
5
7
|
require 'set'
|
|
6
8
|
require 'securerandom'
|
|
9
|
+
require 'responders'
|
|
7
10
|
|
|
8
11
|
module Devise
|
|
9
12
|
autoload :Delegator, 'devise/delegator'
|
|
13
|
+
autoload :Encryptor, 'devise/encryptor'
|
|
10
14
|
autoload :FailureApp, 'devise/failure_app'
|
|
11
15
|
autoload :OmniAuth, 'devise/omniauth'
|
|
12
16
|
autoload :ParameterFilter, 'devise/parameter_filter'
|
|
13
|
-
autoload :BaseSanitizer, 'devise/parameter_sanitizer'
|
|
14
17
|
autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
|
|
15
18
|
autoload :TestHelpers, 'devise/test_helpers'
|
|
16
19
|
autoload :TimeInflector, 'devise/time_inflector'
|
|
17
20
|
autoload :TokenGenerator, 'devise/token_generator'
|
|
21
|
+
autoload :SecretKeyFinder, 'devise/secret_key_finder'
|
|
18
22
|
|
|
19
23
|
module Controllers
|
|
20
|
-
autoload :Helpers,
|
|
21
|
-
autoload :Rememberable,
|
|
22
|
-
autoload :ScopedViews,
|
|
23
|
-
autoload :SignInOut,
|
|
24
|
-
autoload :
|
|
24
|
+
autoload :Helpers, 'devise/controllers/helpers'
|
|
25
|
+
autoload :Rememberable, 'devise/controllers/rememberable'
|
|
26
|
+
autoload :ScopedViews, 'devise/controllers/scoped_views'
|
|
27
|
+
autoload :SignInOut, 'devise/controllers/sign_in_out'
|
|
28
|
+
autoload :StoreLocation, 'devise/controllers/store_location'
|
|
29
|
+
autoload :UrlHelpers, 'devise/controllers/url_helpers'
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
module Hooks
|
|
@@ -33,17 +38,22 @@ module Devise
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
module Strategies
|
|
36
|
-
autoload :Base,
|
|
41
|
+
autoload :Base, 'devise/strategies/base'
|
|
37
42
|
autoload :Authenticatable, 'devise/strategies/authenticatable'
|
|
38
43
|
end
|
|
39
44
|
|
|
45
|
+
module Test
|
|
46
|
+
autoload :ControllerHelpers, 'devise/test/controller_helpers'
|
|
47
|
+
autoload :IntegrationHelpers, 'devise/test/integration_helpers'
|
|
48
|
+
end
|
|
49
|
+
|
|
40
50
|
# Constants which holds devise configuration for extensions. Those should
|
|
41
51
|
# not be modified by the "end user" (this is why they are constants).
|
|
42
52
|
ALL = []
|
|
43
|
-
CONTROLLERS =
|
|
44
|
-
ROUTES =
|
|
45
|
-
STRATEGIES =
|
|
46
|
-
URL_HELPERS =
|
|
53
|
+
CONTROLLERS = {}
|
|
54
|
+
ROUTES = {}
|
|
55
|
+
STRATEGIES = {}
|
|
56
|
+
URL_HELPERS = {}
|
|
47
57
|
|
|
48
58
|
# Strategies that do not require user input.
|
|
49
59
|
NO_INPUT = []
|
|
@@ -55,29 +65,13 @@ module Devise
|
|
|
55
65
|
mattr_accessor :secret_key
|
|
56
66
|
@@secret_key = nil
|
|
57
67
|
|
|
58
|
-
[ :allow_insecure_token_lookup,
|
|
59
|
-
:allow_insecure_sign_in_after_confirmation,
|
|
60
|
-
:token_authentication_key ].each do |method|
|
|
61
|
-
class_eval <<-RUBY
|
|
62
|
-
def self.#{method}
|
|
63
|
-
ActiveSupport::Deprecation.warn "Devise.#{method} is deprecated " \
|
|
64
|
-
"and has no effect"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def self.#{method}=(val)
|
|
68
|
-
ActiveSupport::Deprecation.warn "Devise.#{method}= is deprecated " \
|
|
69
|
-
"and has no effect"
|
|
70
|
-
end
|
|
71
|
-
RUBY
|
|
72
|
-
end
|
|
73
|
-
|
|
74
68
|
# Custom domain or key for cookies. Not set by default
|
|
75
69
|
mattr_accessor :rememberable_options
|
|
76
70
|
@@rememberable_options = {}
|
|
77
71
|
|
|
78
|
-
# The number of times to
|
|
72
|
+
# The number of times to hash the password.
|
|
79
73
|
mattr_accessor :stretches
|
|
80
|
-
@@stretches =
|
|
74
|
+
@@stretches = 11
|
|
81
75
|
|
|
82
76
|
# The default key used when authenticating over http auth.
|
|
83
77
|
mattr_accessor :http_authentication_key
|
|
@@ -85,7 +79,7 @@ module Devise
|
|
|
85
79
|
|
|
86
80
|
# Keys used when authenticating a user.
|
|
87
81
|
mattr_accessor :authentication_keys
|
|
88
|
-
@@authentication_keys = [
|
|
82
|
+
@@authentication_keys = [:email]
|
|
89
83
|
|
|
90
84
|
# Request keys used when authenticating a user.
|
|
91
85
|
mattr_accessor :request_keys
|
|
@@ -93,11 +87,11 @@ module Devise
|
|
|
93
87
|
|
|
94
88
|
# Keys that should be case-insensitive.
|
|
95
89
|
mattr_accessor :case_insensitive_keys
|
|
96
|
-
@@case_insensitive_keys = [
|
|
90
|
+
@@case_insensitive_keys = [:email]
|
|
97
91
|
|
|
98
92
|
# Keys that should have whitespace stripped.
|
|
99
93
|
mattr_accessor :strip_whitespace_keys
|
|
100
|
-
@@strip_whitespace_keys = []
|
|
94
|
+
@@strip_whitespace_keys = [:email]
|
|
101
95
|
|
|
102
96
|
# If http authentication is enabled by default.
|
|
103
97
|
mattr_accessor :http_authenticatable
|
|
@@ -115,11 +109,11 @@ module Devise
|
|
|
115
109
|
mattr_accessor :http_authentication_realm
|
|
116
110
|
@@http_authentication_realm = "Application"
|
|
117
111
|
|
|
118
|
-
# Email regex used to validate email formats. It
|
|
119
|
-
#
|
|
120
|
-
#
|
|
112
|
+
# Email regex used to validate email formats. It asserts that there are no
|
|
113
|
+
# @ symbols or whitespaces in either the localpart or the domain, and that
|
|
114
|
+
# there is a single @ symbol separating the localpart and the domain.
|
|
121
115
|
mattr_accessor :email_regexp
|
|
122
|
-
@@email_regexp = /\A[^@\s]+@
|
|
116
|
+
@@email_regexp = /\A[^@\s]+@[^@\s]+\z/
|
|
123
117
|
|
|
124
118
|
# Range validation for password length
|
|
125
119
|
mattr_accessor :password_length
|
|
@@ -133,6 +127,10 @@ module Devise
|
|
|
133
127
|
mattr_accessor :extend_remember_period
|
|
134
128
|
@@extend_remember_period = false
|
|
135
129
|
|
|
130
|
+
# If true, all the remember me tokens are going to be invalidated when the user signs out.
|
|
131
|
+
mattr_accessor :expire_all_remember_me_on_sign_out
|
|
132
|
+
@@expire_all_remember_me_on_sign_out = true
|
|
133
|
+
|
|
136
134
|
# Time interval you can access your account before confirming your account.
|
|
137
135
|
# nil - allows unconfirmed access for unlimited time
|
|
138
136
|
mattr_accessor :allow_unconfirmed_access_for
|
|
@@ -144,25 +142,28 @@ module Devise
|
|
|
144
142
|
|
|
145
143
|
# Defines which key will be used when confirming an account.
|
|
146
144
|
mattr_accessor :confirmation_keys
|
|
147
|
-
@@confirmation_keys = [
|
|
145
|
+
@@confirmation_keys = [:email]
|
|
148
146
|
|
|
149
147
|
# Defines if email should be reconfirmable.
|
|
150
|
-
# False by default for backwards compatibility.
|
|
151
148
|
mattr_accessor :reconfirmable
|
|
152
|
-
@@reconfirmable =
|
|
149
|
+
@@reconfirmable = true
|
|
153
150
|
|
|
154
151
|
# Time interval to timeout the user session without activity.
|
|
155
152
|
mattr_accessor :timeout_in
|
|
156
153
|
@@timeout_in = 30.minutes
|
|
157
154
|
|
|
158
|
-
#
|
|
159
|
-
mattr_accessor :expire_auth_token_on_timeout
|
|
160
|
-
@@expire_auth_token_on_timeout = false
|
|
161
|
-
|
|
162
|
-
# Used to encrypt password. Please generate one with rake secret.
|
|
155
|
+
# Used to hash the password. Please generate one with rails secret.
|
|
163
156
|
mattr_accessor :pepper
|
|
164
157
|
@@pepper = nil
|
|
165
158
|
|
|
159
|
+
# Used to send notification to the original user email when their email is changed.
|
|
160
|
+
mattr_accessor :send_email_changed_notification
|
|
161
|
+
@@send_email_changed_notification = false
|
|
162
|
+
|
|
163
|
+
# Used to enable sending notification to user when their password is changed.
|
|
164
|
+
mattr_accessor :send_password_change_notification
|
|
165
|
+
@@send_password_change_notification = false
|
|
166
|
+
|
|
166
167
|
# Scoped views. Since it relies on fallbacks to render default views, it's
|
|
167
168
|
# turned off by default.
|
|
168
169
|
mattr_accessor :scoped_views
|
|
@@ -175,7 +176,7 @@ module Devise
|
|
|
175
176
|
|
|
176
177
|
# Defines which key will be used when locking and unlocking an account
|
|
177
178
|
mattr_accessor :unlock_keys
|
|
178
|
-
@@unlock_keys = [
|
|
179
|
+
@@unlock_keys = [:email]
|
|
179
180
|
|
|
180
181
|
# Defines which strategy can be used to unlock an account.
|
|
181
182
|
# Values: :email, :time, :both
|
|
@@ -192,12 +193,16 @@ module Devise
|
|
|
192
193
|
|
|
193
194
|
# Defines which key will be used when recovering the password for an account
|
|
194
195
|
mattr_accessor :reset_password_keys
|
|
195
|
-
@@reset_password_keys = [
|
|
196
|
+
@@reset_password_keys = [:email]
|
|
196
197
|
|
|
197
198
|
# Time interval you can reset your password with a reset password key
|
|
198
199
|
mattr_accessor :reset_password_within
|
|
199
200
|
@@reset_password_within = 6.hours
|
|
200
201
|
|
|
202
|
+
# When set to false, resetting a password does not automatically sign in a user
|
|
203
|
+
mattr_accessor :sign_in_after_reset_password
|
|
204
|
+
@@sign_in_after_reset_password = true
|
|
205
|
+
|
|
201
206
|
# The default scope which is used by warden.
|
|
202
207
|
mattr_accessor :default_scope
|
|
203
208
|
@@default_scope = nil
|
|
@@ -208,7 +213,7 @@ module Devise
|
|
|
208
213
|
|
|
209
214
|
# Skip session storage for the following strategies
|
|
210
215
|
mattr_accessor :skip_session_storage
|
|
211
|
-
@@skip_session_storage = []
|
|
216
|
+
@@skip_session_storage = [:http_auth]
|
|
212
217
|
|
|
213
218
|
# Which formats should be treated as navigational.
|
|
214
219
|
mattr_accessor :navigational_formats
|
|
@@ -220,7 +225,7 @@ module Devise
|
|
|
220
225
|
|
|
221
226
|
# The default method used while signing out
|
|
222
227
|
mattr_accessor :sign_out_via
|
|
223
|
-
@@sign_out_via = :
|
|
228
|
+
@@sign_out_via = :delete
|
|
224
229
|
|
|
225
230
|
# The parent controller all Devise controllers inherits from.
|
|
226
231
|
# Defaults to ApplicationController. This should be set early
|
|
@@ -235,12 +240,12 @@ module Devise
|
|
|
235
240
|
@@parent_mailer = "ActionMailer::Base"
|
|
236
241
|
|
|
237
242
|
# The router Devise should use to generate routes. Defaults
|
|
238
|
-
# to :main_app. Should be
|
|
243
|
+
# to :main_app. Should be overridden by engines in order
|
|
239
244
|
# to provide custom routes.
|
|
240
245
|
mattr_accessor :router_name
|
|
241
246
|
@@router_name = nil
|
|
242
247
|
|
|
243
|
-
# Set the
|
|
248
|
+
# Set the OmniAuth path prefix so it can be overridden when
|
|
244
249
|
# Devise is used in a mountable engine
|
|
245
250
|
mattr_accessor :omniauth_path_prefix
|
|
246
251
|
@@omniauth_path_prefix = nil
|
|
@@ -249,15 +254,22 @@ module Devise
|
|
|
249
254
|
mattr_accessor :clean_up_csrf_token_on_authentication
|
|
250
255
|
@@clean_up_csrf_token_on_authentication = true
|
|
251
256
|
|
|
257
|
+
# When false, Devise will not attempt to reload routes on eager load.
|
|
258
|
+
# This can reduce the time taken to boot the app but if your application
|
|
259
|
+
# requires the Devise mappings to be loaded during boot time the application
|
|
260
|
+
# won't boot properly.
|
|
261
|
+
mattr_accessor :reload_routes
|
|
262
|
+
@@reload_routes = true
|
|
263
|
+
|
|
252
264
|
# PRIVATE CONFIGURATION
|
|
253
265
|
|
|
254
266
|
# Store scopes mappings.
|
|
255
267
|
mattr_reader :mappings
|
|
256
|
-
@@mappings =
|
|
268
|
+
@@mappings = {}
|
|
257
269
|
|
|
258
|
-
#
|
|
270
|
+
# OmniAuth configurations.
|
|
259
271
|
mattr_reader :omniauth_configs
|
|
260
|
-
@@omniauth_configs =
|
|
272
|
+
@@omniauth_configs = {}
|
|
261
273
|
|
|
262
274
|
# Define a set of modules that are called when a mapping is added.
|
|
263
275
|
mattr_reader :helpers
|
|
@@ -267,28 +279,40 @@ module Devise
|
|
|
267
279
|
# Private methods to interface with Warden.
|
|
268
280
|
mattr_accessor :warden_config
|
|
269
281
|
@@warden_config = nil
|
|
270
|
-
@@
|
|
282
|
+
@@warden_config_blocks = []
|
|
271
283
|
|
|
272
284
|
# When true, enter in paranoid mode to avoid user enumeration.
|
|
273
285
|
mattr_accessor :paranoid
|
|
274
286
|
@@paranoid = false
|
|
275
287
|
|
|
276
|
-
# When true, warn user if
|
|
288
|
+
# When true, warn user if they just used next-to-last attempt of authentication
|
|
277
289
|
mattr_accessor :last_attempt_warning
|
|
278
|
-
@@last_attempt_warning =
|
|
290
|
+
@@last_attempt_warning = true
|
|
279
291
|
|
|
280
292
|
# Stores the token generator
|
|
281
293
|
mattr_accessor :token_generator
|
|
282
294
|
@@token_generator = nil
|
|
283
295
|
|
|
284
|
-
#
|
|
296
|
+
# When set to false, changing a password does not automatically sign in a user
|
|
297
|
+
mattr_accessor :sign_in_after_change_password
|
|
298
|
+
@@sign_in_after_change_password = true
|
|
299
|
+
|
|
300
|
+
def self.rails51? # :nodoc:
|
|
301
|
+
Rails.gem_version >= Gem::Version.new("5.1.x")
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def self.activerecord51? # :nodoc:
|
|
305
|
+
defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Default way to set up Devise. Run rails generate devise_install to create
|
|
285
309
|
# a fresh initializer with all configuration values.
|
|
286
310
|
def self.setup
|
|
287
311
|
yield self
|
|
288
312
|
end
|
|
289
313
|
|
|
290
314
|
class Getter
|
|
291
|
-
def initialize
|
|
315
|
+
def initialize(name)
|
|
292
316
|
@name = name
|
|
293
317
|
end
|
|
294
318
|
|
|
@@ -298,12 +322,8 @@ module Devise
|
|
|
298
322
|
end
|
|
299
323
|
|
|
300
324
|
def self.ref(arg)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Getter.new(arg)
|
|
304
|
-
else
|
|
305
|
-
ActiveSupport::Dependencies.ref(arg)
|
|
306
|
-
end
|
|
325
|
+
ActiveSupport::Dependencies.reference(arg)
|
|
326
|
+
Getter.new(arg)
|
|
307
327
|
end
|
|
308
328
|
|
|
309
329
|
def self.available_router_name
|
|
@@ -334,7 +354,12 @@ module Devise
|
|
|
334
354
|
mapping
|
|
335
355
|
end
|
|
336
356
|
|
|
337
|
-
#
|
|
357
|
+
# Register available devise modules. For the standard modules that Devise provides, this method is
|
|
358
|
+
# called from lib/devise/modules.rb. Third-party modules need to be added explicitly using this method.
|
|
359
|
+
#
|
|
360
|
+
# Note that adding a module using this method does not cause it to be used in the authentication
|
|
361
|
+
# process. That requires that the module be listed in the arguments passed to the 'devise' method
|
|
362
|
+
# in the model class definition.
|
|
338
363
|
#
|
|
339
364
|
# == Options:
|
|
340
365
|
#
|
|
@@ -342,6 +367,7 @@ module Devise
|
|
|
342
367
|
# +controller+ - Symbol representing the name of an existing or custom *controller* for this module.
|
|
343
368
|
# +route+ - Symbol representing the named *route* helper for this module.
|
|
344
369
|
# +strategy+ - Symbol representing if this module got a custom *strategy*.
|
|
370
|
+
# +insert_at+ - Integer representing the order in which this module's model will be included
|
|
345
371
|
#
|
|
346
372
|
# All values, except :model, accept also a boolean and will have the same name as the given module
|
|
347
373
|
# name.
|
|
@@ -349,12 +375,14 @@ module Devise
|
|
|
349
375
|
# == Examples:
|
|
350
376
|
#
|
|
351
377
|
# Devise.add_module(:party_module)
|
|
352
|
-
# Devise.add_module(:party_module, :
|
|
353
|
-
# Devise.add_module(:party_module, :
|
|
378
|
+
# Devise.add_module(:party_module, strategy: true, controller: :sessions)
|
|
379
|
+
# Devise.add_module(:party_module, model: 'party_module/model')
|
|
380
|
+
# Devise.add_module(:party_module, insert_at: 0)
|
|
354
381
|
#
|
|
355
382
|
def self.add_module(module_name, options = {})
|
|
356
|
-
|
|
357
|
-
|
|
383
|
+
options.assert_valid_keys(:strategy, :model, :controller, :route, :no_input, :insert_at)
|
|
384
|
+
|
|
385
|
+
ALL.insert (options[:insert_at] || -1), module_name
|
|
358
386
|
|
|
359
387
|
if strategy = options[:strategy]
|
|
360
388
|
strategy = (strategy == true ? module_name : strategy)
|
|
@@ -399,7 +427,7 @@ module Devise
|
|
|
399
427
|
# Sets warden configuration using a block that will be invoked on warden
|
|
400
428
|
# initialization.
|
|
401
429
|
#
|
|
402
|
-
# Devise.
|
|
430
|
+
# Devise.setup do |config|
|
|
403
431
|
# config.allow_unconfirmed_access_for = 2.days
|
|
404
432
|
#
|
|
405
433
|
# config.warden do |manager|
|
|
@@ -408,15 +436,14 @@ module Devise
|
|
|
408
436
|
# end
|
|
409
437
|
# end
|
|
410
438
|
def self.warden(&block)
|
|
411
|
-
@@
|
|
439
|
+
@@warden_config_blocks << block
|
|
412
440
|
end
|
|
413
441
|
|
|
414
|
-
# Specify an
|
|
442
|
+
# Specify an OmniAuth provider.
|
|
415
443
|
#
|
|
416
444
|
# config.omniauth :github, APP_ID, APP_SECRET
|
|
417
445
|
#
|
|
418
446
|
def self.omniauth(provider, *args)
|
|
419
|
-
@@helpers << Devise::OmniAuth::UrlHelpers
|
|
420
447
|
config = Devise::OmniAuth::Config.new(provider, args)
|
|
421
448
|
@@omniauth_configs[config.strategy_name.to_sym] = config
|
|
422
449
|
end
|
|
@@ -439,8 +466,8 @@ module Devise
|
|
|
439
466
|
Devise::Controllers::UrlHelpers.generate_helpers!
|
|
440
467
|
end
|
|
441
468
|
|
|
442
|
-
# A method used internally to setup warden manager
|
|
443
|
-
#
|
|
469
|
+
# A method used internally to complete the setup of warden manager after routes are loaded.
|
|
470
|
+
# See lib/devise/rails/routes.rb - ActionDispatch::Routing::RouteSet#finalize_with_devise!
|
|
444
471
|
def self.configure_warden! #:nodoc:
|
|
445
472
|
@@warden_configured ||= begin
|
|
446
473
|
warden_config.failure_app = Devise::Delegator.new
|
|
@@ -448,28 +475,29 @@ module Devise
|
|
|
448
475
|
warden_config.intercept_401 = false
|
|
449
476
|
|
|
450
477
|
Devise.mappings.each_value do |mapping|
|
|
451
|
-
warden_config.scope_defaults mapping.name, :
|
|
478
|
+
warden_config.scope_defaults mapping.name, strategies: mapping.strategies
|
|
452
479
|
|
|
453
480
|
warden_config.serialize_into_session(mapping.name) do |record|
|
|
454
481
|
mapping.to.serialize_into_session(record)
|
|
455
482
|
end
|
|
456
483
|
|
|
457
|
-
warden_config.serialize_from_session(mapping.name) do |
|
|
458
|
-
# Previous versions contained an additional entry at the beginning of
|
|
459
|
-
# key with the record's class name.
|
|
460
|
-
args = key[-2, 2]
|
|
484
|
+
warden_config.serialize_from_session(mapping.name) do |args|
|
|
461
485
|
mapping.to.serialize_from_session(*args)
|
|
462
486
|
end
|
|
463
487
|
end
|
|
464
488
|
|
|
465
|
-
@@
|
|
489
|
+
@@warden_config_blocks.map { |block| block.call Devise.warden_config }
|
|
466
490
|
true
|
|
467
491
|
end
|
|
468
492
|
end
|
|
469
493
|
|
|
470
494
|
# Generate a friendly string randomly to be used as token.
|
|
471
|
-
|
|
472
|
-
|
|
495
|
+
# By default, length is 20 characters.
|
|
496
|
+
def self.friendly_token(length = 20)
|
|
497
|
+
# To calculate real characters, we must perform this operation.
|
|
498
|
+
# See SecureRandom.urlsafe_base64
|
|
499
|
+
rlength = (length * 3) / 4
|
|
500
|
+
SecureRandom.urlsafe_base64(rlength).tr('lIO0', 'sxyz')
|
|
473
501
|
end
|
|
474
502
|
|
|
475
503
|
# constant-time comparison algorithm to prevent timing attacks
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'rails/generators/active_record'
|
|
2
4
|
require 'generators/devise/orm_helpers'
|
|
3
5
|
|
|
4
6
|
module ActiveRecord
|
|
5
7
|
module Generators
|
|
6
8
|
class DeviseGenerator < ActiveRecord::Generators::Base
|
|
7
|
-
argument :attributes, :
|
|
9
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
10
|
+
|
|
11
|
+
class_option :primary_key_type, type: :string, desc: "The type for primary key"
|
|
8
12
|
|
|
9
13
|
include Devise::Generators::OrmHelpers
|
|
10
14
|
source_root File.expand_path("../templates", __FILE__)
|
|
11
15
|
|
|
12
16
|
def copy_devise_migration
|
|
13
17
|
if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
|
14
|
-
migration_template "migration_existing.rb", "
|
|
18
|
+
migration_template "migration_existing.rb", "#{migration_path}/add_devise_to_#{table_name}.rb", migration_version: migration_version
|
|
15
19
|
else
|
|
16
|
-
migration_template "migration.rb", "
|
|
20
|
+
migration_template "migration.rb", "#{migration_path}/devise_create_#{table_name}.rb", migration_version: migration_version
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
def generate_model
|
|
21
|
-
invoke "active_record:model", [name], :
|
|
25
|
+
invoke "active_record:model", [name], migration: false unless model_exists? && behavior == :invoke
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
def inject_devise_content
|
|
@@ -39,8 +43,8 @@ module ActiveRecord
|
|
|
39
43
|
def migration_data
|
|
40
44
|
<<RUBY
|
|
41
45
|
## Database authenticatable
|
|
42
|
-
t.string :email, :
|
|
43
|
-
t.string :encrypted_password, :
|
|
46
|
+
t.string :email, null: false, default: ""
|
|
47
|
+
t.string :encrypted_password, null: false, default: ""
|
|
44
48
|
|
|
45
49
|
## Recoverable
|
|
46
50
|
t.string :reset_password_token
|
|
@@ -50,11 +54,11 @@ module ActiveRecord
|
|
|
50
54
|
t.datetime :remember_created_at
|
|
51
55
|
|
|
52
56
|
## Trackable
|
|
53
|
-
t.integer :sign_in_count, :
|
|
54
|
-
t.datetime :current_sign_in_at
|
|
55
|
-
t.datetime :last_sign_in_at
|
|
56
|
-
t
|
|
57
|
-
t
|
|
57
|
+
# t.integer :sign_in_count, default: 0, null: false
|
|
58
|
+
# t.datetime :current_sign_in_at
|
|
59
|
+
# t.datetime :last_sign_in_at
|
|
60
|
+
# t.#{ip_column} :current_sign_in_ip
|
|
61
|
+
# t.#{ip_column} :last_sign_in_ip
|
|
58
62
|
|
|
59
63
|
## Confirmable
|
|
60
64
|
# t.string :confirmation_token
|
|
@@ -63,11 +67,44 @@ module ActiveRecord
|
|
|
63
67
|
# t.string :unconfirmed_email # Only if using reconfirmable
|
|
64
68
|
|
|
65
69
|
## Lockable
|
|
66
|
-
# t.integer :failed_attempts, :
|
|
70
|
+
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
|
|
67
71
|
# t.string :unlock_token # Only if unlock strategy is :email or :both
|
|
68
72
|
# t.datetime :locked_at
|
|
69
73
|
RUBY
|
|
70
74
|
end
|
|
75
|
+
|
|
76
|
+
def ip_column
|
|
77
|
+
# Padded with spaces so it aligns nicely with the rest of the columns.
|
|
78
|
+
"%-8s" % (inet? ? "inet" : "string")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def inet?
|
|
82
|
+
postgresql?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def rails5_and_up?
|
|
86
|
+
Rails::VERSION::MAJOR >= 5
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def postgresql?
|
|
90
|
+
config = ActiveRecord::Base.configurations[Rails.env]
|
|
91
|
+
config && config['adapter'] == 'postgresql'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def migration_version
|
|
95
|
+
if rails5_and_up?
|
|
96
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def primary_key_type
|
|
101
|
+
primary_key_string if rails5_and_up?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def primary_key_string
|
|
105
|
+
key_string = options[:primary_key_type]
|
|
106
|
+
", id: :#{key_string}" if key_string
|
|
107
|
+
end
|
|
71
108
|
end
|
|
72
109
|
end
|
|
73
110
|
end
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
4
|
def change
|
|
3
|
-
create_table
|
|
5
|
+
create_table :<%= table_name %><%= primary_key_type %> do |t|
|
|
4
6
|
<%= migration_data -%>
|
|
5
7
|
|
|
6
8
|
<% attributes.each do |attribute| -%>
|
|
7
9
|
t.<%= attribute.type %> :<%= attribute.name %>
|
|
8
10
|
<% end -%>
|
|
9
11
|
|
|
10
|
-
t.timestamps
|
|
12
|
+
t.timestamps null: false
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
add_index :<%= table_name %>, :email, :
|
|
14
|
-
add_index :<%= table_name %>, :reset_password_token, :
|
|
15
|
-
# add_index :<%= table_name %>, :confirmation_token, :
|
|
16
|
-
# add_index :<%= table_name %>, :unlock_token, :
|
|
15
|
+
add_index :<%= table_name %>, :email, unique: true
|
|
16
|
+
add_index :<%= table_name %>, :reset_password_token, unique: true
|
|
17
|
+
# add_index :<%= table_name %>, :confirmation_token, unique: true
|
|
18
|
+
# add_index :<%= table_name %>, :unlock_token, unique: true
|
|
17
19
|
end
|
|
18
20
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddDeviseTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
4
|
def self.up
|
|
3
|
-
change_table
|
|
5
|
+
change_table :<%= table_name %> do |t|
|
|
4
6
|
<%= migration_data -%>
|
|
5
7
|
|
|
6
8
|
<% attributes.each do |attribute| -%>
|
|
@@ -8,13 +10,13 @@ class AddDeviseTo<%= table_name.camelize %> < ActiveRecord::Migration
|
|
|
8
10
|
<% end -%>
|
|
9
11
|
|
|
10
12
|
# Uncomment below if timestamps were not included in your original model.
|
|
11
|
-
# t.timestamps
|
|
13
|
+
# t.timestamps null: false
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
add_index :<%= table_name %>, :email, :
|
|
15
|
-
add_index :<%= table_name %>, :reset_password_token, :
|
|
16
|
-
# add_index :<%= table_name %>, :confirmation_token, :
|
|
17
|
-
# add_index :<%= table_name %>, :unlock_token, :
|
|
16
|
+
add_index :<%= table_name %>, :email, unique: true
|
|
17
|
+
add_index :<%= table_name %>, :reset_password_token, unique: true
|
|
18
|
+
# add_index :<%= table_name %>, :confirmation_token, unique: true
|
|
19
|
+
# add_index :<%= table_name %>, :unlock_token, unique: true
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def self.down
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/base'
|
|
4
|
+
|
|
5
|
+
module Devise
|
|
6
|
+
module Generators
|
|
7
|
+
class ControllersGenerator < Rails::Generators::Base
|
|
8
|
+
CONTROLLERS = %w(confirmations passwords registrations sessions unlocks omniauth_callbacks).freeze
|
|
9
|
+
|
|
10
|
+
desc <<-DESC.strip_heredoc
|
|
11
|
+
Create inherited Devise controllers in your app/controllers folder.
|
|
12
|
+
|
|
13
|
+
Use -c to specify which controller you want to overwrite.
|
|
14
|
+
If you do no specify a controller, all controllers will be created.
|
|
15
|
+
For example:
|
|
16
|
+
|
|
17
|
+
rails generate devise:controllers users -c=sessions
|
|
18
|
+
|
|
19
|
+
This will create a controller class at app/controllers/users/sessions_controller.rb like this:
|
|
20
|
+
|
|
21
|
+
class Users::SessionsController < Devise::SessionsController
|
|
22
|
+
content...
|
|
23
|
+
end
|
|
24
|
+
DESC
|
|
25
|
+
|
|
26
|
+
source_root File.expand_path("../../templates/controllers", __FILE__)
|
|
27
|
+
argument :scope, required: true,
|
|
28
|
+
desc: "The scope to create controllers in, e.g. users, admins"
|
|
29
|
+
class_option :controllers, aliases: "-c", type: :array,
|
|
30
|
+
desc: "Select specific controllers to generate (#{CONTROLLERS.join(', ')})"
|
|
31
|
+
|
|
32
|
+
def create_controllers
|
|
33
|
+
@scope_prefix = scope.blank? ? '' : (scope.camelize + '::')
|
|
34
|
+
controllers = options[:controllers] || CONTROLLERS
|
|
35
|
+
controllers.each do |name|
|
|
36
|
+
template "#{name}_controller.rb",
|
|
37
|
+
"app/controllers/#{scope}/#{name}_controller.rb"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def show_readme
|
|
42
|
+
readme "README" if behavior == :invoke
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|