restful-authentication 1.2.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.
Files changed (53) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +227 -0
  3. data/Rakefile +33 -0
  4. data/TODO +15 -0
  5. data/init.rb +5 -0
  6. data/lib/authentication.rb +40 -0
  7. data/lib/authentication/by_cookie_token.rb +82 -0
  8. data/lib/authentication/by_password.rb +65 -0
  9. data/lib/authorization.rb +14 -0
  10. data/lib/authorization/aasm_roles.rb +74 -0
  11. data/lib/authorization/stateful_roles.rb +62 -0
  12. data/lib/generators/authenticated/USAGE +1 -0
  13. data/lib/generators/authenticated/authenticated_generator.rb +524 -0
  14. data/lib/generators/authenticated/templates/_model_partial.html.erb +8 -0
  15. data/lib/generators/authenticated/templates/activation.erb +3 -0
  16. data/lib/generators/authenticated/templates/authenticated_system.rb +189 -0
  17. data/lib/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  18. data/lib/generators/authenticated/templates/controller.rb +41 -0
  19. data/lib/generators/authenticated/templates/features/accounts.feature +109 -0
  20. data/lib/generators/authenticated/templates/features/sessions.feature +134 -0
  21. data/lib/generators/authenticated/templates/features/step_definitions/ra_env.rb +9 -0
  22. data/lib/generators/authenticated/templates/features/step_definitions/ra_navigation_steps.rb +48 -0
  23. data/lib/generators/authenticated/templates/features/step_definitions/ra_resource_steps.rb +178 -0
  24. data/lib/generators/authenticated/templates/features/step_definitions/ra_response_steps.rb +169 -0
  25. data/lib/generators/authenticated/templates/features/step_definitions/rest_auth_features_helper.rb +81 -0
  26. data/lib/generators/authenticated/templates/features/step_definitions/user_steps.rb +131 -0
  27. data/lib/generators/authenticated/templates/helper.rb +2 -0
  28. data/lib/generators/authenticated/templates/login.html.erb +16 -0
  29. data/lib/generators/authenticated/templates/mailer.rb +26 -0
  30. data/lib/generators/authenticated/templates/migration.rb +26 -0
  31. data/lib/generators/authenticated/templates/model.rb +87 -0
  32. data/lib/generators/authenticated/templates/model_controller.rb +83 -0
  33. data/lib/generators/authenticated/templates/model_helper.rb +93 -0
  34. data/lib/generators/authenticated/templates/model_helper_spec.rb +158 -0
  35. data/lib/generators/authenticated/templates/observer.rb +11 -0
  36. data/lib/generators/authenticated/templates/signup.html.erb +19 -0
  37. data/lib/generators/authenticated/templates/signup_notification.erb +8 -0
  38. data/lib/generators/authenticated/templates/site_keys.rb +38 -0
  39. data/lib/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  40. data/lib/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  41. data/lib/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  42. data/lib/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +198 -0
  43. data/lib/generators/authenticated/templates/spec/fixtures/users.yml +60 -0
  44. data/lib/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  45. data/lib/generators/authenticated/templates/spec/models/user_spec.rb +290 -0
  46. data/lib/generators/authenticated/templates/test/functional_test.rb +82 -0
  47. data/lib/generators/authenticated/templates/test/mailer_test.rb +32 -0
  48. data/lib/generators/authenticated/templates/test/model_functional_test.rb +93 -0
  49. data/lib/generators/authenticated/templates/test/unit_test.rb +164 -0
  50. data/lib/tasks/auth.rake +33 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. metadata +105 -0
