devise-security 0.14.3 → 0.15.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +114 -58
  3. data/app/controllers/devise/password_expired_controller.rb +10 -1
  4. data/app/views/devise/paranoid_verification_code/show.html.erb +3 -3
  5. data/app/views/devise/password_expired/show.html.erb +5 -5
  6. data/config/locales/by.yml +48 -0
  7. data/config/locales/cs.yml +40 -0
  8. data/config/locales/de.yml +12 -2
  9. data/config/locales/en.yml +12 -1
  10. data/config/locales/es.yml +9 -9
  11. data/config/locales/fa.yml +40 -0
  12. data/config/locales/hi.yml +41 -0
  13. data/config/locales/it.yml +34 -4
  14. data/config/locales/ja.yml +1 -1
  15. data/config/locales/nl.yml +40 -0
  16. data/config/locales/pt.yml +40 -0
  17. data/config/locales/ru.yml +48 -0
  18. data/config/locales/uk.yml +48 -0
  19. data/config/locales/zh_CN.yml +40 -0
  20. data/config/locales/zh_TW.yml +40 -0
  21. data/lib/devise-security/controllers/helpers.rb +59 -50
  22. data/lib/devise-security/hooks/password_expirable.rb +2 -0
  23. data/lib/devise-security/hooks/session_limitable.rb +13 -7
  24. data/lib/devise-security/models/password_expirable.rb +5 -1
  25. data/lib/devise-security/models/session_limitable.rb +8 -1
  26. data/lib/devise-security/validators/password_complexity_validator.rb +4 -2
  27. data/lib/devise-security/version.rb +1 -1
  28. data/lib/generators/devise_security/install_generator.rb +2 -2
  29. data/test/controllers/test_password_expired_controller.rb +111 -16
  30. data/test/dummy/app/assets/config/manifest.js +3 -0
  31. data/test/dummy/config/routes.rb +3 -3
  32. data/test/dummy/log/test.log +1799 -0
  33. data/test/integration/test_password_expirable_workflow.rb +57 -0
  34. data/test/orm/active_record.rb +4 -1
  35. data/test/support/integration_helpers.rb +1 -1
  36. data/test/test_complexity_validator.rb +12 -0
  37. data/test/test_helper.rb +10 -3
  38. data/test/test_install_generator.rb +10 -0
  39. data/test/test_session_limitable.rb +17 -0
  40. data/test/tmp/config/initializers/devise-security.rb +44 -0
  41. data/test/tmp/config/locales/devise.security_extension.de.yml +38 -0
  42. data/test/tmp/config/locales/devise.security_extension.en.yml +40 -0
  43. data/test/tmp/config/locales/devise.security_extension.es.yml +29 -0
  44. data/test/tmp/config/locales/devise.security_extension.fa.yml +40 -0
  45. data/test/tmp/config/locales/devise.security_extension.fr.yml +29 -0
  46. data/test/tmp/config/locales/devise.security_extension.it.yml +40 -0
  47. data/test/tmp/config/locales/devise.security_extension.ja.yml +29 -0
  48. data/test/tmp/config/locales/devise.security_extension.nl.yml +40 -0
  49. data/test/tmp/config/locales/devise.security_extension.pt.yml +40 -0
  50. data/test/tmp/config/locales/devise.security_extension.ru.yml +48 -0
  51. data/test/tmp/config/locales/devise.security_extension.tr.yml +17 -0
  52. data/test/tmp/config/locales/devise.security_extension.uk.yml +48 -0
  53. data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +40 -0
  54. metadata +152 -118
  55. data/.codeclimate.yml +0 -63
  56. data/.document +0 -5
  57. data/.gitignore +0 -43
  58. data/.mdlrc +0 -1
  59. data/.rubocop.yml +0 -64
  60. data/.ruby-version +0 -1
  61. data/.travis.yml +0 -39
  62. data/Appraisals +0 -35
  63. data/Gemfile +0 -10
  64. data/Rakefile +0 -27
  65. data/devise-security.gemspec +0 -50
  66. data/gemfiles/rails_4.2_stable.gemfile +0 -16
  67. data/gemfiles/rails_5.0_stable.gemfile +0 -15
  68. data/gemfiles/rails_5.1_stable.gemfile +0 -15
  69. data/gemfiles/rails_5.2_stable.gemfile +0 -15
  70. data/gemfiles/rails_6.0_beta.gemfile +0 -15
  71. data/test/dummy/app/models/.gitkeep +0 -0
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestPasswordExpirableWorkflow < ActionDispatch::IntegrationTest
6
+ include IntegrationHelpers
7
+
8
+ setup do
9
+ @user = User.create!(password: 'passWord1',
10
+ password_confirmation: 'passWord1',
11
+ email: 'bob@microsoft.com',
12
+ password_changed_at: 4.months.ago) # the default expiration time is 3.months.ago
13
+ @user.confirm
14
+
15
+ assert @user.valid?
16
+ assert @user.need_change_password?
17
+ end
18
+
19
+ test 'sign in and change expired password' do
20
+ skip("Does not work in Rails < 5.0") if Rails.gem_version < Gem::Version.new('5.0')
21
+
22
+ sign_in(@user)
23
+ assert_redirected_to(root_path)
24
+ follow_redirect!
25
+ assert_redirected_to(user_password_expired_path)
26
+ # @note This is not the same controller used by Devise for password changes
27
+ put '/users/password_expired', params: {
28
+ user: {
29
+ current_password: 'passWord1',
30
+ password: 'Password12345!',
31
+ password_confirmation: 'Password12345!',
32
+ },
33
+ }
34
+ assert_redirected_to(root_path)
35
+ @user.reload
36
+ assert_not @user.need_change_password?
37
+ end
38
+
39
+ test 'sign in and password is updated before redirect completes' do
40
+ skip("Does not work in Rails < 5.0") if Rails.gem_version < Gem::Version.new('5.0')
41
+
42
+ sign_in(@user)
43
+ assert_redirected_to(root_path)
44
+
45
+ # simulates an external process updating the password
46
+ @user.update(password_changed_at: Time.zone.now)
47
+ assert_not @user.need_change_password?
48
+
49
+ follow_redirect!
50
+ assert_response :success
51
+
52
+ # if the password is expired at this point they will be redirected to the
53
+ # password change controller.
54
+ get root_path
55
+ assert_response :success
56
+ end
57
+ end
@@ -2,7 +2,10 @@ require 'active_record'
2
2
 
