devise_token_auth 0.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +13 -0
  3. data/README.md +97 -0
  4. data/Rakefile +12 -4
  5. data/app/controllers/devise_token_auth/application_controller.rb +89 -22
  6. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +58 -0
  7. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +199 -0
  8. data/app/controllers/devise_token_auth/confirmations_controller.rb +79 -14
  9. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +284 -0
  10. data/app/controllers/devise_token_auth/passwords_controller.rb +196 -35
  11. data/app/controllers/devise_token_auth/registrations_controller.rb +191 -20
  12. data/app/controllers/devise_token_auth/sessions_controller.rb +130 -21
  13. data/app/controllers/devise_token_auth/token_validations_controller.rb +31 -0
  14. data/app/controllers/devise_token_auth/unlocks_controller.rb +94 -0
  15. data/app/models/devise_token_auth/concerns/active_record_support.rb +18 -0
  16. data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
  17. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  18. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
  19. data/app/models/devise_token_auth/concerns/user.rb +287 -0
  20. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +35 -0
  21. data/app/validators/devise_token_auth_email_validator.rb +31 -0
  22. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  23. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  24. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  25. data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
  26. data/config/locales/da-DK.yml +52 -0
  27. data/config/locales/de.yml +51 -0
  28. data/config/locales/en.yml +60 -0
  29. data/config/locales/es.yml +51 -0
  30. data/config/locales/fa.yml +60 -0
  31. data/config/locales/fr.yml +51 -0
  32. data/config/locales/he.yml +52 -0
  33. data/config/locales/it.yml +48 -0
  34. data/config/locales/ja.yml +60 -0
  35. data/config/locales/ko.yml +51 -0
  36. data/config/locales/nl.yml +32 -0
  37. data/config/locales/pl.yml +51 -0
  38. data/config/locales/pt-BR.yml +48 -0
  39. data/config/locales/pt.yml +51 -0
  40. data/config/locales/ro.yml +48 -0
  41. data/config/locales/ru.yml +52 -0
  42. data/config/locales/sq.yml +48 -0
  43. data/config/locales/sv.yml +52 -0
  44. data/config/locales/uk.yml +61 -0
  45. data/config/locales/vi.yml +52 -0
  46. data/config/locales/zh-CN.yml +48 -0
  47. data/config/locales/zh-HK.yml +50 -0
  48. data/config/locales/zh-TW.yml +50 -0
  49. data/lib/devise_token_auth/blacklist.rb +6 -0
  50. data/lib/devise_token_auth/controllers/helpers.rb +157 -0
  51. data/lib/devise_token_auth/controllers/url_helpers.rb +10 -0
  52. data/lib/devise_token_auth/engine.rb +100 -0
  53. data/lib/devise_token_auth/errors.rb +8 -0
  54. data/lib/devise_token_auth/rails/routes.rb +135 -0
  55. data/lib/devise_token_auth/token_factory.rb +126 -0
  56. data/lib/devise_token_auth/url.rb +44 -0
  57. data/lib/devise_token_auth/version.rb +3 -1
  58. data/lib/devise_token_auth.rb +11 -2
  59. data/lib/generators/devise_token_auth/USAGE +27 -4
  60. data/lib/generators/devise_token_auth/install_generator.rb +91 -0
  61. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  62. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  63. data/lib/generators/devise_token_auth/install_views_generator.rb +18 -0
  64. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +66 -0
  65. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +49 -0
  66. data/lib/generators/devise_token_auth/templates/user.rb.erb +9 -0
  67. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  68. data/lib/tasks/devise_token_auth_tasks.rake +2 -0
  69. data/test/controllers/custom/custom_confirmations_controller_test.rb +25 -0
  70. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +33 -0
  71. data/test/controllers/custom/custom_passwords_controller_test.rb +79 -0
  72. data/test/controllers/custom/custom_registrations_controller_test.rb +63 -0
  73. data/test/controllers/custom/custom_sessions_controller_test.rb +39 -0
  74. data/test/controllers/custom/custom_token_validations_controller_test.rb +42 -0
  75. data/test/controllers/demo_group_controller_test.rb +151 -0
  76. data/test/controllers/demo_mang_controller_test.rb +313 -0
  77. data/test/controllers/demo_user_controller_test.rb +658 -0
  78. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +275 -0
  79. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +438 -0
  80. data/test/controllers/devise_token_auth/passwords_controller_test.rb +893 -0
  81. data/test/controllers/devise_token_auth/registrations_controller_test.rb +920 -0
  82. data/test/controllers/devise_token_auth/sessions_controller_test.rb +605 -0
  83. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +142 -0
  84. data/test/controllers/devise_token_auth/unlocks_controller_test.rb +235 -0
  85. data/test/controllers/overrides/confirmations_controller_test.rb +47 -0
  86. data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +53 -0
  87. data/test/controllers/overrides/passwords_controller_test.rb +64 -0
  88. data/test/controllers/overrides/registrations_controller_test.rb +46 -0
  89. data/test/controllers/overrides/sessions_controller_test.rb +35 -0
  90. data/test/controllers/overrides/token_validations_controller_test.rb +43 -0
  91. data/test/dummy/app/active_record/confirmable_user.rb +11 -0
  92. data/test/dummy/app/active_record/lockable_user.rb +7 -0
  93. data/test/dummy/app/active_record/mang.rb +5 -0
  94. data/test/dummy/app/active_record/only_email_user.rb +7 -0
  95. data/test/dummy/app/active_record/scoped_user.rb +9 -0
  96. data/test/dummy/app/active_record/unconfirmable_user.rb +9 -0
  97. data/test/dummy/app/active_record/unregisterable_user.rb +9 -0
  98. data/test/dummy/app/active_record/user.rb +6 -0
  99. data/test/dummy/app/controllers/application_controller.rb +12 -3
  100. data/test/dummy/app/controllers/auth_origin_controller.rb +7 -0
  101. data/test/dummy/app/controllers/custom/confirmations_controller.rb +13 -0
  102. data/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb +13 -0
  103. data/test/dummy/app/controllers/custom/passwords_controller.rb +39 -0
  104. data/test/dummy/app/controllers/custom/registrations_controller.rb +39 -0
  105. data/test/dummy/app/controllers/custom/sessions_controller.rb +29 -0
  106. data/test/dummy/app/controllers/custom/token_validations_controller.rb +19 -0
  107. data/test/dummy/app/controllers/demo_group_controller.rb +15 -0
  108. data/test/dummy/app/controllers/demo_mang_controller.rb +14 -0
  109. data/test/dummy/app/controllers/demo_user_controller.rb +27 -0
  110. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +29 -0
  111. data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +16 -0
  112. data/test/dummy/app/controllers/overrides/passwords_controller.rb +36 -0
  113. data/test/dummy/app/controllers/overrides/registrations_controller.rb +29 -0
  114. data/test/dummy/app/controllers/overrides/sessions_controller.rb +36 -0
  115. data/test/dummy/app/controllers/overrides/token_validations_controller.rb +23 -0
  116. data/test/dummy/app/helpers/application_helper.rb +1056 -0
  117. data/test/dummy/app/models/concerns/favorite_color.rb +19 -0
  118. data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
  119. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  120. data/test/dummy/app/mongoid/mang.rb +46 -0
  121. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  122. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  123. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  124. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  125. data/test/dummy/app/mongoid/user.rb +49 -0
  126. data/test/dummy/app/views/layouts/application.html.erb +0 -2
  127. data/test/dummy/config/application.rb +25 -8
  128. data/test/dummy/config/application.yml.bk +0 -0
  129. data/test/dummy/config/boot.rb +8 -2
  130. data/test/dummy/config/environment.rb +3 -1
  131. data/test/dummy/config/environments/development.rb +10 -11
  132. data/test/dummy/config/environments/production.rb +3 -17
  133. data/test/dummy/config/environments/test.rb +25 -3
  134. data/test/dummy/config/initializers/backtrace_silencers.rb +2 -0
  135. data/test/dummy/config/initializers/cookies_serializer.rb +3 -1
  136. data/{config → test/dummy/config}/initializers/devise.rb +63 -31
  137. data/test/dummy/config/initializers/devise_token_auth.rb +55 -0
  138. data/test/dummy/config/initializers/figaro.rb +3 -0
  139. data/test/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  140. data/test/dummy/config/initializers/inflections.rb +2 -0
  141. data/test/dummy/config/initializers/mime_types.rb +2 -0
  142. data/test/dummy/config/initializers/omniauth.rb +7 -1
  143. data/test/dummy/config/initializers/session_store.rb +2 -0
  144. data/test/dummy/config/initializers/wrap_parameters.rb +2 -0
  145. data/test/dummy/config/routes.rb +55 -1
  146. data/test/dummy/config/spring.rb +3 -0
  147. data/test/dummy/config.ru +14 -0
  148. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +58 -0
  149. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +57 -0
  150. data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +8 -0
  151. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +7 -0
  152. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +55 -0
  153. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +56 -0
  154. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +56 -0
  155. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +56 -0
  156. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +56 -0
  157. data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
  158. data/test/dummy/db/schema.rb +180 -28
  159. data/test/dummy/lib/migration_database_helper.rb +43 -0
  160. data/test/dummy/tmp/generators/app/models/user.rb +11 -0
  161. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +66 -0
  162. data/{db/migrate/20140628234942_devise_token_auth_create_users.rb → test/dummy/tmp/generators/db/migrate/20240519164408_devise_token_auth_create_users.rb} +16 -23
  163. data/test/factories/users.rb +41 -0
  164. data/test/lib/devise_token_auth/blacklist_test.rb +19 -0
  165. data/test/lib/devise_token_auth/rails/custom_routes_test.rb +30 -0
  166. data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
  167. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  168. data/test/lib/devise_token_auth/url_test.rb +26 -0
  169. data/test/lib/generators/devise_token_auth/install_generator_test.rb +217 -0
  170. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +222 -0
  171. data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +25 -0
  172. data/test/models/concerns/mongoid_support_test.rb +31 -0
  173. data/test/models/concerns/tokens_serialization_test.rb +104 -0
  174. data/test/models/confirmable_user_test.rb +35 -0
  175. data/test/models/only_email_user_test.rb +29 -0
  176. data/test/models/user_test.rb +251 -0
  177. data/test/support/controllers/routes.rb +43 -0
  178. data/test/test_helper.rb +136 -10
  179. metadata +368 -80
  180. data/MIT-LICENSE +0 -20
  181. data/README.rdoc +0 -3
  182. data/app/assets/javascripts/devise_token_auth/application.js +0 -13
  183. data/app/assets/stylesheets/devise_token_auth/application.css +0 -15
  184. data/app/controllers/devise_token_auth/auth_controller.rb +0 -62
  185. data/app/helpers/devise_token_auth/application_helper.rb +0 -4
  186. data/app/models/user.rb +0 -6
  187. data/app/views/devise_token_auth/omniauth_success.html.erb +0 -7
  188. data/app/views/layouts/omniauth_response.html.erb +0 -20
  189. data/config/locales/devise.en.yml +0 -59
  190. data/config/routes.rb +0 -14
  191. data/lib/generators/devise_token_auth/devise_token_auth_generator.rb +0 -3
  192. data/test/devise_token_auth_test.rb +0 -7
  193. data/test/dummy/Rakefile +0 -6
  194. data/test/dummy/app/assets/javascripts/application.js +0 -13
  195. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  196. data/test/dummy/bin/bundle +0 -3
  197. data/test/dummy/bin/rails +0 -4
  198. data/test/dummy/bin/rake +0 -4
  199. data/test/dummy/config/application.yml +0 -13
  200. data/test/dummy/config/database.yml +0 -25
  201. data/test/dummy/config/initializers/assets.rb +0 -8
  202. data/test/dummy/config/locales/en.yml +0 -23
  203. data/test/dummy/config/secrets.yml +0 -22
  204. data/test/dummy/db/development.sqlite3 +0 -0
  205. data/test/dummy/db/migrate/20140629011345_devise_token_auth_create_users.devise_token_auth.rb +0 -57
  206. data/test/dummy/db/test.sqlite3 +0 -0
  207. data/test/dummy/log/development.log +0 -3406
  208. data/test/dummy/public/404.html +0 -67
  209. data/test/dummy/public/422.html +0 -67
  210. data/test/dummy/public/500.html +0 -66
  211. data/test/dummy/public/favicon.ico +0 -0
  212. data/test/integration/navigation_test.rb +0 -10
  213. data/test/lib/generators/devise_token_auth/devise_token_auth_generator_test.rb +0 -16
