devise_token_auth 0.1.32.beta10 → 0.1.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -31
  3. data/app/controllers/devise_token_auth/confirmations_controller.rb +2 -0
  4. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +2 -0
  5. data/app/controllers/devise_token_auth/passwords_controller.rb +25 -14
  6. data/app/controllers/devise_token_auth/registrations_controller.rb +22 -11
  7. data/app/controllers/devise_token_auth/sessions_controller.rb +15 -9
  8. data/app/controllers/devise_token_auth/token_validations_controller.rb +2 -1
  9. data/app/models/devise_token_auth/concerns/user.rb +19 -14
  10. data/app/validators/email_validator.rb +1 -1
  11. data/config/locales/en.yml +30 -0
  12. data/config/locales/es.yml +30 -0
  13. data/config/locales/fr.yml +30 -0
  14. data/lib/devise_token_auth/engine.rb +10 -8
  15. data/lib/devise_token_auth/version.rb +1 -1
  16. data/lib/generators/devise_token_auth/install_generator.rb +28 -0
  17. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +6 -0
  18. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +2 -2
  19. data/test/controllers/custom/custom_confirmations_controller_test.rb +26 -0
  20. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +29 -0
  21. data/test/controllers/custom/custom_passwords_controller_test.rb +66 -0
  22. data/test/controllers/custom/custom_registrations_controller_test.rb +1 -1
  23. data/test/controllers/custom/custom_sessions_controller_test.rb +30 -0
  24. data/test/controllers/custom/custom_token_validations_controller_test.rb +29 -0
  25. data/test/controllers/devise_token_auth/passwords_controller_test.rb +159 -10
  26. data/test/controllers/devise_token_auth/registrations_controller_test.rb +249 -58
  27. data/test/controllers/devise_token_auth/sessions_controller_test.rb +80 -1
  28. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +17 -0
  29. data/test/dummy/app/controllers/application_controller.rb +1 -0
  30. data/test/dummy/app/controllers/custom/confirmations_controller.rb +13 -0
  31. data/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb +13 -0
  32. data/test/dummy/app/controllers/custom/passwords_controller.rb +35 -0
  33. data/test/dummy/app/controllers/custom/sessions_controller.rb +23 -0
  34. data/test/dummy/app/controllers/custom/token_validations_controller.rb +13 -0
  35. data/test/dummy/app/models/unconfirmable_user.rb +8 -0
  36. data/test/dummy/config/application.rb +1 -0
  37. data/test/dummy/config/routes.rb +8 -1
  38. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +7 -1
  39. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +7 -1
  40. data/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb +7 -1
  41. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +7 -1
  42. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +7 -1
  43. data/test/dummy/db/migrate/20150409095712_devise_token_auth_create_nice_users.rb +7 -1
  44. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +60 -0
  45. data/test/dummy/db/schema.rb +89 -64
  46. data/test/dummy/db/test.sqlite3 +0 -0
  47. data/test/dummy/lib/migration_database_helper.rb +29 -0
  48. data/test/dummy/log/test.log +41319 -29566
  49. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +6 -0
  50. data/test/dummy/tmp/generators/config/routes.rb +4 -0
  51. data/test/dummy/tmp/generators/db/migrate/{20150617175802_devise_token_auth_create_users.rb → 20150729144233_devise_token_auth_create_users.rb} +1 -1
  52. data/test/fixtures/unconfirmable_users.yml +9 -0
  53. data/test/fixtures/users.yml +12 -0
  54. data/test/models/user_test.rb +21 -0
  55. metadata +39 -13
  56. data/config/locales/devise.en.yml +0 -59
  57. data/test/dummy/db/development.sqlite3 +0 -0
  58. data/test/dummy/log/development.log +0 -473
  59. data/test/dummy/tmp/generators/app/controllers/application_controller.rb +0 -6
@@ -6,6 +6,7 @@ module DeviseTokenAuth
6
6
  def validate_token
7
7
  # @resource will have been set by set_user_token concern
8
8
  if @resource
