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
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth::Concerns::User
4
+ extend ActiveSupport::Concern
5
+
6
+ def self.tokens_match?(token_hash, token)
7
+ @token_equality_cache ||= {}
8
+
9
+ key = "#{token_hash}/#{token}"
10
+ result = @token_equality_cache[key] ||= DeviseTokenAuth::TokenFactory.token_hash_is_token?(token_hash, token)
11
+ @token_equality_cache = {} if @token_equality_cache.size > 10000
12
+ result
13
+ end
14
+
15
+ included do
16
+ # Hack to check if devise is already enabled
17
+ if method_defined?(:devise_modules)
18
+ devise_modules.delete(:omniauthable)
19
+ else
20
+ devise :database_authenticatable, :registerable,
21
+ :recoverable, :validatable, :confirmable
22
+ end
23
+
24
+ if const_defined?('ActiveRecord') && ancestors.include?(ActiveRecord::Base)
25
+ include DeviseTokenAuth::Concerns::ActiveRecordSupport
26
+ end
27
+
28
+ if const_defined?('Mongoid') && ancestors.include?(Mongoid::Document)
29
+ include DeviseTokenAuth::Concerns::MongoidSupport
30
+ end
31
+
32
+ if DeviseTokenAuth.default_callbacks
33
+ include DeviseTokenAuth::Concerns::UserOmniauthCallbacks
34
+ end
35
+
36
+ # get rid of dead tokens
37
+ before_save :destroy_expired_tokens
38
+
39
+ # remove old tokens if password has changed
40
+ before_save :remove_tokens_after_password_reset
41
+
42
+ # don't use default devise email validation
43
+ def email_required?; false; end
44
+ def devise_will_save_change_to_email?; false; end
45
+
46
+ if DeviseTokenAuth.send_confirmation_email && devise_modules.include?(:confirmable)
47
+ include DeviseTokenAuth::Concerns::ConfirmableSupport
48
+ end
49
+
50
+ def password_required?
51
+ return false unless provider == 'email'
52
+ super
53
+ end
54
+
55
+ # override devise method to include additional info as opts hash
56
+ def send_confirmation_instructions(opts = {})
57
+ generate_confirmation_token! unless @raw_confirmation_token
58
+
59
+ # fall back to "default" config name
60
+ opts[:client_config] ||= 'default'
61
+ opts[:to] = unconfirmed_email if pending_reconfirmation?
62
+ opts[:redirect_url] ||= DeviseTokenAuth.default_confirm_success_url
63
+
64
+ send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
65
+ end
66
+
67
+ # override devise method to include additional info as opts hash
68
+ def send_reset_password_instructions(opts = {})
69
+ token = set_reset_password_token
70
+
71
+ # fall back to "default" config name
72
+ opts[:client_config] ||= 'default'
73
+
74
+ send_devise_notification(:reset_password_instructions, token, opts)
75
+ token
76
+ end
77
+
78
+ # override devise method to include additional info as opts hash
79
+ def send_unlock_instructions(opts = {})
80
+ raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
81
+ self.unlock_token = enc
82
+ save(validate: false)
83
+
84
+ # fall back to "default" config name
85
+ opts[:client_config] ||= 'default'
86
+
87
+ send_devise_notification(:unlock_instructions, raw, opts)
88
+ raw
89
+ end
90
+
91
+ def create_token(client: nil, lifespan: nil, cost: nil, **token_extras)
92
+ token = DeviseTokenAuth::TokenFactory.create(client: client, lifespan: lifespan, cost: cost)
93
+
94
+ tokens[token.client] = {
95
+ token: token.token_hash,
96
+ expiry: token.expiry
97
+ }.merge!(token_extras)
98
+
99
+ clean_old_tokens
100
+
101
+ token
102
+ end
103
+ end
104
+
105
+ def valid_token?(token, client = 'default')
106
+ return false unless tokens[client]
107
+ return true if token_is_current?(token, client)
108
+ return true if token_can_be_reused?(token, client)
109
+
110
+ # return false if none of the above conditions are met
111
+ false
112
+ end
113
+
114
+ # this must be done from the controller so that additional params
115
+ # can be passed on from the client
116
+ def send_confirmation_notification?; false; end
117
+
118
+ def token_is_current?(token, client)
119
+ # ghetto HashWithIndifferentAccess
120
+ expiry = tokens[client]['expiry'] || tokens[client][:expiry]
121
+ token_hash = tokens[client]['token'] || tokens[client][:token]
122
+ previous_token_hash = tokens[client]['previous_token'] || tokens[client][:previous_token]
123
+
124
+ return true if (
125
+ # ensure that expiry and token are set
126
+ expiry && token &&
127
+
128
+ # ensure that the token has not yet expired
129
+ DateTime.strptime(expiry.to_s, '%s') > Time.zone.now &&
130
+
131
+ # ensure that the token is valid
132
+ (
133
+ # check if the latest token matches
134
+ does_token_match?(token_hash, token) ||
135
+
136
+ # check if the previous token matches
137
+ does_token_match?(previous_token_hash, token)
138
+ )
139
+ )
140
+ end
141
+
142
+ # check if the hash of received token matches the stored token
143
+ def does_token_match?(token_hash, token)
144
+ return false if token_hash.nil?
145
+
146
+ DeviseTokenAuth::Concerns::User.tokens_match?(token_hash, token)
147
+ end
148
+
149
+ # allow batch requests to use the last token
150
+ def token_can_be_reused?(token, client)
151
+ # ghetto HashWithIndifferentAccess
152
+ updated_at = tokens[client]['updated_at'] || tokens[client][:updated_at]
153
+ last_token_hash = tokens[client]['last_token'] || tokens[client][:last_token]
154
+
155
+ return true if (
156
+ # ensure that the last token and its creation time exist
157
+ updated_at && last_token_hash &&
158
+
159
+ # ensure that last token falls within the batch buffer throttle time of the last request
160
+ updated_at.to_time > Time.zone.now - DeviseTokenAuth.batch_request_buffer_throttle &&
161
+
162
+ # ensure that the token is valid
163
+ DeviseTokenAuth::TokenFactory.token_hash_is_token?(last_token_hash, token)
164
+ )
165
+ end
166
+
167
+ # update user's auth token (should happen on each request)
168
+ def create_new_auth_token(client = nil)
169
+ now = Time.zone.now
170
+
171
+ token = create_token(
172
+ client: client,
173
+ previous_token: tokens.fetch(client, {})['token'],
174
+ last_token: tokens.fetch(client, {})['previous_token'],
175
+ updated_at: now
176
+ )
177
+
178
+ update_auth_headers(token.token, token.client)
179
+ end
180
+
181
+ def build_auth_headers(token, client = 'default')
182
+ # client may use expiry to prevent validation request if expired
183
+ # must be cast as string or headers will break
184
+ expiry = tokens[client]['expiry'] || tokens[client][:expiry]
185
+ headers = {
186
+ DeviseTokenAuth.headers_names[:"access-token"] => token,
187
+ DeviseTokenAuth.headers_names[:"token-type"] => 'Bearer',
188
+ DeviseTokenAuth.headers_names[:"client"] => client,
189
+ DeviseTokenAuth.headers_names[:"expiry"] => expiry.to_s,
190
+ DeviseTokenAuth.headers_names[:"uid"] => uid
191
+ }
192
+ headers.merge(build_bearer_token(headers))
193
+ end
194
+
195
+ def build_bearer_token(auth)
196
+ return {} if DeviseTokenAuth.cookie_enabled # There is no need for the bearer token if it is using cookies
197
+
198
+ encoded_token = Base64.strict_encode64(auth.to_json)
199
+ bearer_token = "Bearer #{encoded_token}"
200
+ { DeviseTokenAuth.headers_names[:"authorization"] => bearer_token }
201
+ end
202
+
203
+ def update_auth_headers(token, client = 'default')
204
+ headers = build_auth_headers(token, client)
205
+ clean_old_tokens
206
+ save!
207
+
208
+ headers
209
+ end
210
+
211
+ def build_auth_url(base_url, args)
212
+ args[:uid] = uid
213
+ args[:expiry] = tokens[args[:client_id]]['expiry']
214
+
215
+ DeviseTokenAuth::Url.generate(base_url, args)
216
+ end
217
+
218
+ def extend_batch_buffer(token, client)
219
+ tokens[client]['updated_at'] = Time.zone.now
220
+ update_auth_headers(token, client)
221
+ end
222
+
223
+ def confirmed?
224
+ devise_modules.exclude?(:confirmable) || super
225
+ end
226
+
227
+ def token_validation_response
228
+ as_json(except: %i[tokens created_at updated_at])
229
+ end
230
+
231
+ protected
232
+
233
+ def destroy_expired_tokens
234
+ if tokens
235
+ tokens.delete_if do |cid, v|
236
+ expiry = v[:expiry] || v['expiry']
237
+ DateTime.strptime(expiry.to_s, '%s') < Time.zone.now
238
+ end
239
+ end
240
+ end
241
+
242
+ def should_remove_tokens_after_password_reset?
243
+ DeviseTokenAuth.remove_tokens_after_password_reset &&
244
+ (respond_to?(:encrypted_password_changed?) && encrypted_password_changed?)
245
+ end
246
+
247
+ def remove_tokens_after_password_reset
248
+ return unless should_remove_tokens_after_password_reset?
249
+
250
+ if tokens.present? && tokens.many?
251
+ client, token_data = tokens.max_by { |cid, v| v[:expiry] || v['expiry'] }
252
+ self.tokens = { client => token_data }
253
+ end
254
+ end
255
+
256
+ def max_client_tokens_exceeded?
257
+ tokens.length > DeviseTokenAuth.max_number_of_devices
258
+ end
259
+
260
+ def clean_old_tokens
261
+ return if tokens.blank? || !max_client_tokens_exceeded?
262
+
263
+ # First, remove any tokens with expiry greater than current max allowed lifespan
264
+ # this handles the case where token lifespan was reduced and old tokens exist.
265
+ # The threshold MUST be computed the same way TokenFactory.expiry writes
266
+ # expiries — calendar advance (Time.zone.now + lifespan) — otherwise a
267
+ # calendar Duration (e.g. 2.months) and its average-seconds form
268
+ # (token_lifespan.to_i) disagree by hours, and the freshly minted token
269
+ # gets purged out from under the response.
270
+ max_lifespan_expiry = (Time.zone.now + DeviseTokenAuth.token_lifespan).to_i
271
+ tokens_to_keep = tokens.select do |_cid, v|
272
+ expiry = (v[:expiry] || v['expiry']).to_i
273
+ expiry <= max_lifespan_expiry
274
+ end
275
+
276
+ # Using Enumerable#sort_by on a Hash will typecast it into an associative
277
+ # Array (i.e. an Array of key-value Array pairs). However, since Hashes
278
+ # have an internal order in Ruby 1.9+, the resulting sorted associative
279
+ # Array can be converted back into a Hash, while maintaining the sorted
280
+ # order.
281
+ self.tokens = tokens_to_keep.sort_by { |_cid, v| v[:expiry] || v['expiry'] }.to_h
282
+
283
+ # Since the tokens are sorted by expiry, shift the oldest client token
284
+ # off the Hash until it no longer exceeds the maximum number of clients
285
+ tokens.shift while max_client_tokens_exceeded?
286
+ end
287
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth::Concerns::UserOmniauthCallbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ validates :email, presence: true, if: lambda { uid_and_provider_defined? && email_provider? }
8
+ validates :email, :devise_token_auth_email => true, allow_nil: true, allow_blank: true, if: lambda { uid_and_provider_defined? && email_provider? }
9
+ validates_presence_of :uid, if: lambda { uid_and_provider_defined? && !email_provider? }
10
+
11
+ # only validate unique emails among email registration users
12
+ validates :email, uniqueness: { case_sensitive: false, scope: :provider }, on: :create, if: lambda { uid_and_provider_defined? && email_provider? }
13
+
14
+ # keep uid in sync with email
15
+ before_save :sync_uid
16
+ before_create :sync_uid
17
+ end
18
+
19
+ protected
20
+
21
+ def uid_and_provider_defined?
22
+ defined?(provider) && defined?(uid)
23
+ end
24
+
25
+ def email_provider?
26
+ provider == 'email'
27
+ end
28
+
29
+ def sync_uid
30
+ unless self.new_record?
31
+ return if devise_modules.include?(:confirmable) && !@bypass_confirmation_postpone && postpone_email_change?
32
+ end
33
+ self.uid = email if uid_and_provider_defined? && email_provider?
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DeviseTokenAuthEmailValidator < ActiveModel::EachValidator
4
+ EMAIL_REGEXP = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
5
+
6
+ class << self
7
+ def validate?(email)
8
+ email =~ EMAIL_REGEXP
9
+ end
10
+ end
11
+
12
+ def validate_each(record, attribute, value)
13
+ unless DeviseTokenAuthEmailValidator.validate?(value)
14
+ record.errors.add(attribute, email_invalid_message)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def email_invalid_message
21
+ # Try strictly set message:
22
+ message = options[:message]
23
+
24
+ if message.nil?
25
+ # Try DeviceTokenAuth translations or fallback to ActiveModel translations
26
+ message = I18n.t(:'errors.messages.not_email', default: :'errors.messages.invalid')
27
+ end
28
+
29
+ message
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ <p><%= t(:welcome).capitalize + ' ' + @email %>!</p>
2
+
3
+ <p><%= t '.confirm_link_msg' %> </p>
4
+
5
+ <p><%= link_to t('.confirm_account_link'), confirmation_url(@resource, {confirmation_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url']}).html_safe %></p>
@@ -0,0 +1,8 @@
1
+ <p><%= t(:hello).capitalize %> <%= @resource.email %>!</p>
2
+
3
+ <p><%= t '.request_reset_link_msg' %></p>
4
+
5
+ <p><%= link_to t('.password_change_link'), edit_password_url(@resource, reset_password_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s).html_safe %></p>
6
+
7
+ <p><%= t '.ignore_mail_msg' %></p>
8
+ <p><%= t '.no_changes_msg' %></p>
@@ -0,0 +1,7 @@
1
+ <p><%= t :hello %> <%= @resource.email %>!</p>
2
+
3
+ <p><%= t '.account_lock_msg' %></p>
4
+
5
+ <p><%= t '.unlock_link_msg' %></p>
6
+
7
+ <p><%= link_to t('.unlock_link'), unlock_url(@resource, unlock_token: @token, config: message['client-config'].to_s) %></p>
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <script>
5
+ /*
6
+ The data is accessible in two ways:
7
+
8
+ 1. Using the postMessage api, this window will respond to a
9
+ 'message' event with a post of all the data. (This can
10
+ be used by browsers other than IE if this window was
11
+ opened with window.open())
12
+ 2. This window has a function called requestCredentials which,
13
+ when called, will return the data. (This can be
14
+ used if this window was opened in an inAppBrowser using
15
+ Cordova / PhoneGap)
16
+ */
17
+
18
+ var data = JSON.parse(decodeURIComponent('<%= ERB::Util.url_encode( @data.to_json ) %>'));
19
+
20
+ window.addEventListener("message", function(ev) {
21
+ if (ev.data === "requestCredentials") {
22
+ ev.source.postMessage(data, '*');
23
+ window.close();
24
+ }
25
+ });
26
+ function requestCredentials() {
27
+ return data;
28
+ }
29
+ setTimeout(function() {
30
+ document.getElementById('text').innerHTML = (data && data.error) || 'Redirecting...';
31
+ }, 1000);
32
+ </script>
33
+ </head>
34
+ <body>
35
+ <pre id="text">
36
+ </pre>
37
+ </body>
38
+ </html>
@@ -0,0 +1,52 @@
1
+ da-DK:
2
+ devise_token_auth:
3
+ sessions:
4
+ not_confirmed: "Der er sendt en bekræftelsesemail til din konto på '%{email}'. Følg venligst instruktionerne i emailen for at aktivere din konto."
5
+ bad_credentials: "Ugyldig kombination af brugernavn og kodeord. Prøv venligst igen."
6
+ not_supported: "Brug POST /sign_in for at logge ind. GET er ikke supporteret."
7
+ user_not_found: "Brugeren er ikke fundet eller er ikke logget ind."
8
+ token_validations:
9
+ invalid: "Ugyldige legitimationsoplysninger."
10
+ registrations:
11
+ missing_confirm_success_url: "Der mangler et 'confirm_success_url' parameter."
12
+ redirect_url_not_allowed: "Omdirigering til '%{redirect_url}' er ikke tilladt."
13
+ email_already_exists: "Der eksisterer allerede en konto med '%{email}'"
14
+ account_with_uid_destroyed: "Kontoen med UID '%{uid}' er slettet."
15
+ account_to_destroy_not_found: "Kan ikke finde kontoen som skal slettes."
16
+ user_not_found: "Brugeren ikke fundet."
17
+ omniauth:
18
+ not_allowed_redirect_url: "Omdirigering til '%{redirect_url}' er ikke tilladt."
19
+ passwords:
20
+ missing_email: "Du skal udfylde email feltet."
21
+ missing_redirect_url: "Der er ingen omdirigeringsadresse."
22
+ redirect_url_not_allowed: "Omdirigering til '%{redirect_url}' er ikke tilladt."
23
+ sended: "En email er blevet sendt til '%{email}' med instruktioner for at nulstille dit kodeord."
24
+ user_not_found: "Kan ikke finde en bruger med '%{email}'."
25
+ password_not_required: "Denne bruger kræver ikke et kodeord. Log ind med '%{provider}' konto i stedet."
26
+ missing_passwords: "Du skal udfylde både kodeord og bekræftelse af kodeord."
27
+ successfully_updated: "Dit kodeord er opdateret."
28
+ unlocks:
29
+ missing_email: "Du skal udfylde en email."
30
+ sended: "En email er blevet sendt til '%{email}', som indeholder instruktioner for at låse kontoen op."
31
+ user_not_found: "Kan ikke finde en bruger med email '%{email}'."
32
+ errors:
33
+ messages:
34
+ validate_sign_up_params: "Angiv venligst passende registeringsdata i request body."
35
+ validate_account_update_params: "Angiv venligst en passende konto opdatering i request body."
36
+ not_email: "er ikke en email"
37
+ devise:
38
+ mailer:
39
+ confirmation_instructions:
40
+ confirm_link_msg: "Du kan bekræfte din kontos email gennem linket herunder:"
41
+ confirm_account_link: "Bekræft min konto"
42
+ reset_password_instructions:
43
+ request_reset_link_msg: "Nogen har anmodet om et link til at ændre dit kodeord. Det kan du gøre via linket nedenfor."
44
+ password_change_link: "Skift mit kodeord."
45
+ ignore_mail_msg: "Hvis du ikke anmodede om dette, ignorer venligst denne email."
46
+ no_changes_msg: "Dit kodeord ændres først når du følger linket ovenfor og skaber et nyt."
47
+ unlock_instructions:
48
+ account_lock_msg: "Din konto er blevet låst fordi der har været for mange ugyldige log ind-forsøg."
49
+ unlock_link_msg: "Klik linket nedenfor, for at låse din konto op:"
50
+ unlock_link: "Lås min konto op"
51
+ hello: "hej"
52
+ welcome: "velkommen"
@@ -0,0 +1,51 @@
1
+ de:
2
+ devise_token_auth:
3
+ sessions:
4
+ not_confirmed: "Eine Bestätigungs-E-Mail wurde an Ihre Adresse '%{email}' gesendet. Sie müssen der Anleitung in der E-Mail folgen, um Ihren Account zu aktivieren."
5
+ bad_credentials: "Ungültige Anmeldeinformationen. Bitte versuchen Sie es erneut."
6
+ not_supported: "Verwenden Sie POST /sign_in zur Anmeldung. GET wird nicht unterstützt."
7
+ user_not_found: "Benutzer wurde nicht gefunden oder konnte nicht angemeldet werden."
8
+ token_validations:
9
+ invalid: "Ungültige Anmeldeinformationen"
10
+ registrations:
11
+ missing_confirm_success_url: "Fehlender Paramter 'confirm_success_url'."
12
+ redirect_url_not_allowed: "Weiterleitung zu '%{redirect_url}' ist nicht gestattet."
13
+ email_already_exists: "Es gibt bereits einen Account für '%{email}'."
14
+ account_with_uid_destroyed: "Account mit der uid '%{uid}' wurde gelöscht."
15
+ account_to_destroy_not_found: "Der zu löschende Account kann nicht gefunden werden."
16
+ user_not_found: "Benutzer kann nicht gefunden werden."
17
+ omniauth:
18
+ not_allowed_redirect_url: "Weiterleitung zu '%{redirect_url}' ist nicht gestattet."
19
+ passwords:
20
+ missing_email: "Sie müssen eine E-Mail-Adresse angeben."
21
+ missing_redirect_url: "Es fehlt die URL zu Weiterleitung."
22
+ not_allowed_redirect_url: "Weiterleitung zu '%{redirect_url}' ist nicht gestattet."
23
+ sended: "Ein E-Mail mit der Anleitung zum Zurücksetzen Ihres Passwortes wurde an '%{email}' gesendet."
24
+ user_not_found: "Der Benutzer mit der E-Mail-Adresse '%{email}' kann nicht gefunden werden."
25
+ password_not_required: "Dieser Account benötigt kein Passwort. Melden Sie sich stattdessen über Ihren Account bei '%{provider}' an."
26
+ missing_passwords: "Sie müssen die Felder 'Passwort' und 'Passwortbestätigung' ausfüllen."
27
+ successfully_updated: "Ihr Passwort wurde erfolgreich aktualisiert."
28
+ errors:
29
+ messages:
30
+ validate_sign_up_params: "Bitte übermitteln sie vollständige Anmeldeinformationen im Body des Requests."
31
+ validate_account_update_params: "Bitte übermitteln sie vollständige Informationen zur Aktualisierung im Body des Requests."
32
+ not_email: "ist keine E-Mail-Adresse"
33
+ devise:
34
+ mailer:
35
+ confirmation_instructions:
36
+ subject: "Bestätigung Ihres Kontos"
37
+ confirm_link_msg: "Sie können Ihr Konto über den untenstehenden Link bestätigen:"
38
+ confirm_account_link: "Konto bestätigen"
39
+ reset_password_instructions:
40
+ subject: "Passwort zurücksetzen"
41
+ request_reset_link_msg: "Jemand hat einen Link zur Änderungen Ihres Passwortes angefordert. Sie können dies durch den folgenden Link tun:"
42
+ password_change_link: "Passwort ändern"
43
+ ignore_mail_msg: "Wenn Sie keine Änderung Ihres Passwortes angefordert haben, ignorieren Sie bitte diese E-Mail:"
44
+ no_changes_msg: "Ihr Passwort wird nicht geändert, bis Sie auf den obigen Link zugreifen und eine neues Passwort erstellen."
45
+ unlock_instructions:
46
+ subject: "Anweisungen zum Entsperren Ihres Kontos"
47
+ account_lock_msg: "Ihr Konto wurde aufgrund einer übermäßigen Anzahl von erfolglosen Anmeldeversuchen gesperrt."
48
+ unlock_link_msg: "Klicken Sie auf den Link unten, um Ihr Konto zu entsperren:"
49
+ unlock_link: "Entsperren Sie Ihr Konto"
50
+ hello: "hallo"
51
+ welcome: "willkommen"
@@ -0,0 +1,60 @@
1
+ en:
2
+ devise_token_auth:
3
+ sessions:
4
+ not_confirmed: "A confirmation email was sent to your account at '%{email}'. You must follow the instructions in the email before your account can be activated"
5
+ bad_credentials: "Invalid login credentials. Please try again."
6
+ not_supported: "Use POST /sign_in to sign in. GET is not supported."
7
+ user_not_found: "User was not found or was not logged in."
8
+ token_validations:
9
+ invalid: "Invalid login credentials"
10
+ registrations:
11
+ missing_confirm_success_url: "Missing 'confirm_success_url' parameter."
12
+ redirect_url_not_allowed: "Redirect to '%{redirect_url}' not allowed."
13
+ email_already_exists: "An account already exists for '%{email}'"
14
+ account_with_uid_destroyed: "Account with UID '%{uid}' has been destroyed."
15
+ account_to_destroy_not_found: "Unable to locate account for destruction."
16
+ user_not_found: "User not found."
17
+ omniauth:
18
+ not_allowed_redirect_url: "Redirect to '%{redirect_url}' not allowed."
19
+ passwords:
20
+ missing_email: "You must provide an email address."
21
+ missing_redirect_url: "Missing redirect URL."
22
+ not_allowed_redirect_url: "Redirect to '%{redirect_url}' not allowed."
23
+ sended: "An email has been sent to '%{email}' containing instructions for resetting your password."
24
+ sended_paranoid: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
25
+ user_not_found: "Unable to find user with email '%{email}'."
26
+ password_not_required: "This account does not require a password. Sign in using your '%{provider}' account instead."
27
+ missing_passwords: "You must fill out the fields labeled 'Password' and 'Password confirmation'."
28
+ successfully_updated: "Your password has been successfully updated."
29
+ unlocks:
30
+ missing_email: "You must provide an email address."
31
+ sended: "An email has been sent to '%{email}' containing instructions for unlocking your account."
32
+ sended_paranoid: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
33
+ user_not_found: "Unable to find user with email '%{email}'."
34
+ confirmations:
35
+ sended: "An email has been sent to '%{email}' containing instructions for confirming your account."
36
+ sended_paranoid: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
37
+ user_not_found: "Unable to find user with email '%{email}'."
38
+ missing_email: "You must provide an email address."
39
+
40
+ errors:
41
+ messages:
42
+ validate_sign_up_params: "Please submit proper sign up data in request body."
43
+ validate_account_update_params: "Please submit proper account update data in request body."
44
+ not_email: "is not an email"
45
+ devise:
46
+ mailer:
47
+ confirmation_instructions:
48
+ confirm_link_msg: "You can confirm your account email through the link below:"
49
+ confirm_account_link: "Confirm my account"
50
+ reset_password_instructions:
51
+ request_reset_link_msg: "Someone has requested a link to change your password. You can do this through the link below."
52
+ password_change_link: "Change my password"
53
+ ignore_mail_msg: "If you didn't request this, please ignore this email."
54
+ no_changes_msg: "Your password won't change until you access the link above and create a new one."
55
+ unlock_instructions:
56
+ account_lock_msg: "Your account has been locked due to an excessive number of unsuccessful sign in attempts."
57
+ unlock_link_msg: "Click the link below to unlock your account:"
58
+ unlock_link: "Unlock my account"
59
+ hello: "hello"
60
+ welcome: "welcome"
@@ -0,0 +1,51 @@
1
+ es:
2
+ devise_token_auth:
3
+ sessions:
4
+ not_confirmed: "Un correo electrónico de confirmación de su cuenta ha sido enviado a '%{email}'. Por favor, siga las instrucciones para validar su cuenta"
5
+ bad_credentials: "Identidad o contraseña no válida."
6
+ not_supported: "Use POST /sign_in para la conexión. GET no esta disponible."
7
+ user_not_found: "Usuario desconocido o no está conectado."
8
+ token_validations:
9
+ invalid: "Identidad o contraseña no válida."
10
+ registrations:
11
+ missing_confirm_success_url: "El parámetro 'confirm_success_url' no esta presente."
12
+ redirect_url_not_allowed: "Redirección hacia '%{redirect_url}' no esta permitida."
13
+ email_already_exists: "Una cuenta ya existe con este correo electrónico '%{email}'"
14
+ account_with_uid_destroyed: "La cuenta con el identificador '%{uid}' se ha eliminado."
15
+ account_to_destroy_not_found: "No se puede encontrar la cuenta a borrar."
16
+ user_not_found: "Usuario no encontrado."
17
+ omniauth:
18
+ not_allowed_redirect_url: "Redirección hacia '%{redirect_url}' no esta permitida."
19
+ passwords:
20
+ missing_email: "Debe incluir un correo electrónico."
21
+ missing_redirect_url: "Falta el Url de redirección."
22
+ not_allowed_redirect_url: "Redirección hacia '%{redirect_url}' no esta permitida."
23
+ sended: "Un correo electrónico ha sido enviado a '%{email}' con las instrucciones para restablecer su contraseña."
24
+ user_not_found: "No se pudo encontrar un usuario con este correo electrónico '%{email}'."
25
+ password_not_required: "Esta cuenta no requiere contraseña. Iniciar sesión utilizando '%{provider}'."
26
+ missing_passwords: "Debe llenar los campos 'Contraseña' y 'Confirmación de contraseña'."
27
+ successfully_updated: "Su contraseña ha sido actualizada con éxito."
28
+ errors:
29
+ messages:
30
+ validate_sign_up_params: "Los datos introducidos en la solicitud de acceso no son válidos."
31
+ validate_account_update_params: "Los datos introducidos en la solicitud de actualización no son válidos."
32
+ not_email: "no es un correo electrónico"
33
+ devise:
34
+ mailer:
35
+ confirmation_instructions:
36
+ subject: "Instrucciones de confirmación"
37
+ confirm_link_msg: "Para confirmar su cuenta ingrese en el siguiente link:"
38
+ confirm_account_link: "Confirmar cuenta"
39
+ reset_password_instructions:
40
+ subject: "Instrucciones para restablecer su contraseña"
41
+ request_reset_link_msg: "Ha solicitado un cambio de contraseña. Para continuar ingrese en el siguiente link:"
42
+ password_change_link: "Cambiar contraseña"
43
+ ignore_mail_msg: "Por favor ignore este mensaje si no ha solicitado esta acción."
44
+ no_changes_msg: "Importante: Su contraseña no será actualizada a menos que ingrese en el link."
45
+ unlock_instructions:
46
+ subject: "Instrucciones de desbloqueo"
47
+ account_lock_msg: "Su cuenta ha sido bloqueada debido a sucesivos intentos de ingresos fallidos"
48
+ unlock_link_msg: "Para desbloquear su cuenta ingrese en el siguiente link:"
49
+ unlock_link: "Desbloquear cuenta"
50
+ hello: "hola"
51
+ welcome: "bienvenido"