@@ -1,34 +1,205 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeviseTokenAuth
2
- class RegistrationsController < Devise::RegistrationsController
3
- include Devise::Controllers::Helpers
4
+ class RegistrationsController < DeviseTokenAuth::ApplicationController
5
+ before_action :set_user_by_token, only: [:destroy, :update]
6
+ before_action :validate_sign_up_params, only: :create
7
+ before_action :validate_account_update_params, only: :update
8
+ skip_after_action :update_auth_header, only: [:create, :destroy]
4
9
 
5
- prepend_before_filter :require_no_authentication, :only => [ :create ]
10
+ def create
11
+ build_resource
6
12
 
7
- respond_to :json
13
+ unless @resource.present?
14
+ raise DeviseTokenAuth::Errors::NoResourceDefinedError,
15
+ "#{self.class.name} #build_resource does not define @resource,"\
16
+ ' execution stopped.'
17
+ end
8
18
 
9
- def create
10
- @resource = User.new(resource_params)
11
- @resource.uid = resource_params[:email]
12
- @resource.provider = "email"
13
- @resource.auth_token = SecureRandom.urlsafe_base64(nil, false)
19
+ # give redirect value from params priority
20
+ @redirect_url = params.fetch(
21
+ :confirm_success_url,
22
+ DeviseTokenAuth.default_confirm_success_url
23
+ )
24
+
25
+ # success redirect url is required
26
+ if confirmable_enabled? && !@redirect_url
27
+ return render_create_error_missing_confirm_success_url
28
+ end
29
+
30
+ # if whitelist is set, validate redirect_url against whitelist
31
+ return render_create_error_redirect_url_not_allowed if blacklisted_redirect_url?(@redirect_url)
32
+
33
+ # override email confirmation, must be sent manually from ctrl
34
+ callback_name = defined?(ActiveRecord) && resource_class < ActiveRecord::Base ? :commit : :create
35
+ resource_class.set_callback(callback_name, :after, :send_on_create_confirmation_instructions)
36
+ resource_class.skip_callback(callback_name, :after, :send_on_create_confirmation_instructions)
37
+
38
+ if @resource.respond_to? :skip_confirmation_notification!
39
+ # Fix duplicate e-mails by disabling Devise confirmation e-mail
40
+ @resource.skip_confirmation_notification!
41
+ end
14
42
 