9
+ yield if block_given?
9
10
  render json: {
10
11
  success: true,
11
12
  data: @resource.token_validation_response
@@ -13,7 +14,7 @@ module DeviseTokenAuth
13
14
  else
14
15
  render json: {
15
16
  success: false,
16
- errors: ["Invalid login credentials"]
17
+ errors: [I18n.t("devise_token_auth.token_validations.invalid")]
17
18
  }, status: 401
18
19
  end
19
20
  end
@@ -21,7 +21,9 @@ module DeviseTokenAuth::Concerns::User
21
21
  self.devise_modules.delete(:omniauthable)
22
22
  end
23
23
 
24
- serialize :tokens, JSON
24
+ unless tokens_has_json_column_type?
25
+ serialize :tokens, JSON
26
+ end
25
27
 
26
28
  validates :email, presence: true, email: true, if: Proc.new { |u| u.provider == 'email' }
27
29
  validates_presence_of :uid, if: Proc.new { |u| u.provider != 'email' }
@@ -76,18 +78,21 @@ module DeviseTokenAuth::Concerns::User
76
78
  # fall back to "default" config name
77
79
  opts[:client_config] ||= "default"
78
80
 
79
- if respond_to?(:pending_reconfirmation?) && pending_reconfirmation?
80
- opts[:to] = unconfirmed_email
81
- else
82
- opts[:to] = email
83
- end
84
-
85
81
  send_devise_notification(:reset_password_instructions, token, opts)
86
82
 
87
83
  token
88
84
  end
89
85
  end
90
86
 
87
+ module ClassMethods
88
+ protected
89
+
90
+
91
+ def tokens_has_json_column_type?
92
+ table_exists? && self.columns_hash['tokens'] && self.columns_hash['tokens'].type.in?([:json, :jsonb])
93
+ end
94
+ end
95
+
91
96
 
92
97
  def valid_token?(token, client_id='default')
93
98
  client_id ||= 'default'
@@ -218,16 +223,14 @@ module DeviseTokenAuth::Concerns::User
218
223
  protected
219
224
 
220
225
 
221
- # NOTE: ensure that fragment comes AFTER querystring for proper $location
222
- # parsing using AngularJS.
223
226
  def generate_url(url, params = {})
224
227
  uri = URI(url)
225
228
 
226
229
  res = "#{uri.scheme}://#{uri.host}"
227
230
  res += ":#{uri.port}" if (uri.port and uri.port != 80 and uri.port != 443)
228
231
  res += "#{uri.path}" if uri.path
229
- res += "##{uri.fragment}" if uri.fragment
230
232
  res += "?#{params.to_query}"
233
+ res += "##{uri.fragment}" if uri.fragment
231
234
 
232
235
  return res
233
236
  end
@@ -248,10 +251,12 @@ module DeviseTokenAuth::Concerns::User
248
251
  end
249
252
 
250
253
  def destroy_expired_tokens
251
- self.tokens.delete_if{|cid,v|
252
- expiry = v[:expiry] || v["expiry"]
253
- DateTime.strptime(expiry.to_s, '%s') < Time.now
254
- }
254
+ if self.tokens
255
+ self.tokens.delete_if do |cid, v|
256
+ expiry = v[:expiry] || v["expiry"]
257
+ DateTime.strptime(expiry.to_s, '%s') < Time.now
258
+ end
259
+ end
255
260
  end
256
261
 
257
262
  end
@@ -1,7 +1,7 @@
1
1
  class EmailValidator < ActiveModel::EachValidator
2
2
  def validate_each(record, attribute, value)
3
3
  unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
4
- record.errors[attribute] << (options[:message] || 'is not an email')
4
+ record.errors[attribute] << (options[:message] || I18n.t("errors.not_email"))
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,30 @@
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` param."
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
+ passwords:
18
+ missing_email: "You must provide an email address."
19
+ missing_redirect_url: "Missing redirect url."
20
+ not_allowed_redirect_url: "Redirect to %{redirect_url} not allowed."
21
+ sended: "An email has been sent to %{email} containing instructions for resetting your password."
22
+ user_not_found: "Unable to find user with email '%{email}'."
23
+ password_not_required: "This account does not require a password. Sign in using your %{provider} account instead."
24
+ missing_passwords: 'You must fill out the fields labeled "password" and "password confirmation".'
25
+ successfully_updated: "Your password has been successfully updated."
26
+
27
+ errors:
28
+ validate_sign_up_params: "Please submit proper sign up data in request body."
29
+ validate_account_update_params: "Please submit proper account update data in request body."
30
+ not_email: "is not an email"
@@ -0,0 +1,30 @@
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
+ passwords:
18
+ missing_email: "Debe incluir un correo electrónico."
19
+ missing_redirect_url: "Falta el Url de redirección."
20
+ not_allowed_redirect_url: "Redirección hacia %{redirect_url} no esta permitida."
21
+ sended: "Un correo electrónico ha sido enviado a %{email} con las instrucciones para restablecer su contraseña."
22
+ user_not_found: "No se pudo encontrar un usuario con este correo electrónico: '%{email}'."
23
+ password_not_required: "Esta cuenta no requiere contraseña. Iniciar sesión utilizando %{provider}."
24
+ missing_passwords: 'Debe llenar los campos "contraseña" y "confirmación de contraseña".'
25
+ successfully_updated: "Su contraseña ha sido actualizada con éxito."
26
+
27
+ errors:
28
+ validate_sign_up_params: "Los datos introducidos en la solicitud de acceso no son válidos."
29
+ validate_account_update_params: "Los datos introducidos en la solicitud de actualización no son válidos."
30
+ not_email: "no es un correo electrónico"
@@ -0,0 +1,30 @@
1
+ fr:
2
+ devise_token_auth:
3
+ sessions:
4
+ not_confirmed: "Une email de confirmation de votre compte a été envoyé à %{email}. Merci de suivre les instructions afin de valider votre compte"
5
+ bad_credentials: "Mot de passe ou identifiant invalide."
6
+ not_supported: "Utilisez POST /sign_in pour la connexion. GET n'est pas supporté."
7
+ user_not_found: "L'utilisateur est inconnu ou n'est pas connecté."
8
+ token_validations:
9
+ invalid: "Mot de passe ou identifiant invalide."
10
+ registrations:
11
+ missing_confirm_success_url: "Le paramètre `confirm_success_url` est manquant."
12
+ redirect_url_not_allowed: "Redirection vers %{redirect_url} n'est pas autorisée."
13
+ email_already_exists: "Un compte existe déjà avec cet email: %{email}"
14
+ account_with_uid_destroyed: "Le compte avec l'identifiant %{uid} a été supprimé."
15
+ account_to_destroy_not_found: "Impossible de trouver le compte à supprimer."
16
+ user_not_found: "Utilisateur non trouvé."
17
+ passwords:
18
+ missing_email: "Vous devez soumettre un email."
19
+ missing_redirect_url: "Url de redirection manquante."
20
+ not_allowed_redirect_url: "Redirection vers %{redirect_url} n'est pas autorisée."
21
+ sended: "Un email a été envoyé à %{email} avec les instructions pour réinitialiser votre mot de passe."
22
+ user_not_found: "Impossible de trouver un utilisateur avec cet email: '%{email}'."
23
+ password_not_required: "Ce compte ne demande pas de mot de passe. Connectez vous plutôt en utilisant %{provider}."
24
+ missing_passwords: 'Vous devez remplir les champs "mt de passe" et "confirmation de mot de passe".'
25
+ successfully_updated: "Votre mot de passe a été correctement mis à jour."
26
+
27
+ errors:
28
+ validate_sign_up_params: "Les données de l'inscription dans le corps de la requête ne sont pas valides."
29
+ validate_account_update_params: "Les données de mise à jour dans le corps de la requête ne sont pas valides."
30
+ not_email: "n'est pas un email"
@@ -15,15 +15,17 @@ module DeviseTokenAuth
15
15
  :omniauth_prefix,
16
16
  :default_confirm_success_url,
17
17
  :default_password_reset_url,
18
- :redirect_whitelist
18
+ :redirect_whitelist,
19
+ :check_current_password_before_update
19
20
 
20
- self.change_headers_on_each_request = true
21
- self.token_lifespan = 2.weeks
22
- self.batch_request_buffer_throttle = 5.seconds
23
- self.omniauth_prefix = '/omniauth'
24
- self.default_confirm_success_url = nil
25
- self.default_password_reset_url = nil
26
- self.redirect_whitelist = nil
21
+ self.change_headers_on_each_request = true
22
+ self.token_lifespan = 2.weeks
23
+ self.batch_request_buffer_throttle = 5.seconds
24
+ self.omniauth_prefix = '/omniauth'
25
+ self.default_confirm_success_url = nil
26
+ self.default_password_reset_url = nil
27
+ self.redirect_whitelist = nil
28
+ self.check_current_password_before_update = false
27
29
 
28
30
  def self.setup(&block)
29
31
  yield self
@@ -1,3 +1,3 @@
1
1
  module DeviseTokenAuth
2
- VERSION = "0.1.32.beta10"
2
+ VERSION = "0.1.32"
3
3
  end
@@ -115,5 +115,33 @@ module DeviseTokenAuth
115
115
  end
116
116
  match
117
117
  end
118
+
119
+ def json_supported_database?
120
+ (postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?)
121
+ end
122
+
123
+ def postgres?
124
+ database_name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
125
+ end
126
+
127
+ def postgres_correct_version?
128
+ database_version > '9.3'
129
+ end
130
+
131
+ def mysql?
132
+ database_name == 'ActiveRecord::ConnectionAdapters::MysqlAdapter'
133
+ end
134
+
135
+ def mysql_correct_version?
136
+ database_version > '5.7.7'
137
+ end
138
+
139
+ def database_name
140
+ ActiveRecord::Base.connection.class.name
141
+ end
142
+
143
+ def database_version
144
+ ActiveRecord::Base.connection.select_value('SELECT VERSION()')
145
+ end
118
146
  end
119
147
  end
@@ -19,4 +19,10 @@ DeviseTokenAuth.setup do |config|
19
19
  # example, using the default '/omniauth', the github oauth2 provider will
20
20
  # redirect successful authentications to '/omniauth/github/callback'
21
21
  #config.omniauth_prefix = "/omniauth"
22
+
23
+ # By defult sending current password is not needed for the password update.
24
+ # Uncomment to enforce current_password param to be checked before all
25
+ # attribute updates. Set it to :password if you want it to be checked only if
26
+ # password is updated.
27
+ # config.check_current_password_before_update = :attributes
22
28
  end
@@ -2,7 +2,7 @@ class DeviseTokenAuthCreate<%= user_class.pluralize %> < ActiveRecord::Migration
2
2
  def change
3
3
  create_table(:<%= user_class.pluralize.underscore %>) do |t|
4
4
  ## Required
5
- t.string :provider, :null => false
5
+ t.string :provider, :null => false, :default => "email"
6
6
  t.string :uid, :null => false, :default => ""
7
7
 
8
8
  ## Database authenticatable
@@ -40,7 +40,7 @@ class DeviseTokenAuthCreate<%= user_class.pluralize %> < ActiveRecord::Migration
40
40
  t.string :email
41
41
 
42
42
  ## Tokens
43
- t.text :tokens
43
+ <%= json_supported_database? ? 't.json :tokens' : 't.text :tokens' %>
44
44
 
45
45
  t.timestamps
46
46
  end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class Custom::ConfirmationsControllerTest < ActionController::TestCase
4
+
5
+ describe Custom::ConfirmationsController do
6
+
7
+ before do
8
+ @redirect_url = Faker::Internet.url
9
+ @new_user = users(:unconfirmed_email_user)
10
+ @new_user.send_confirmation_instructions({
11
+ redirect_url: @redirect_url
12
+ })
13
+ @mail = ActionMailer::Base.deliveries.last
14
+ @token = @mail.body.match(/confirmation_token=([^&]*)&/)[1]
15
+ @client_config = @mail.body.match(/config=([^&]*)&/)[1]
16
+
17
+ get :show, {confirmation_token: @token, redirect_url: @redirect_url}
18
+ end
19
+
20
+ test "yield resource to block on show success" do
21
+ assert @controller.show_block_called?, "show failed to yield resource to provided block"
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class Custom::OmniauthCallbacksControllerTest < ActionDispatch::IntegrationTest
4
+
5
+ describe Custom::OmniauthCallbacksController do
6
+
7
+ setup do
8
+ OmniAuth.config.test_mode = true
9
+ OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
10
+ :provider => 'facebook',
11
+ :uid => '123545',
12
+ :info => {
13
+ name: 'swong',
14
+ email: 'swongsong@yandex.ru'
15
+ }
16
+ })
17
+ end
18
+
19
+ test "yield resource to block on omniauth_sucess success" do
20
+ @redirect_url = "http://ng-token-auth.dev/"
21
+ get_via_redirect '/nice_user_auth/facebook', {
22
+ auth_origin_url: @redirect_url
23
+ }
24
+ assert @controller.omniauth_success_block_called?, "omniauth_success failed to yield resource to provided block"
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ class Custom::PasswordsControllerTest < ActionController::TestCase
4
+
5
+ describe Custom::PasswordsController do
6
+
7
+ before do
8
+ @resource = users(:confirmed_email_user)
9
+ @redirect_url = 'http://ng-token-auth.dev'
10
+ end
11
+
12
+ test "yield resource to block on create success" do
13
+ post :create, {
14
+ email: @resource.email,
15
+ redirect_url: @redirect_url
16
+ }
17
+
18
+ @mail = ActionMailer::Base.deliveries.last
19
+ @resource.reload
20
+
21
+ @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1])
22
+ @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1])
23
+ @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1]
24
+
25
+ assert @controller.create_block_called?, "create failed to yield resource to provided block"
26
+ end
27
+
28
+ test "yield resource to block on edit success" do
29
+ @resource = users(:unconfirmed_email_user)
30
+ @redirect_url = 'http://ng-token-auth.dev'
31
+
32
+ xhr :post, :create, {
33
+ email: @resource.email,
34
+ redirect_url: @redirect_url
35
+ }
36
+
37
+ @mail = ActionMailer::Base.deliveries.last
38
+ @resource.reload
39
+
40
+ @mail_config_name = CGI.unescape(@mail.body.match(/config=([^&]*)&/)[1])
41
+ @mail_redirect_url = CGI.unescape(@mail.body.match(/redirect_url=([^&]*)&/)[1])
42
+ @mail_reset_token = @mail.body.match(/reset_password_token=(.*)\"/)[1]
43
+
44
+ xhr :get, :edit, {
45
+ reset_password_token: @mail_reset_token,
46
+ redirect_url: @mail_redirect_url
47
+ }
48
+
49
+ @resource.reload
50
+ assert @controller.edit_block_called?, "edit failed to yield resource to provided block"
51
+ end
52
+
53
+ test "yield resource to block on update success" do
54
+ @auth_headers = @resource.create_new_auth_token
55
+ request.headers.merge!(@auth_headers)
56
+ @new_password = Faker::Internet.password
57
+ put :update, {
58
+ password: @new_password,
59
+ password_confirmation: @new_password
60
+ }
61
+ assert @controller.update_block_called?, "update failed to yield resource to provided block"
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -35,7 +35,7 @@ class Custom::RegistrationsControllerTest < ActionDispatch::IntegrationTest
35
35
 
36
36
  test "yield resource to block on destroy success" do
37
37
  delete '/nice_user_auth', @auth_headers
38
- assert @controller.destroy_block_called?, "update failed to yield resource to provided block"
38
+ assert @controller.destroy_block_called?, "destroy failed to yield resource to provided block"
39
39
  end
40
40
 
41
41
  end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class Custom::SessionsControllerTest < ActionController::TestCase
4
+
5
+ describe Custom::SessionsController do
6
+
7
+ before do
8
+ @existing_user = users(:confirmed_email_user)
9
+ @existing_user.skip_confirmation!
10
+ @existing_user.save!
11
+ end
12
+
13
+ test "yield resource to block on create success" do
14
+ post :create, {
15
+ email: @existing_user.email,
16
+ password: 'secret123'
17
+ }
18
+ assert @controller.create_block_called?, "create failed to yield resource to provided block"
19
+ end
20
+
21
+ test "yield resource to block on destroy success" do
22
+ @auth_headers = @existing_user.create_new_auth_token
23
+ request.headers.merge!(@auth_headers)
24
+ delete :destroy, format: :json
25
+ assert @controller.destroy_block_called?, "destroy failed to yield resource to provided block"
26
+ end
27
+
28
+ end
29
+
30
+ end