3
3
  ActiveRecord::Migration.verbose = false
4
4
  ActiveRecord::Base.logger = Logger.new(nil)
5
- if Rails.gem_version >= Gem::Version.new('5.2.0')
5
+ case
6
+ when Rails.gem_version >= Gem::Version.new('6.0.0')
7
+ ActiveRecord::MigrationContext.new(File.expand_path('../../dummy/db/migrate', __FILE__), ActiveRecord::SchemaMigration).migrate
8
+ when Rails.gem_version >= Gem::Version.new('5.2.0')
6
9
  ActiveRecord::MigrationContext.new(File.expand_path('../../dummy/db/migrate', __FILE__)).migrate
7
10
  else
8
11
  ActiveRecord::Migrator.migrate(File.expand_path('../../dummy/db/migrate', __FILE__))
@@ -4,7 +4,7 @@ module IntegrationHelpers
4
4
  # @param session [ActionDispatch::Integration::Session]
5
5
  # @return [void]
6
6
  # @note accounts for differences in the integration test API between rails versions
7
- def sign_in(user, session)
7
+ def sign_in(user, session = integration_session)
8
8
  if Rails.gem_version > Gem::Version.new('5.0')
9
9
  session.post new_user_session_path, params: {
10
10
  user: {
@@ -37,6 +37,12 @@ class PasswordComplexityValidatorTest < Minitest::Test
37
37
  assert(ModelWithPassword.new('aaa1').valid?)
38
38
  end
39
39
 
40
+ def test_enforces_digits
41
+ ModelWithPassword.validates :password, 'devise_security/password_complexity': { digits: 2 }
42
+ refute(ModelWithPassword.new('aaa1').valid?)
43
+ assert(ModelWithPassword.new('aa12').valid?)
44
+ end
45
+
40
46
  def test_enforces_lower
41
47
  ModelWithPassword.validates :password, 'devise_security/password_complexity': { lower: 1 }
42
48
  refute(ModelWithPassword.new('AAAA').valid?)
@@ -49,6 +55,12 @@ class PasswordComplexityValidatorTest < Minitest::Test
49
55
  assert(ModelWithPassword.new('aaa!').valid?)
50
56
  end
51
57
 
58
+ def test_enforces_symbols
59
+ ModelWithPassword.validates :password, 'devise_security/password_complexity': { symbols: 2 }
60
+ refute(ModelWithPassword.new('aaa!').valid?)
61
+ assert(ModelWithPassword.new('aa!?').valid?)
62
+ end
63
+
52
64
  def test_enforces_combination
53
65
  ModelWithPassword.validates :password, 'devise_security/password_complexity': { lower: 1, upper: 1, digit: 1, symbol: 1 }
54
66
  refute(ModelWithPassword.new('abcd').valid?)
@@ -19,9 +19,11 @@ SimpleCov.start do
19
19
  end
20
20
 
21
21
  if ENV['CI']
22
- require 'coveralls'
23
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
24
- Coveralls.wear!
22
+ require 'simplecov'
23
+ require 'simplecov-lcov'
24
+ SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
25
+ SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
26
+ SimpleCov.start
25
27
  end
26
28
 
27
29
  require 'pry'
@@ -31,6 +33,11 @@ require 'rails/test_help'
31
33
  require 'devise-security'
32
34
  require 'database_cleaner'
33
35
  require "orm/#{DEVISE_ORM}"
36
+
37
+ if Rails.gem_version >= Gem::Version.new('5.0.0')
38
+ require 'rails-controller-testing'
39
+ Rails::Controller::Testing.install
40
+ end
34
41
  require 'support/integration_helpers'
35
42
 
36
43
  class Minitest::Test
@@ -12,12 +12,22 @@ class TestInstallGenerator < Rails::Generators::TestCase
12
12
  test 'Assert all files are properly created' do
13
13
  run_generator
14
14
  assert_file 'config/initializers/devise-security.rb'
15
+ assert_file 'config/locales/devise.security_extension.by.yml'
16
+ assert_file 'config/locales/devise.security_extension.cs.yml'
15
17
  assert_file 'config/locales/devise.security_extension.de.yml'
16
18
  assert_file 'config/locales/devise.security_extension.en.yml'
17
19
  assert_file 'config/locales/devise.security_extension.es.yml'
20
+ assert_file 'config/locales/devise.security_extension.fa.yml'
18
21
  assert_file 'config/locales/devise.security_extension.fr.yml'
22
+ assert_file 'config/locales/devise.security_extension.hi.yml'
19
23
  assert_file 'config/locales/devise.security_extension.it.yml'
20
24
  assert_file 'config/locales/devise.security_extension.ja.yml'
25
+ assert_file 'config/locales/devise.security_extension.nl.yml'
26
+ assert_file 'config/locales/devise.security_extension.pt.yml'
27
+ assert_file 'config/locales/devise.security_extension.ru.yml'
21
28
  assert_file 'config/locales/devise.security_extension.tr.yml'
29
+ assert_file 'config/locales/devise.security_extension.uk.yml'
30
+ assert_file 'config/locales/devise.security_extension.zh_CN.yml'
31
+ assert_file 'config/locales/devise.security_extension.zh_TW.yml'
22
32
  end
23
33
  end
@@ -1,7 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestSessionLimitable < ActiveSupport::TestCase
6
+ class ModifiedUser < User
7
+ def skip_session_limitable?
8
+ true
9
+ end
10
+ end
4
11
 
12
+ test 'check is not skipped by default' do
13
+ user = User.create email: 'bob@microsoft.com', password: 'password1', password_confirmation: 'password1'
14
+ assert_equal(false, user.skip_session_limitable?)
15
+ end
16
+
17
+ test 'default check can be overridden by record instance' do
18
+ modified_user = ModifiedUser.create email: 'bob2@microsoft.com', password: 'password1', password_confirmation: 'password1'
19
+ assert_equal(true, modified_user.skip_session_limitable?)
20
+ end
21
+
5
22
  class SessionLimitableUser < User
6
23
  devise :session_limitable
7
24
  include ::Mongoid::Mappings if DEVISE_ORM == :mongoid
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ Devise.setup do |config|
4
+ # ==> Security Extension
5
+ # Configure security extension for devise
6
+
7
+ # Should the password expire (e.g 3.months)
8
+ # config.expire_password_after = false
9
+
10
+ # Need 1 char of A-Z, a-z and 0-9
11
+ # config.password_complexity = { digit: 1, lower: 1, symbol: 1, upper: 1 }
12
+
13
+ # How many passwords to keep in archive
14
+ # config.password_archiving_count = 5
15
+
16
+ # Deny old passwords (true, false, number_of_old_passwords_to_check)
17
+ # Examples:
18
+ # config.deny_old_passwords = false # allow old passwords
19
+ # config.deny_old_passwords = true # will deny all the old passwords
20
+ # config.deny_old_passwords = 3 # will deny new passwords that matches with the last 3 passwords
21
+ # config.deny_old_passwords = true
22
+
23
+ # enable email validation for :secure_validatable. (true, false, validation_options)
24
+ # dependency: see https://github.com/devise-security/devise-security/blob/master/README.md#e-mail-validation
25
+ # config.email_validation = true
26
+
27
+ # captcha integration for recover form
28
+ # config.captcha_for_recover = true
29
+
30
+ # captcha integration for sign up form
31
+ # config.captcha_for_sign_up = true
32
+
33
+ # captcha integration for sign in form
34
+ # config.captcha_for_sign_in = true
35
+
36
+ # captcha integration for unlock form
37
+ # config.captcha_for_unlock = true
38
+
39
+ # captcha integration for confirmation form
40
+ # config.captcha_for_confirmation = true
41
+
42
+ # Time period for account expiry from last_activity_at
43
+ # config.expire_after = 90.days
44
+ end
@@ -0,0 +1,38 @@
1
+ de:
2
+ errors:
3
+ messages:
4
+ taken_in_past: 'wurde bereits in der Vergangenheit verwendet.'
5
+ equal_to_current_password: 'darf nicht dem aktuellen Passwort entsprechen.'
6
+ password_complexity:
7
+ digit:
8
+ one: muss mindestens eine Ziffer enthalten
9
+ other: muss mindestens %{count} Ziffern enthalten
10
+ lower:
11
+ one: muss mindestens einen Kleinbuchstaben enthalten
12
+ other: muss mindestens %{count} Kleinbuchstaben enthalten
13
+ symbol:
14
+ one: muss mindestens ein Sonderzeichen enthalten
15
+ other: muss mindestens %{count} Sonderzeichen enthalten
16
+ upper:
17
+ one: muss mindestens einen Großbuchstaben enthalten
18
+ other: muss mindestens %{count} Großbuchstaben enthalten
19
+ devise:
20
+ invalid_captcha: 'Die Captcha-Eingabe ist nicht gültig.'
21
+ paranoid_verify:
22
+ code_required: 'Bitte geben Sie den Code ein, den unser Support-Team zur Verfügung gestellt hat.'
23
+ show:
24
+ submit_verification_code: Bestätigungscode eingeben
25
+ verification_code: Bestätigungscode
26
+ submit: Bestätigen
27
+ password_expired:
28
+ updated: 'Das neue Passwort wurde übernommen.'
29
+ change_required: 'Ihr Passwort ist abgelaufen. Bitte vergeben Sie ein neues Passwort.'
30
+ show:
31
+ renew_your_password: Vergeben Sie ein neues Passwort
32
+ current_password: Aktuelles Passwort
33
+ new_password: Neues Passwort
34
+ new_password_confirmation: Passwort bestätigen
35
+ change_my_password: Passwort ändern
36
+ failure:
37
+ session_limited: 'Ihre Anmeldedaten wurden in einem anderen Browser genutzt. Bitte melden Sie sich erneut an, um in diesem Browser fortzufahren.'
38
+ expired: 'Ihr Account ist aufgrund zu langer Inaktivität abgelaufen. Bitte kontaktieren Sie den Administrator.'
@@ -0,0 +1,40 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ taken_in_past: 'was used previously.'
5
+ equal_to_current_password: 'must be different than the current password.'
6
+ password_complexity:
7
+ digit:
8
+ one: must contain at least one digit
9
+ other: must contain at least %{count} numerals
10
+ lower:
11
+ one: must contain at least one lower-case letter
12
+ other: must contain at least %{count} lower-case letters
13
+ symbol:
14
+ one: must contain at least one punctuation mark or symbol
15
+ other: must contain at least %{count} punctuation marks or symbols
16
+ upper:
17
+ one: must contain at least one upper-case letter
18
+ other: must contain at least %{count} upper-case letters
19
+ devise:
20
+ invalid_captcha: 'The captcha input was invalid.'
21
+ invalid_security_question: 'The security question answer was invalid.'
22
+ paranoid_verify:
23
+ code_required: 'Please enter the code our support team provided'
24
+ paranoid_verification_code:
25
+ show:
26
+ submit_verification_code: Submit verification code
27
+ verification_code: Verification code
28
+ submit: Submit
29
+ password_expired:
30
+ updated: 'Your new password is saved.'
31
+ change_required: 'Your password is expired. Please renew your password.'
32
+ show:
33
+ renew_your_password: Renew your password
34
+ current_password: Current password
35
+ new_password: New password
36
+ new_password_confirmation: Confirm new password
37
+ change_my_password: Change my password
38
+ failure:
39
+ session_limited: 'Your login credentials were used in another browser. Please sign in again to continue in this browser.'
40
+ expired: 'Your account has expired due to inactivity. Please contact the site administrator.'
@@ -0,0 +1,29 @@
1
+ es:
2
+ errors:
3
+ messages:
4
+ taken_in_past: 'la contraseña fue usada previamente, favor elegir otra.'
5
+ equal_to_current_password: 'tiene que ser diferente a la contraseña actual.'
6
+ password_complexity:
7
+ digit:
8
+ one: tiene que contener al menos un digito
9
+ other: tiene que contener al menos %{count} digitos
10
+ lower:
11
+ one: tiene que contener al menos un minúscula
12
+ other: tiene que contener al menos %{count} minúsculas
13
+ symbol:
14
+ one: tiene que contener al menos un signo de puntuación
15
+ other: tiene que contener al menos %{count} signos de puntuación
16
+ upper:
17
+ one: tiene que contener al menos un mayúscula
18
+ other: tiene que contener al menos %{count} mayúsculas
19
+ devise:
20
+ invalid_captcha: 'El captcha ingresado es inválido.'
21
+ invalid_security_question: 'La respuesta a la pregunta de suguridad fue incorrecta.'
22
+ paranoid_verify:
23
+ code_required: 'Por favor ingrese el código provisto por nuestro equipo de soporte'
24
+ password_expired:
25
+ updated: 'Su nueva contraña ha sido guardada.'
26
+ change_required: 'Su contraña ha expirado. Por favor renueve su contraseña.'
27
+ failure:
28
+ session_limited: 'Sus credenciales de inicio de sesión fueron usadas en otro navegador. Por favor inicie sesión nuevamente para continuar en éste navegador.'
29
+ expired: 'Su cuenta ha expirado debido a inactividad. Por favor contacte al administrador de la aplicación.'
@@ -0,0 +1,40 @@
1
+ fa:
2
+ errors:
3
+ messages:
4
+ taken_in_past: 'قبلا استفاده شده است'
5
+ equal_to_current_password: 'باید متفاوت با رمز عبور فعلی باشد'
6
+ password_complexity:
7
+ digit:
8
+ one: باید حداقل یک رقم داشته باشد
9
+ other: باید حداقل %{count} عدد داشته باشد
10
+ lower:
11
+ one: باید حداقل شامل یک حرف کوچک باشد
12
+ other: باید حداقل %{count} حروف کوچک داشته باشد
13
+ symbol:
14
+ one: باید حداقل دارای یک علامت یا کارکتر خاص باشد
15
+ other: باید حداقل دارای %{count} علائم یا کارکتر های خاص باشد
16
+ upper:
17
+ one: باید حداقل یک حرف بزرگ داشته باشد
18
+ other: باید حداقل %{count} حروف بزرگ داشته باشد
19
+ devise:
20
+ invalid_captcha: 'اطلاعات وارد شده در کپچا نامعتبر بود'
21
+ invalid_security_question: 'پاسخ سوال امنیتی نامعتبر بود'
22
+ paranoid_verify:
23
+ code_required: 'لطفاً کدی را که تیم پشتیبانی ما ارائه کرده است وارد کنید'
24
+ paranoid_verification_code:
25
+ show:
26
+ submit_verification_code: ارسال کد تاییدیه
27
+ verification_code: کد تاییدیه
28
+ submit: ارسال
29
+ password_expired:
30
+ updated: 'رمز جدید شما ذخیره شده است'
31
+ change_required: 'رمز عبور شما منقضی شده است ،لطفاً رمز خود را تمدید کنید'
32
+ show:
33
+ renew_your_password: ساختن رمز عبور جدید
34
+ current_password: رمز عبور جاری
35
+ new_password: رمز عبور جدید
36
+ new_password_confirmation: تکرار رمز جدید
37
+ change_my_password: تغییر رمز عبور
38
+ failure:
39
+ session_limited: 'از اطلاعات ورود شما در مرورگر دیگری استفاده شده است، برای ادامه در این مرورگر لطفاً دوباره وارد سیستم شوید'
40
+ expired: 'حساب شما به دلیل عدم فعالیت منقضی شده است، لطفاً با مدیر سایت تماس بگیرید.'
@@ -0,0 +1,29 @@
1
+ fr:
2
+ errors:
3
+ messages:
4
+ taken_in_past: a été utilisé trop récemment. Veuillez en choisir un autre
5
+ equal_to_current_password: doit être différent de l'actuel
6
+ password_complexity:
7
+ digit:
8
+ one: doit contenir au moins un chiffre
9
+ other: doit contenir au moins %{count} chiffres
10
+ lower:
11
+ one: doit contenir au moins une lettre miniscule
12
+ other: doit contenir au moins %{count} lettres miniscules
13
+ symbol:
14
+ one: doit contenir au moins un signe de ponctuation
15
+ other: doit contenir au moins %{count} signes de ponctuation
16
+ upper:
17
+ one: doit contenir au moins une lettre majuscule
18
+ other: doit contenir au moins %{count} lettres majuscules
19
+ devise:
20
+ invalid_captcha: Le captcha n'est pas valide
21
+ invalid_security_question: La réponse à la question de sécurité est invalide
22
+ paranoid_verify:
23
+ code_required: Veuillez entrer le code fourni par notre équipe de support
24
+ password_expired:
25
+ updated: Votre nouveau mot de passe est enregistré
26
+ change_required: Votre mot de passe a expiré. Veuillez en choisir un autre
27
+ failure:
28
+ session_limited: Vos identifiants de connexion ont été utilisés dans un autre navigateur. Veuillez vous reconnecter pour continuer dans ce navigateur
29
+ expired: Votre compte a expiré pour cause d'inactivité. Veuillez contacter l'administrateur du site
@@ -0,0 +1,40 @@
1
+ it:
2
+ errors:
3
+ messages:
4
+ taken_in_past: "è stata gia' utilizzata in passato!"
5
+ equal_to_current_password: " deve essere differente dalla password corrente!"
6
+ password_complexity:
7
+ digit:
8
+ one: deve contenere almeno una cifra
9
+ other: deve contenere almeno %{count} cifre
10
+ lower:
11
+ one: deve contenere almeno una lettera minuscola
12
+ other: deve contenere almeno %{count} lettere minuscole
13
+ symbol:
14
+ one: deve contenere almeno un simbolo di punteggiatura o un simbolo speciale
15
+ other: deve contenere almeno %{count} tra simboli di punteggiatura e simboli speciali
16
+ upper:
17
+ one: deve contenere almeno una lettera maiuscola
18
+ other: deve contenere almeno %{count} lettere maiuscole
19
+ devise:
20
+ invalid_captcha: "Il captcha inserito non è valido!"
21
+ invalid_security_question: 'La risposta alla domanda di sicurezza non è valida.'
22
+ paranoid_verify:
23
+ code_required: 'Inserisci il codice fornito dal nostro team di supporto'
24
+ paranoid_verification_code:
25
+ show:
26
+ submit_verification_code: Invia codice di verifica
27
+ verification_code: Codice di verifica
28
+ submit: Invia
29
+ password_expired:
30
+ updated: "La tua nuova password è stata salvata."
31
+ change_required: "La tua password è scaduta. Si prega di rinnovarla!"
32
+ show:
33
+ renew_your_password: Rinnova la tua password
34
+ current_password: Password attuale
35
+ new_password: Nuova password
36
+ new_password_confirmation: Conferma nuova password
37
+ change_my_password: Cambia la mia password
38
+ failure:
39
+ session_limited: "Hai effettuato l accesso in un altro browser. Fai nuovamente l accesso per connetterti in questo."
40
+ expired: 'Il tuo account è stato bloccato per inattività. Contatta l amministratore del sito.'