15
43
  if @resource.save
16
- render json: {
17
- status: 'success',
18
- data: @resource.as_json
19
- }
44
+ yield @resource if block_given?
45
+
46
+ unless @resource.confirmed?
47
+ # user will require email authentication
48
+ @resource.send_confirmation_instructions({
49
+ client_config: params[:config_name],
50
+ redirect_url: @redirect_url
51
+ })
52
+ end
53
+
54
+ if active_for_authentication?
55
+ # email auth has been bypassed, authenticate user
56
+ @token = @resource.create_token
57
+ @resource.save!
58
+ update_auth_header
59
+ end
60
+
61
+ render_create_success
20
62
  else
21
63
  clean_up_passwords @resource
22
- render status: 403, json: {
23
- status: 'error',
24
- data: @resource.as_json,
25
- errors: @resource.errors.full_messages
26
- }
64
+ render_create_error
65
+ end
66
+ end
67
+
68
+ def update
69
+ if @resource
70
+ if @resource.send(resource_update_method, account_update_params)
71
+ yield @resource if block_given?
72
+ render_update_success
73
+ else
74
+ render_update_error
75
+ end
76
+ else
77
+ render_update_error_user_not_found
78
+ end
79
+ end
80
+
81
+ def destroy
82
+ if @resource
83
+ @resource.destroy
84
+ yield @resource if block_given?
85
+ render_destroy_success
86
+ else
87
+ render_destroy_error
88
+ end
89
+ end
90
+
91
+ def sign_up_params
92
+ params.permit(*params_for_resource(:sign_up))
93
+ end
94
+
95
+ def account_update_params
96
+ params.permit(*params_for_resource(:account_update))
97
+ end
98
+
99
+ protected
100
+
101
+ def build_resource
102
+ @resource = resource_class.new(sign_up_params)
103
+ @resource.provider = provider
104
+
105
+ # honor devise configuration for case_insensitive_keys
106
+ if resource_class.case_insensitive_keys.include?(:email)
107
+ @resource.email = sign_up_params[:email].try(:downcase)
108
+ else
109
+ @resource.email = sign_up_params[:email]
110
+ end
111
+ end
112
+
113
+ def render_create_error_missing_confirm_success_url
114
+ response = {
115
+ status: 'error',
116
+ data: resource_data
117
+ }
118
+ message = I18n.t('devise_token_auth.registrations.missing_confirm_success_url')
119
+ render_error(422, message, response)
120
+ end
121
+
122
+ def render_create_error_redirect_url_not_allowed
123
+ response = {
124
+ status: 'error',
125
+ data: resource_data
126
+ }
127
+ message = I18n.t('devise_token_auth.registrations.redirect_url_not_allowed', redirect_url: @redirect_url)
128
+ render_error(422, message, response)
129
+ end
130
+
131
+ def render_create_success
132
+ render json: {
133
+ status: 'success',
134
+ data: resource_data
135
+ }
136
+ end
137
+
138
+ def render_create_error
139
+ render json: {
140
+ status: 'error',
141
+ data: resource_data,
142
+ errors: resource_errors
143
+ }, status: 422
144
+ end
145
+
146
+ def render_update_success
147
+ render json: {
148
+ status: 'success',
149
+ data: resource_data
150
+ }
151
+ end
152
+
153
+ def render_update_error
154
+ render json: {
155
+ status: 'error',
156
+ errors: resource_errors
157
+ }, status: 422
158
+ end
159
+
160
+ def render_update_error_user_not_found
161
+ render_error(404, I18n.t('devise_token_auth.registrations.user_not_found'), status: 'error')
162
+ end
163
+
164
+ def render_destroy_success
165
+ render json: {
166
+ status: 'success',
167
+ message: I18n.t('devise_token_auth.registrations.account_with_uid_destroyed', uid: @resource.uid)
168
+ }
169
+ end
170
+
171
+ def render_destroy_error
172
+ render_error(404, I18n.t('devise_token_auth.registrations.account_to_destroy_not_found'), status: 'error')
173
+ end
174
+
175
+ private
176
+
177
+ def resource_update_method
178
+ if DeviseTokenAuth.check_current_password_before_update == :attributes
179
+ 'update_with_password'
180
+ elsif DeviseTokenAuth.check_current_password_before_update == :password && account_update_params.key?(:password)
181
+ 'update_with_password'
182
+ elsif account_update_params.key?(:current_password)
183
+ 'update_with_password'
184
+ else
185
+ 'update'
27
186
  end