@@ -0,0 +1,65 @@
1
+ module Authentication
2
+ module ByPassword
3
+ # Stuff directives into including module
4
+ def self.included(recipient)
5
+ recipient.extend(ModelClassMethods)
6
+ recipient.class_eval do
7
+ include ModelInstanceMethods
8
+
9
+ # Virtual attribute for the unencrypted password
10
+ attr_accessor :password
11
+ validates_presence_of :password, :if => :password_required?
12
+ validates_presence_of :password_confirmation, :if => :password_required?
13
+ validates_confirmation_of :password, :if => :password_required?
14
+ validates_length_of :password, :within => 6..40, :if => :password_required?
15
+ before_save :encrypt_password
16
+ end
17
+ end # #included directives
18
+
19
+ #
20
+ # Class Methods
21
+ #
22
+ module ModelClassMethods
23
+ # This provides a modest increased defense against a dictionary attack if
24
+ # your db were ever compromised, but will invalidate existing passwords.
25
+ # See the README and the file config/initializers/site_keys.rb
26
+ #
27
+ # It may not be obvious, but if you set REST_AUTH_SITE_KEY to nil and
28
+ # REST_AUTH_DIGEST_STRETCHES to 1 you'll have backwards compatibility with
29
+ # older versions of restful-authentication.
30
+ def password_digest(password, salt)
31
+ digest = REST_AUTH_SITE_KEY
32
+ REST_AUTH_DIGEST_STRETCHES.times do
33
+ digest = secure_digest(digest, salt, password, REST_AUTH_SITE_KEY)
34
+ end
35
+ digest
36
+ end
37
+ end # class methods
38
+
39
+ #
40
+ # Instance Methods
41
+ #
42
+ module ModelInstanceMethods
43
+
44
+ # Encrypts the password with the user salt
45
+ def encrypt(password)
46
+ self.class.password_digest(password, salt)
47
+ end
48
+
49
+ def authenticated?(password)
50
+ crypted_password == encrypt(password)
51
+ end
52
+
53
+ # before filter
54
+ def encrypt_password
55
+ return if password.blank?
56
+ self.salt = self.class.make_token if new_record?
57
+ self.crypted_password = encrypt(password)
58
+ end
59
+ def password_required?
60
+ #crypted_password.blank? || !password.blank?
61
+ !password.nil?
62
+ end
63
+ end # instance methods
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ module Authorization
2
+ def self.included(recipient)
3
+ recipient.extend(ModelClassMethods)
4
+ recipient.class_eval do
5
+ include ModelInstanceMethods
6
+ end
7
+ end
8
+
9
+ module ModelClassMethods
10
+ end # class methods
11
+
12
+ module ModelInstanceMethods
13
+ end # instance methods
14
+ end
@@ -0,0 +1,74 @@
1
+ module Authorization
2
+ module AasmRoles
3
+ unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
4
+ STATEFUL_ROLES_CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
5
+ end
6
+
7
+
8
+ def self.included( recipient )
9
+ recipient.extend( StatefulRolesClassMethods )
10
+ recipient.class_eval do
11
+ include StatefulRolesInstanceMethods
12
+ include ActiveRecord::Transitions
13
+
14
+ state_machine do
15
+
16
+ state :passive
17
+ state :active #, :enter => :do_activate
18
+ state :suspended
19
+ state :deleted, :enter => :do_delete
20
+
21
+ event :register do
22
+ # transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
23
+ transitions :from => :passive, :to => :active#, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
24
+ end
25
+
26
+ # event :activate do
27
+ # transitions :from => :pending, :to => :active
28
+ # end
29
+
30
+ event :suspend do
31
+ # transitions :from => [:passive, :pending, :active], :to => :suspended
32
+ transitions :from => [:passive, :active], :to => :suspended
33
+ end
34
+
35
+ event :delete do
36
+ # transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
37
+ transitions :from => [:passive, :active, :suspended], :to => :deleted
38
+ end
39
+
40
+ event :unsuspend do
41
+ # transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.activated_at.blank? }
42
+ transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.crypted_password.blank? }
43
+ # transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
44
+ transitions :from => :suspended, :to => :passive
45
+ end
46
+
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ module StatefulRolesClassMethods
54
+
55
+ end # class methods
56
+
57
+ module StatefulRolesInstanceMethods
58
+ # Returns true if the user has just been activated.
59
+ # def recently_activated?
60
+ # @activated
61
+ # end
62
+
63
+ def do_delete
64
+ self.deleted_at = Time.now.utc
65
+ end
66
+
67
+ # def do_activate
68
+ # @activated = true
69
+ # self.activated_at = Time.now.utc
70
+ # self.deleted_at = self.activation_code = nil
71
+ # end
72
+ end # instance methods
73
+ end
74
+ end
@@ -0,0 +1,62 @@
1
+ module Authorization
2
+ module StatefulRoles
3
+ unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
4
+ STATEFUL_ROLES_CONSTANTS_DEFINED = true # sorry for the C idiom
5
+ end
6
+
7
+ def self.included( recipient )
8
+ recipient.extend( StatefulRolesClassMethods )
9
+ recipient.class_eval do
10
+ include StatefulRolesInstanceMethods
11
+
12
+ acts_as_state_machine :initial => :pending
13
+ state :passive
14
+ state :pending, :enter => :make_activation_code
15
+ state :active, :enter => :do_activate
16
+ state :suspended
17
+ state :deleted, :enter => :do_delete
18
+
19
+ event :register do
20
+ transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
21
+ end
22
+
23
+ event :activate do
24
+ transitions :from => :pending, :to => :active
25
+ end
26
+
27
+ event :suspend do
28
+ transitions :from => [:passive, :pending, :active], :to => :suspended
29
+ end
30
+
31
+ event :delete do
32
+ transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
33
+ end
34
+
35
+ event :unsuspend do
36
+ transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.activated_at.blank? }
37
+ transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
38
+ transitions :from => :suspended, :to => :passive
39
+ end
40
+ end
41
+ end
42
+
43
+ module StatefulRolesClassMethods
44
+ end # class methods
45
+
46
+ module StatefulRolesInstanceMethods
47
+ # Returns true if the user has just been activated.
48
+ def recently_activated?
49
+ @activated
50
+ end
51
+ def do_delete
52
+ self.deleted_at = Time.now.utc
53
+ end
54
+
55
+ def do_activate
56
+ @activated = true
57
+ self.activated_at = Time.now.utc
58
+ self.deleted_at = self.activation_code = nil
59
+ end
60
+ end # instance methods
61
+ end
62
+ end
@@ -0,0 +1 @@
1
+ rails g(generate) authenticated USERMODEL CONTROLLERNAME
@@ -0,0 +1,524 @@
1
+ require 'digest/sha1'
2
+ require 'rails/generators/migration'
3
+ class AuthenticatedGenerator < Rails::Generators::NamedBase
4
+
5
+ include Rails::Generators::Migration
6
+
7
+ argument :controller_name, :type => :string, :default => 'sessions', :banner => 'ControllerName'
8
+
9
+ class_option :skip_routes, :type => :boolean, :desc => "Don't generate a resource line in config/routes.rb."
10
+ class_option :skip_migration, :type => :boolean, :desc => "Don't generate a migration file for this model."
11
+ class_option :aasm, :type => :boolean, :desc => "Works the same as stateful but uses the updated aasm gem"
12
+ class_option :stateful, :type => :boolean, :desc => "Builds in support for acts_as_state_machine and generatesactivation code."
13
+ class_option :rspec, :type => :boolean, :desc => "Generate RSpec tests and Stories in place of standard rails tests."
14
+ class_option :old_passwords, :type => :boolean, :desc => "Use the older password scheme"
15
+ class_option :include_activation, :type => :boolean, :desc => "Skip the code for a ActionMailer and its respective Activation Code through email"
16
+ class_option :dump_generator_attrs, :type => :boolean, :desc => "Dump Generator Attrs"
17
+
18
+ def self.source_root
19
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
20
+ end
21
+
22
+ def initialize(*args, &block)
23
+ super
24
+ controller_base_name
25
+ model_controller_base_name
26
+ load_or_initialize_site_keys()
27
+ end
28
+
29
+ # def check_class_naming_collisions
30
+ # # Check for class naming collisions.
31
+ # class_collisions controller_class_path, "#{ controller_class_name }Controller",
32
+ # "#{ controller_class_name }Helper" # Sessions Controller
33
+ #
34
+ # class_collisions model_controller_class_path, "#{ model_controller_class_name }Controller",
35
+ # "#{ model_controller_class_name }Helper" # Model Controller
36
+ #
37
+ # class_collisions class_path, "#{ class_name }",
38
+ # "#{ class_name }Mailer",
39
+ # "#{ class_name }MailerTest",
40
+ # "#{ class_name }Observer"
41
+ #
42
+ # class_collisions [], 'AuthenticatedSystem', 'AuthenticatedTestHelper'
43
+ # end
44
+
45
+ def create_model_files
46
+ template 'model.rb', File.join('app/models', class_path, "#{ file_name }.rb")
47
+ if options.include_activation?
48
+ template "mailer.rb", File.join('app/mailers', class_path, "#{ file_name }_mailer.rb")
49
+ template "observer.rb", File.join('app/models', class_path, "#{ file_name }_observer.rb")
50
+ end
51
+ end
52
+
53
+ def create_controller_files
54
+ template 'controller.rb', File.join('app/controllers', controller_class_path, "#{ controller_file_name }_controller.rb")
55
+ template 'model_controller.rb', File.join('app/controllers', model_controller_class_path, "#{ model_controller_file_name }_controller.rb")
56
+ end
57
+
58
+ def create_lib_files
59
+ template 'authenticated_system.rb', File.join('lib', 'authenticated_system.rb')
60
+ template 'authenticated_test_helper.rb', File.join('lib', 'authenticated_test_helper.rb')
61
+ end
62
+
63
+ def create_site_key
64
+ template 'site_keys.rb', site_keys_file
65
+ end
66
+
67
+ def create_test_files
68
+ if has_rspec?
69
+ # RSpec Specs
70
+ template 'spec/controllers/users_controller_spec.rb', File.join('spec/controllers', model_controller_class_path, "#{ model_controller_file_name }_controller_spec.rb")
71
+ template 'spec/controllers/sessions_controller_spec.rb', File.join('spec/controllers', controller_class_path, "#{ controller_file_name }_controller_spec.rb")
72
+ template 'spec/controllers/access_control_spec.rb', File.join('spec/controllers', controller_class_path, "access_control_spec.rb")
73
+ template 'spec/controllers/authenticated_system_spec.rb', File.join('spec/controllers', controller_class_path, "authenticated_system_spec.rb")
74
+ template 'spec/helpers/users_helper_spec.rb', File.join('spec/helpers', model_controller_class_path, "#{ table_name }_helper_spec.rb")
75
+ template 'spec/models/user_spec.rb', File.join('spec/models' , class_path, "#{ file_name }_spec.rb")
76
+ #if fixtures_required?
77
+ template 'spec/fixtures/users.yml', File.join('spec/fixtures', class_path, "#{ table_name }.yml")
78
+ #end
79
+ # Cucumber features
80
+ template 'features/step_definitions/ra_navigation_steps.rb', File.join('features/step_definitions/ra_navigation_steps.rb')
81
+ template 'features/step_definitions/ra_response_steps.rb', File.join('features/step_definitions/ra_response_steps.rb')
82
+ template 'features/step_definitions/ra_resource_steps.rb', File.join('features/step_definitions/ra_resource_steps.rb')
83
+ template 'features/step_definitions/user_steps.rb', File.join('features/step_definitions/', "#{ file_name }_steps.rb")
84
+ template 'features/accounts.feature', File.join('features', 'accounts.feature')
85
+ template 'features/sessions.feature', File.join('features', 'sessions.feature')
86
+ template 'features/step_definitions/rest_auth_features_helper.rb', File.join('features', 'step_definitions', 'rest_auth_features_helper.rb')
87
+ template 'features/step_definitions/ra_env.rb', File.join('features', 'step_definitions', 'ra_env.rb')
88
+ else
89
+ template 'test/functional_test.rb', File.join('test/functional', controller_class_path, "#{ controller_file_name }_controller_test.rb")
90
+ template 'test/model_functional_test.rb', File.join('test/functional', model_controller_class_path, "#{ model_controller_file_name }_controller_test.rb")
91
+ template 'test/unit_test.rb', File.join('test/unit', class_path, "#{ file_name }_test.rb")
92
+ if options.include_activation?
93
+ template 'test/mailer_test.rb', File.join('test/functional', class_path, "#{ file_name }_mailer_test.rb")
94
+ end
95
+ #if fixtures_required?
96
+ template 'spec/fixtures/users.yml', File.join('test/fixtures', class_path, "#{ table_name }.yml")
97
+ #end
98
+ end
99
+ end
100
+
101
+ def crete_helper_files
102
+ template 'helper.rb', File.join('app/helpers', controller_class_path, "#{ controller_file_name }_helper.rb")
103
+ template 'model_helper.rb', File.join('app/helpers', model_controller_class_path, "#{ model_controller_file_name }_helper.rb")
104
+ end
105
+
106
+ def create_view_files
107
+ # Controller templates
108
+ template 'login.html.erb', File.join('app/views', controller_class_path, controller_file_name, "new.html.erb")
109
+ template 'signup.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.html.erb")
110
+ template '_model_partial.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "_#{ file_name }_bar.html.erb")
111
+
112
+ if options.include_activation?
113
+ # Mailer templates
114
+ %w( activation signup_notification ).each do |action|
115
+ template "#{ action }.erb", File.join('app/views', "#{ file_name }_mailer", "#{ action }.html.erb")
116
+ end
117
+ end
118
+ end
119
+
120
+ def create_migration
121
+ unless options.skip_migration?
122
+ migration_template 'migration.rb', "db/migrate/create_#{ migration_file_name }.rb"
123
+ end
124
+ end
125
+
126
+ def create_routes
127
+ unless options.skip_routes?
128
+ # Note that this fails for nested classes -- you're on your own with setting up the routes.
129
+ route "match '/activate/:activation_code' => '#{ model_controller_plural_name }#activate', :as => :activate, :activation_code => nil"
130
+ route "match 'logout' => '#{ controller_controller_name }#destroy', :as => :logout"
131
+ route "match 'login' => '#{ controller_controller_name }#new', :as => :login"
132
+ route "match 'register' => '#{ model_controller_plural_name }#create', :as => :register"
133
+ route "match 'signup' => '#{ model_controller_plural_name }#new', :as => :signup"
134
+ route "resource #{ controller_singular_name.to_sym.inspect }, :only => [:new, :create, :destroy]"
135
+ route "resources #{ model_controller_plural_name.to_sym.inspect }"
136
+ end
137
+ end
138
+
139
+ # Post-install notes
140
+ def create_notes
141
+ case behavior
142
+ when :invoke
143
+ puts "Ready to generate."
144
+ puts ("-" * 70)
145
+ puts "Once finished, don't forget to:"
146
+ puts
147
+ puts "- Install the dynamic_form plugin(error_messages_for was removed from Rails and is now available as a plugin):"
148
+ puts " Install it with rails plugin install git://github.com/rails/dynamic_form.git"
149
+ if options.include_activation?
150
+ puts "- Add an observer to config/environment.rb"
151
+ puts " config.active_record.observers = :#{ file_name }_observer"
152
+ end
153
+ if options.aasm?
154
+ puts "- Install the acts_as_state_machine gem:"
155
+ puts " sudo gem sources -a http://gems.github.com (If you haven't already)"
156
+ puts " sudo gem install rubyist-aasm"
157
+ elsif options.stateful?
158
+ puts "- Install the acts_as_state_machine plugin:"
159
+ puts " svn export http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk vendor/plugins/acts_as_state_machine"
160
+ end
161
+ puts "- Add routes to these resources. In config/routes.rb, insert routes like:"
162
+ puts %( match 'login' => '#{ controller_file_name }#new', :as => :login)
163
+ puts %( match 'logout' => '#{ controller_file_name }#destroy', :as => :logout)
164
+ puts %( match 'signup' => '#{ model_controller_file_name }#new', :as => :signup)
165
+ if options.include_activation?
166
+ puts %( match 'activate/:activation_code' => '#{ model_controller_file_name }#activate', :as => :activate, :activation_code => nil)
167
+ end
168
+ if options.stateful?
169
+ puts " and modify the resources :#{ model_controller_file_name } line to include these actions:"
170
+ puts " resources :#{ model_controller_file_name } do"
171
+ puts " member do"
172
+ puts " put :suspend"
173
+ puts " put :unsuspend"
174
+ puts " delete :purge"
175
+ puts " end"
176
+ puts " end"
177
+ end
178
+ puts
179
+ puts ("-" * 70)
180
+ puts
181
+ if $rest_auth_site_key_from_generator.blank?
182
+ puts "You've set a nil site key. This preserves existing users' passwords,"
183
+ puts "but allows dictionary attacks in the unlikely event your database is"
184
+ puts "compromised and your site code is not. See the README for more."
185
+ elsif $rest_auth_keys_are_new
186
+ puts "We've create a new site key in #{ site_keys_file }. If you have existing"
187
+ puts "user accounts their passwords will no longer work (see README). As always,"
188
+ puts "keep this file safe but don't post it in public."
189
+ else
190
+ puts "We've reused the existing site key in #{ site_keys_file }. As always,"
191
+ puts "keep this file safe but don't post it in public."
192
+ end
193
+ puts
194
+ puts ("-" * 70)
195
+ when :revoke
196
+ puts
197
+ puts ("-" * 70)
198
+ puts
199
+ puts "Thanks for using restful_authentication"
200
+ puts
201
+ puts "Don't forget to comment out the observer line in environment.rb"
202
+ puts " (This was optional so it may not even be there)"
203
+ puts " # config.active_record.observers = :#{ file_name }_observer"
204
+ puts
205
+ puts ("-" * 70)
206
+ puts
207
+ else
208
+ puts "Didn't understand the action '#{ action }' -- you might have missed the 'after running me' instructions."
209
+ end
210
+ end
211
+
212
+ def print_generator_attribute_names
213
+ if options.dump_generator_attrs?
214
+ dump_generator_attribute_names
215
+ end
216
+ end
217
+
218
+ protected
219
+
220
+ # Override with your own usage banner.
221
+ def banner
222
+ "Usage: #{$0} authenticated ModelName [ControllerName]"
223
+ end
224
+
225
+ def controller_class_path
226
+ controller_modules.map { |m| m.underscore }
227
+ end
228
+
229
+ def controller_file_path
230
+ (controller_class_path + [controller_base_name.underscore]).join('/')
231
+ end
232
+
233
+ def controller_class_nesting
234
+ controller_modules.map { |m| m.camelize }.join('::')
235
+ end
236
+
237
+ def controller_class_nesting_depth
238
+ controller_modules.size
239
+ end
240
+
241
+ def controller_class_name_without_nesting
242
+ camelcase_name(controller_base_name)
243
+ end
244
+
245
+ def controller_file_name
246
+ underscored_name(controller_base_name)
247
+ end
248
+
249
+ def controller_plural_name
250
+ pluralized_name(controller_base_name)
251
+ end
252
+
253
+ def controller_singular_name
254
+ controller_file_name.singularize
255
+ end
256
+
257
+ def controller_class_name
258
+ controller_class_nesting.empty? ? controller_class_name_without_nesting : "#{ controller_class_nesting }::#{ controller_class_name_without_nesting }"
259
+ end
260
+
261
+ def controller_routing_name # new_session_path
262
+ controller_singular_name
263
+ end
264
+
265
+ def controller_routing_path # /session/new
266
+ controller_file_path.singularize
267
+ end
268
+
269
+ def controller_controller_name # sessions
270
+ controller_plural_name
271
+ end
272
+
273
+ alias_method :controller_table_name, :controller_plural_name
274
+
275
+
276
+ def model_controller_class_path
277
+ model_controller_modules.map { |m| m.underscore }
278
+ end
279
+
280
+ def model_controller_file_path
281
+ (model_controller_class_path + [model_controller_base_name.underscore]).join('/')
282
+ end
283
+
284
+ def model_controller_class_nesting
285
+ model_controller_modules.map { |m| m.camelize }.join('::')
286
+ end
287
+
288
+ def model_controller_class_nesting_depth
289
+ model_controller_modules.size
290
+ end
291
+
292
+ def model_controller_class_name_without_nesting
293
+ camelcase_name(model_controller_base_name)
294
+ end
295
+
296
+ def model_controller_singular_name
297
+ underscored_name(model_controller_base_name)
298
+ end
299
+
300
+ def model_controller_plural_name
301
+ pluralized_name(model_controller_base_name)
302
+ end
303
+
304
+ def model_controller_class_name
305
+ model_controller_class_nesting.empty? ? model_controller_class_name_without_nesting : "#{ model_controller_class_nesting }::#{ model_controller_class_name_without_nesting }"
306
+ end
307
+
308
+ def model_controller_routing_name # new_user_path
309
+ table_name
310
+ end
311
+
312
+ def model_controller_routing_path # /users/new
313
+ model_controller_file_path
314
+ end
315
+
316
+ def model_controller_controller_name # users
317
+ model_controller_plural_name
318
+ end
319
+
320
+ alias_method :model_controller_file_name, :model_controller_singular_name
321
+ alias_method :model_controller_table_name, :model_controller_plural_name
322
+
323
+ private
324
+
325
+ def controller_base_name
326
+ @controller_base_name ||= controller_modules.pop
327
+ end
328
+
329
+ def controller_modules
330
+ @controller_modules ||= modules(pluralized_controller_name)
331
+ end
332
+
333
+ def pluralized_controller_name
334
+ controller_name.pluralize
335
+ end
336
+
337
+ def model_controller_name
338
+ name.pluralize
339
+ end
340
+
341
+ def model_controller_base_name
342
+ @model_controller_base_name ||= model_controller_modules.pop
343
+ end
344
+
345
+ def model_controller_modules
346
+ @model_controller_modules ||= modules(model_controller_name)
347
+ end
348
+
349
+ def modules(name)
350
+ name.include?('/') ? name.split('/') : name.split('::')
351
+ end
352
+
353
+ def camelcase_name(name)
354
+ name.camelize
355
+ end
356
+
357
+ def underscored_name(name)
358
+ camelcase_name(name).underscore
359
+ end
360
+
361
+ def pluralized_name(name)
362
+ underscored_name(name).pluralize
363
+ end
364
+
365
+ def has_rspec?
366
+ @rspec ||= (options.rspec? && File.exist?(destination_path("spec")))
367
+ end
368
+
369
+ # def test_framework?(name)
370
+ # name == test_framework.to_s
371
+ # end
372
+ #
373
+ # def fixtures_required?
374
+ # test_framework && Rails::Application.config.generators.options[test_framework][:fixture] != false
375
+ # end
376
+ #
377
+ # def test_framework
378
+ # Rails::Application.config.generators.rails[:test_framework]
379
+ # end
380
+
381
+ def destination_path(path)
382
+ File.join(destination_root, path)
383
+ end
384
+
385
+ #
386
+ # !! These must match the corresponding routines in by_password.rb !!
387
+ #
388
+ def secure_digest(*args)
389
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
390
+ end
391
+
392
+ def make_token
393
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
394
+ end
395
+ def password_digest(password, salt)
396
+ digest = $rest_auth_site_key_from_generator
397
+ $rest_auth_digest_stretches_from_generator.times do
398
+ digest = secure_digest(digest, salt, password, $rest_auth_site_key_from_generator)
399
+ end
400
+ digest
401
+ end
402
+
403
+ #
404
+ # Try to be idempotent:
405
+ # pull in the existing site key if any,
406
+ # seed it with reasonable defaults otherwise
407
+ #
408
+ def load_or_initialize_site_keys
409
+ case
410
+ when defined? REST_AUTH_SITE_KEY
411
+ if (options.old_passwords?) && ((! REST_AUTH_SITE_KEY.blank?) || (REST_AUTH_DIGEST_STRETCHES != 1))
412
+ raise "You have a site key, but --old-passwords will overwrite it. If this is really what you want, move the file #{site_keys_file} and re-run."
413
+ end
414
+ $rest_auth_site_key_from_generator = REST_AUTH_SITE_KEY
415
+ $rest_auth_digest_stretches_from_generator = REST_AUTH_DIGEST_STRETCHES
416
+ when options.old_passwords?
417
+ $rest_auth_site_key_from_generator = nil
418
+ $rest_auth_digest_stretches_from_generator = 1
419
+ $rest_auth_keys_are_new = true
420
+ else
421
+ $rest_auth_site_key_from_generator = make_token
422
+ $rest_auth_digest_stretches_from_generator = 10
423
+ $rest_auth_keys_are_new = true
424
+ end
425
+ end
426
+
427
+ def site_keys_file
428
+ File.join("config", "initializers", "site_keys.rb")
429
+ end
430
+
431
+ def migration_name
432
+ "Create#{ class_name.pluralize.gsub(/::/, '') }"
433
+ end
434
+
435
+ def migration_file_name
436
+ "#{ file_path.gsub(/\//, '_').pluralize }"
437
+ end
438
+
439
+ #
440
+ # Implement the required interface for Rails::Generators::Migration.
441
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
442
+ #
443
+ def self.next_migration_number(dirname) #:nodoc:
444
+ if ActiveRecord::Base.timestamped_migrations
445
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
446
+ else
447
+ "%.3d" % (current_migration_number(dirname) + 1)
448
+ end
449
+ end
450
+
451
+ def dump_generator_attribute_names
452
+ generator_attribute_names = [
453
+ :table_name,
454
+ :file_name,
455
+ :class_name,
456
+ :controller_name,
457
+ :controller_class_path,
458
+ :controller_file_path,
459
+ :controller_class_nesting,
460
+ :controller_class_nesting_depth,
461
+ :controller_class_name,
462
+ :controller_singular_name,
463
+ :controller_plural_name,
464
+ :controller_routing_name, # new_session_path
465
+ :controller_routing_path, # /session/new
466
+ :controller_controller_name, # sessions
467
+ :controller_file_name,
468
+ :controller_table_name, :controller_plural_name,
469
+ :model_controller_name,
470
+ :model_controller_class_path,
471
+ :model_controller_file_path,
472
+ :model_controller_class_nesting,
473
+ :model_controller_class_nesting_depth,
474
+ :model_controller_class_name,
475
+ :model_controller_singular_name,
476
+ :model_controller_plural_name,
477
+ :model_controller_routing_name, # new_user_path
478
+ :model_controller_routing_path, # /users/new
479
+ :model_controller_controller_name, # users
480
+ :model_controller_file_name, :model_controller_singular_name,
481
+ :model_controller_table_name, :model_controller_plural_name,
482
+ ]
483
+
484
+ generator_attribute_names.each do |attr|
485
+ puts "%-40s %s" % ["#{attr}:", self.send(attr.to_s)] # instance_variable_get("@#{attr.to_s}"
486
+ end
487
+
488
+ end
489
+
490
+ end
491
+
492
+ # rails g authenticated FoonParent::Foon SporkParent::Spork -p --force --rspec --dump-generator-attrs
493
+ # table_name: foon_parent_foons
494
+ # file_name: foon
495
+ # class_name: FoonParent::Foon
496
+ # controller_name: SporkParent::Sporks
497
+ # controller_class_path: spork_parent
498
+ # controller_file_path: spork_parent/sporks
499
+ # controller_class_nesting: SporkParent
500
+ # controller_class_nesting_depth: 1
501
+ # controller_class_name: SporkParent::Sporks
502
+ # controller_singular_name: spork
503
+ # controller_plural_name: sporks
504
+ # controller_routing_name: spork
505
+ # controller_routing_path: spork_parent/spork
506
+ # controller_controller_name: sporks
507
+ # controller_file_name: sporks
508
+ # controller_table_name: sporks
509
+ # controller_plural_name: sporks
510
+ # model_controller_name: FoonParent::Foons
511
+ # model_controller_class_path: foon_parent
512
+ # model_controller_file_path: foon_parent/foons
513
+ # model_controller_class_nesting: FoonParent
514
+ # model_controller_class_nesting_depth: 1
515
+ # model_controller_class_name: FoonParent::Foons
516
+ # model_controller_singular_name: foons
517
+ # model_controller_plural_name: foons
518
+ # model_controller_routing_name: foon_parent_foons
519
+ # model_controller_routing_path: foon_parent/foons
520
+ # model_controller_controller_name: foons
521
+ # model_controller_file_name: foons
522
+ # model_controller_singular_name: foons
523
+ # model_controller_table_name: foons
524
+ # model_controller_plural_name: foons