28
187
  end
29
188
 
30
- def resource_params
31
- params.permit(:email, :password, :password_confirmation, :confirm_success_url, :confirm_error_url)
189
+ def validate_sign_up_params
190
+ validate_post_data sign_up_params, I18n.t('errors.messages.validate_sign_up_params')
191
+ end
192
+
193
+ def validate_account_update_params
194
+ validate_post_data account_update_params, I18n.t('errors.messages.validate_account_update_params')
195
+ end
196
+
197
+ def validate_post_data which, message
198
+ render_error(:unprocessable_entity, message, status: 'error') if which.empty?
199
+ end
200
+
201
+ def active_for_authentication?
202
+ !@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?
32
203
  end
33
204
  end
34
205
  end
@@ -1,44 +1,153 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # see http://www.emilsoman.com/blog/2013/05/18/building-a-tested/
2
4
  module DeviseTokenAuth
3
- class SessionsController < Devise::SessionsController
4
- prepend_before_filter :require_no_authentication, :only => [:create]
5
- include Devise::Controllers::Helpers
5
+ class SessionsController < DeviseTokenAuth::ApplicationController
6
+ before_action :set_user_by_token, only: [:destroy]
7
+ after_action :reset_session, only: [:destroy]
6
8
 
7
- respond_to :json
9
+ def new
10
+ render_new_error
11
+ end
8
12
 
9
13
  def create
10
- resource = User.find_by_email(resource_params[:email])
14
+ if field = (resource_params.keys.map(&:to_sym) & resource_class.authentication_keys).first
15
+ q_value = get_case_insensitive_field_from_resource_params(field)
16
+
17
+ @resource = find_resource(field, q_value)
18
+ end
11
19
 
12
- unless resource and valid_params? and resource.valid_password?(params[:password])
13
- render json: {
14
- success: false,
15
- errors: ["Invalid login credentials. Please try again."]
16
- }, status: 401
20
+ if @resource && valid_params?(field, q_value) && (!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
21
+ valid_password = @resource.valid_password?(resource_params[:password])
22
+ if (@resource.respond_to?(:valid_for_authentication?) && !@resource.valid_for_authentication? { valid_password }) || !valid_password
23
+ return render_create_error_bad_credentials
24
+ end
17
25
 
18
- else
19
- sign_in(:user, resource, store: false)
26
+ create_and_assign_token
27
+
28
+ sign_in(@resource, scope: :user, store: false, bypass: false)
20
29
 
21
- render json: {
22
- success: true,
23
- data: resource.as_json
24
- }
30
+ yield @resource if block_given?
31
+
32
+ render_create_success
33
+ elsif @resource && !Devise.paranoid && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
34
+ if @resource.respond_to?(:locked_at) && @resource.locked_at
35
+ render_create_error_account_locked
36
+ else
37
+ render_create_error_not_confirmed
38
+ end
39
+ else
40
+ hash_password_in_paranoid_mode
41
+ render_create_error_bad_credentials
25
42
  end
26
43
  end
27
44
 
28
45
  def destroy
29
- sign_out(resource_name)
46
+ # remove auth instance variables so that after_action does not run
47
+ user = remove_instance_variable(:@resource) if @resource
48
+ client = @token.client
49
+ @token.clear!
50
+
51
+ if user && client && user.tokens[client]
52
+ user.tokens.delete(client)
53
+ user.save!
54
+
55
+ if DeviseTokenAuth.cookie_enabled
56
+ # If a cookie is set with a domain specified then it must be deleted with that domain specified
57
+ # See https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
58
+ cookies.delete(DeviseTokenAuth.cookie_name, domain: DeviseTokenAuth.cookie_attributes[:domain])
59
+ end
60
+
61
+ yield user if block_given?
62
+
63
+ render_destroy_success
64
+ else
65
+ render_destroy_error
66
+ end
67
+ end
68
+
69
+ protected
70
+
71
+ def valid_params?(key, val)
72
+ resource_params[:password] && key && val
73
+ end
74
+
75
+ def get_auth_params
76
+ auth_key = nil
77
+ auth_val = nil
78
+ # iterate thru allowed auth keys, use first found
79
+ resource_class.authentication_keys.each do |k|
80
+ if resource_params[k]
81
+ auth_val = resource_params[k]
82
+ auth_key = k
83
+ break
84
+ end
85
+ end
86
+
87
+ # honor devise configuration for case_insensitive_keys
88
+ if resource_class.case_insensitive_keys.include?(auth_key)
89
+ auth_val.downcase!
90
+ end
30
91
 
92
+ { key: auth_key, val: auth_val }
93
+ end
94
+
95
+ def render_new_error
96
+ render_error(405, I18n.t('devise_token_auth.sessions.not_supported'))
97
+ end
98
+
99
+ def render_create_success
31
100
  render json: {
32
- success:true
101
+ data: resource_data(resource_json: @resource.token_validation_response)
33
102
  }
34
103
  end
35
104
 
36
- def valid_params?
37
- params[:password] && params[:email]
105
+ def render_create_error_not_confirmed
106
+ render_error(401, I18n.t('devise_token_auth.sessions.not_confirmed', email: @resource.email))
107
+ end
108
+
109
+ def render_create_error_account_locked
110
+ render_error(401, I18n.t('devise.mailer.unlock_instructions.account_lock_msg'))
111
+ end
112
+
113
+ def render_create_error_bad_credentials
114
+ render_error(401, I18n.t('devise_token_auth.sessions.bad_credentials'))
115
+ end
116
+
117
+ def render_destroy_success
118
+ render json: {
119
+ success:true
120
+ }, status: 200
121
+ end
122
+
123
+ def render_destroy_error
124
+ render_error(404, I18n.t('devise_token_auth.sessions.user_not_found'))
38
125
  end
39
126
 
127
+ private
128
+
40
129
  def resource_params
41
- params.permit(:email, :password)
130
+ params.permit(*params_for_resource(:sign_in))
131
+ end
132
+
133
+ def create_and_assign_token
134
+ if @resource.respond_to?(:with_lock) && !@resource.changed?
135
+ @resource.with_lock do
136
+ @token = @resource.create_token
137
+ @resource.save!
138
+ end
139
+ else
140
+ @token = @resource.create_token
141
+ @resource.save!
142
+ end
143
+ end
144
+
145
+ def hash_password_in_paranoid_mode
146
+ # In order to avoid timing attacks in paranoid mode, we want the password hash to be
147
+ # calculated even if no resource has been found. Devise's DatabaseAuthenticatable warden
148
+ # strategy handles this case similarly:
149
+ # https://github.com/heartcombo/devise/blob/main/lib/devise/strategies/database_authenticatable.rb
150
+ resource_class.new.password = resource_params[:password] if Devise.paranoid
42
151
  end
43
152
  end
44
153
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ class TokenValidationsController < DeviseTokenAuth::ApplicationController
5
+ skip_before_action :assert_is_devise_resource!, only: [:validate_token]
6
+ before_action :set_user_by_token, only: [:validate_token]
7
+
8
+ def validate_token
9
+ # @resource will have been set by set_user_by_token concern
10
+ if @resource
11
+ yield @resource if block_given?
12
+ render_validate_token_success
13
+ else
14
+ render_validate_token_error
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ def render_validate_token_success
21
+ render json: {
22
+ success: true,
23
+ data: resource_data(resource_json: @resource.token_validation_response)
24
+ }
25
+ end
26
+
27
+ def render_validate_token_error
28
+ render_error(401, I18n.t('devise_token_auth.token_validations.invalid'))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ class UnlocksController < DeviseTokenAuth::ApplicationController
5
+ skip_after_action :update_auth_header, only: [:create, :show]
6
+
7
+ # this action is responsible for generating unlock tokens and
8
+ # sending emails
9
+ def create
10
+ return render_create_error_missing_email unless resource_params[:email]
11
+
12
+ @email = get_case_insensitive_field_from_resource_params(:email)
13
+ @resource = find_resource(:email, @email)
14
+
15
+ if @resource
16
+ yield @resource if block_given?
17
+
18
+ @resource.send_unlock_instructions(
19
+ email: @email,
20
+ provider: 'email',
21
+ client_config: params[:config_name]
22
+ )
23
+
24
+ if @resource.errors.empty?
25
+ return render_create_success
26
+ else
27
+ render_create_error @resource.errors
28
+ end
29
+ else
30
+ render_not_found_error
31
+ end
32
+ end
33
+
34
+ def show
35
+ @resource = resource_class.unlock_access_by_token(params[:unlock_token])
36
+
37
+ if @resource.persisted?
38
+ token = @resource.create_token
39
+ @resource.save!
40
+ yield @resource if block_given?
41
+
42
+ redirect_header_options = { unlock: true }
43
+ redirect_headers = build_redirect_headers(token.token,
44
+ token.client,
45
+ redirect_header_options)
46
+ redirect_to(@resource.build_auth_url(after_unlock_path_for(@resource),
47
+ redirect_headers),
48
+ redirect_options)
49
+ else
50
+ render_show_error
51
+ end
52
+ end
53
+
54
+ private
55
+ def after_unlock_path_for(resource)
56
+ #TODO: This should probably be a configuration option at the very least.
57
+ '/'
58
+ end
59
+
60
+ def render_create_error_missing_email
61
+ render_error(401, I18n.t('devise_token_auth.unlocks.missing_email'))
62
+ end
63
+
64
+ def render_create_success
65
+ render json: {
66
+ success: true,
67
+ message: success_message('unlocks', @email)
68
+ }
69
+ end
70
+
71
+ def render_create_error(errors)
72
+ render json: {
73
+ success: false,
74
+ errors: errors
75
+ }, status: 400
76
+ end
77
+
78
+ def render_show_error
79
+ raise ActionController::RoutingError, 'Not Found'
80
+ end
81
+
82
+ def render_not_found_error
83
+ if Devise.paranoid
84
+ render_create_success
85
+ else
86
+ render_error(404, I18n.t('devise_token_auth.unlocks.user_not_found', email: @email))
87
+ end
88
+ end
89
+
90
+ def resource_params
91
+ params.permit(:email, :unlock_token, :config)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,18 @@
1
+ module DeviseTokenAuth::Concerns::ActiveRecordSupport
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ if Rails.gem_version >= Gem::Version.new("7.1.0.a")
6
+ serialize :tokens, coder: DeviseTokenAuth::Concerns::TokensSerialization
7
+ else
8
+ serialize :tokens, DeviseTokenAuth::Concerns::TokensSerialization
9
+ end
10
+ end
11
+
12
+ class_methods do
13
+ # It's abstract replacement .find_by
14
+ def dta_find_by(attrs = {})
15
+ find_by(attrs)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ module DeviseTokenAuth::Concerns::ConfirmableSupport
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ # Override standard devise `postpone_email_change?` method
6
+ # for not to use `devise_will_save_change_to_email?` methods.
7
+ def postpone_email_change?
8
+ postpone = self.class.reconfirmable &&
9
+ email_value_in_database != email &&
10
+ !@bypass_confirmation_postpone &&
11
+ self.email.present? &&
12
+ (!@skip_reconfirmation_in_callback || !email_value_in_database.nil?)
13
+ @bypass_confirmation_postpone = false
14
+ postpone
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ def email_value_in_database
21
+ rails51 = Rails.gem_version >= Gem::Version.new("5.1.x")
22
+ if rails51 && respond_to?(:email_in_database)
23
+ email_in_database
24
+ else
25
+ email_was
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module DeviseTokenAuth::Concerns::MongoidSupport
2
+ extend ActiveSupport::Concern
3
+
4
+ def as_json(options = {})
5
+ options[:except] = (options[:except] || []) + [:_id]
6
+ hash = super(options)
7
+ hash['id'] = to_param
8
+ hash
9
+ end
10
+
11
+ class_methods do
12
+ # It's abstract replacement .find_by
13
+ def dta_find_by(attrs = {})
14
+ find_by(attrs)
15
+ rescue Mongoid::Errors::DocumentNotFound
16
+ nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module DeviseTokenAuth::Concerns::TokensSerialization
2
+ extend self
3
+ # Serialization hash to json
4
+ def dump(object)
5
+ JSON.generate(object && object.transform_values do |token|
6
+ serialize_updated_at(token).compact
7
+ end.compact)
8
+ end
9
+
10
+ # Deserialization json to hash
11
+ def load(json)
12
+ case json
13
+ when String
14
+ JSON.parse(json)
15
+ when NilClass
16
+ {}
17
+ else
18
+ json
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def serialize_updated_at(token)
25
+ updated_at_key = ['updated_at', :updated_at].find(&token.method(:[]))
26
+
27
+ return token unless token[updated_at_key].respond_to?(:iso8601)
28
+
29
+ token.merge updated_at_key => token[updated_at_key].iso8601
30
+ end
31
+ end