active_authentication 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +120 -0
- data/Rakefile +8 -0
- data/app/controllers/active_authentication/confirmations_controller.rb +29 -0
- data/app/controllers/active_authentication/passwords_controller.rb +37 -0
- data/app/controllers/active_authentication/registrations_controller.rb +42 -0
- data/app/controllers/active_authentication/sessions_controller.rb +36 -0
- data/app/controllers/active_authentication/unlocks_controller.rb +29 -0
- data/app/mailers/active_authentication/mailer.rb +21 -0
- data/app/views/active_authentication/confirmations/new.html.erb +14 -0
- data/app/views/active_authentication/mailer/email_confirmation_instructions.html.erb +5 -0
- data/app/views/active_authentication/mailer/password_reset_instructions.html.erb +5 -0
- data/app/views/active_authentication/mailer/unlock_instructions.html.erb +5 -0
- data/app/views/active_authentication/passwords/edit.html.erb +28 -0
- data/app/views/active_authentication/passwords/new.html.erb +14 -0
- data/app/views/active_authentication/registrations/edit.html.erb +42 -0
- data/app/views/active_authentication/registrations/new.html.erb +35 -0
- data/app/views/active_authentication/sessions/new.html.erb +19 -0
- data/app/views/active_authentication/shared/_links.html.erb +19 -0
- data/app/views/active_authentication/unlocks/new.html.erb +14 -0
- data/config/i18n-tasks.yml +159 -0
- data/config/locales/en.yml +90 -0
- data/config/locales/es.yml +90 -0
- data/lib/active_authentication/controller/lockable.rb +31 -0
- data/lib/active_authentication/controller/trackable.rb +17 -0
- data/lib/active_authentication/controller.rb +48 -0
- data/lib/active_authentication/current.rb +5 -0
- data/lib/active_authentication/engine.rb +16 -0
- data/lib/active_authentication/model/authenticatable.rb +16 -0
- data/lib/active_authentication/model/confirmable.rb +54 -0
- data/lib/active_authentication/model/lockable.rb +42 -0
- data/lib/active_authentication/model/recoverable.rb +16 -0
- data/lib/active_authentication/model/registerable.rb +7 -0
- data/lib/active_authentication/model/trackable.rb +23 -0
- data/lib/active_authentication/model.rb +21 -0
- data/lib/active_authentication/routes.rb +34 -0
- data/lib/active_authentication/test/helpers.rb +13 -0
- data/lib/active_authentication/version.rb +3 -0
- data/lib/active_authentication.rb +42 -0
- data/lib/generators/active_authentication/install/install_generator.rb +53 -0
- data/lib/generators/active_authentication/install/templates/initializer.rb +14 -0
- data/lib/generators/active_authentication/install/templates/migration.rb +26 -0
- data/lib/generators/active_authentication/views/views_generator.rb +17 -0
- metadata +116 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# i18n-tasks finds and manages missing and unused translations: https://github.com/glebm/i18n-tasks
|
2
|
+
|
3
|
+
# The "main" locale.
|
4
|
+
base_locale: en
|
5
|
+
## All available locales are inferred from the data by default. Alternatively, specify them explicitly:
|
6
|
+
# locales: [es, fr]
|
7
|
+
## Reporting locale, default: en. Available: en, ru.
|
8
|
+
# internal_locale: en
|
9
|
+
|
10
|
+
# Read and write translations.
|
11
|
+
data:
|
12
|
+
## Translations are read from the file system. Supported format: YAML, JSON.
|
13
|
+
## Provide a custom adapter:
|
14
|
+
# adapter: I18n::Tasks::Data::FileSystem
|
15
|
+
|
16
|
+
# Locale files or `Find.find` patterns where translations are read from:
|
17
|
+
read:
|
18
|
+
## Default:
|
19
|
+
# - config/locales/%{locale}.yml
|
20
|
+
## More files:
|
21
|
+
# - config/locales/**/*.%{locale}.yml
|
22
|
+
|
23
|
+
# Locale files to write new keys to, based on a list of key pattern => file rules. Matched from top to bottom:
|
24
|
+
# `i18n-tasks normalize -p` will force move the keys according to these rules
|
25
|
+
write:
|
26
|
+
## For example, write devise and simple form keys to their respective files:
|
27
|
+
# - ['{devise, simple_form}.*', 'config/locales/\1.%{locale}.yml']
|
28
|
+
## Catch-all default:
|
29
|
+
# - config/locales/%{locale}.yml
|
30
|
+
|
31
|
+
# External locale data (e.g. gems).
|
32
|
+
# This data is not considered unused and is never written to.
|
33
|
+
external:
|
34
|
+
## Example (replace %#= with %=):
|
35
|
+
# - "<%#= %x[bundle info vagrant --path].chomp %>/templates/locales/%{locale}.yml"
|
36
|
+
|
37
|
+
## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, or a custom class.
|
38
|
+
# router: conservative_router
|
39
|
+
|
40
|
+
yaml:
|
41
|
+
write:
|
42
|
+
# do not wrap lines at 80 characters
|
43
|
+
line_width: -1
|
44
|
+
|
45
|
+
## Pretty-print JSON:
|
46
|
+
# json:
|
47
|
+
# write:
|
48
|
+
# indent: ' '
|
49
|
+
# space: ' '
|
50
|
+
# object_nl: "\n"
|
51
|
+
# array_nl: "\n"
|
52
|
+
|
53
|
+
# Find translate calls
|
54
|
+
search:
|
55
|
+
## Paths or `Find.find` patterns to search in:
|
56
|
+
# paths:
|
57
|
+
# - app/
|
58
|
+
|
59
|
+
## Root directories for relative keys resolution.
|
60
|
+
# relative_roots:
|
61
|
+
# - app/controllers
|
62
|
+
# - app/helpers
|
63
|
+
# - app/mailers
|
64
|
+
# - app/presenters
|
65
|
+
# - app/views
|
66
|
+
|
67
|
+
## Directories where method names which should not be part of a relative key resolution.
|
68
|
+
# By default, if a relative translation is used inside a method, the name of the method will be considered part of the resolved key.
|
69
|
+
# Directories listed here will not consider the name of the method part of the resolved key
|
70
|
+
#
|
71
|
+
# relative_exclude_method_name_paths:
|
72
|
+
# -
|
73
|
+
|
74
|
+
## Files or `File.fnmatch` patterns to exclude from search. Some files are always excluded regardless of this setting:
|
75
|
+
## *.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less
|
76
|
+
## *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus *.webp *.map *.xlsx
|
77
|
+
exclude:
|
78
|
+
- app/assets/images
|
79
|
+
- app/assets/fonts
|
80
|
+
- app/assets/videos
|
81
|
+
- app/assets/builds
|
82
|
+
|
83
|
+
## Alternatively, the only files or `File.fnmatch patterns` to search in `paths`:
|
84
|
+
## If specified, this settings takes priority over `exclude`, but `exclude` still applies.
|
85
|
+
# only: ["*.rb", "*.html.slim"]
|
86
|
+
|
87
|
+
## If `strict` is `false`, guess usages such as t("categories.#{category}.title"). The default is `true`.
|
88
|
+
# strict: true
|
89
|
+
|
90
|
+
## Allows adding ast_matchers for finding translations using the AST-scanners
|
91
|
+
## The available matchers are:
|
92
|
+
## - RailsModelMatcher
|
93
|
+
## Matches ActiveRecord translations like
|
94
|
+
## User.human_attribute_name(:email) and User.model_name.human
|
95
|
+
##
|
96
|
+
## To implement your own, please see `I18n::Tasks::Scanners::AstMatchers::BaseMatcher`.
|
97
|
+
# <%# I18n::Tasks.add_ast_matcher('I18n::Tasks::Scanners::AstMatchers::RailsModelMatcher') %>
|
98
|
+
|
99
|
+
## Multiple scanners can be used. Their results are merged.
|
100
|
+
## The options specified above are passed down to each scanner. Per-scanner options can be specified as well.
|
101
|
+
## See this example of a custom scanner: https://github.com/glebm/i18n-tasks/wiki/A-custom-scanner-example
|
102
|
+
|
103
|
+
## Translation Services
|
104
|
+
# translation:
|
105
|
+
# # Google Translate
|
106
|
+
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
|
107
|
+
# google_translate_api_key: "AbC-dEf5"
|
108
|
+
# # DeepL Pro Translate
|
109
|
+
# # Get an API key and subscription at https://www.deepl.com/pro to use DeepL Pro
|
110
|
+
# deepl_api_key: "48E92789-57A3-466A-9959-1A1A1A1A1A1A"
|
111
|
+
# # deepl_host: "https://api.deepl.com"
|
112
|
+
# # deepl_version: "v2"
|
113
|
+
# # add additional options to the DeepL.translate call: https://www.deepl.com/docs-api/translate-text/translate-text/
|
114
|
+
# deepl_options:
|
115
|
+
# formality: prefer_less
|
116
|
+
## Do not consider these keys missing:
|
117
|
+
# ignore_missing:
|
118
|
+
# - 'errors.messages.{accepted,blank,invalid,too_short,too_long}'
|
119
|
+
# - '{devise,simple_form}.*'
|
120
|
+
|
121
|
+
## Consider these keys used:
|
122
|
+
# ignore_unused:
|
123
|
+
# - 'activerecord.attributes.*'
|
124
|
+
# - '{devise,kaminari,will_paginate}.*'
|
125
|
+
# - 'simple_form.{yes,no}'
|
126
|
+
# - 'simple_form.{placeholders,hints,labels}.*'
|
127
|
+
# - 'simple_form.{error_notification,required}.:'
|
128
|
+
ignore_unused:
|
129
|
+
- activerecord.attributes.*
|
130
|
+
- active_authentication.failure.*
|
131
|
+
- active_authentication.mailer.*.subject
|
132
|
+
|
133
|
+
## Exclude these keys from the `i18n-tasks eq-base' report:
|
134
|
+
# ignore_eq_base:
|
135
|
+
# all:
|
136
|
+
# - common.ok
|
137
|
+
# fr,es:
|
138
|
+
# - common.brand
|
139
|
+
|
140
|
+
## Exclude these keys from the `i18n-tasks check-consistent-interpolations` report:
|
141
|
+
# ignore_inconsistent_interpolations:
|
142
|
+
# - 'activerecord.attributes.*'
|
143
|
+
|
144
|
+
## Ignore these keys completely:
|
145
|
+
# ignore:
|
146
|
+
# - kaminari.*
|
147
|
+
|
148
|
+
## Sometimes, it isn't possible for i18n-tasks to match the key correctly,
|
149
|
+
## e.g. in case of a relative key defined in a helper method.
|
150
|
+
## In these cases you can use the built-in PatternMapper to map patterns to keys, e.g.:
|
151
|
+
#
|
152
|
+
# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper',
|
153
|
+
# only: %w(*.html.haml *.html.slim),
|
154
|
+
# patterns: [['= title\b', '.page_title']] %>
|
155
|
+
#
|
156
|
+
# The PatternMapper can also match key literals via a special %{key} interpolation, e.g.:
|
157
|
+
#
|
158
|
+
# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper',
|
159
|
+
# patterns: [['\bSpree\.t[( ]\s*%{key}', 'spree.%{key}']] %>
|
@@ -0,0 +1,90 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
active_authentication:
|
4
|
+
confirmations:
|
5
|
+
create:
|
6
|
+
success: Email confirmation instructions will be sent to your email.
|
7
|
+
new:
|
8
|
+
email_confirmation_instructions: Send email confirmation instructions
|
9
|
+
set_user:
|
10
|
+
invalid_token: Email confirmation token is invalid.
|
11
|
+
show:
|
12
|
+
success: Your email has been successfully confirmed.
|
13
|
+
failure:
|
14
|
+
already_signed_in: You are already signed in.
|
15
|
+
form_errors: "%{errors} prohibited this user from being saved:"
|
16
|
+
locked: Your account has been locked after %{count} failed attempts. Unlock instructions will be sent to your email.
|
17
|
+
unauthenticated: You need to sign in or sign up before continuing.
|
18
|
+
mailer:
|
19
|
+
email_confirmation_instructions:
|
20
|
+
confirm_email: Confirm my account
|
21
|
+
confirm_email_below: 'You can confirm your account email by clicking the link below:'
|
22
|
+
hello: Hello, %{email}!
|
23
|
+
subject: Confirmation instructions
|
24
|
+
password_reset_instructions:
|
25
|
+
hello: Hello, %{email}!
|
26
|
+
reset_password: Reset your password
|
27
|
+
reset_password_below: 'You can reset your password by clicking the link below:'
|
28
|
+
subject: Password reset instructions
|
29
|
+
unlock_instructions:
|
30
|
+
hello: Hello, %{email}!
|
31
|
+
subject: Unlock instructions
|
32
|
+
unlock: Unlock your account
|
33
|
+
unlock_below: 'You can unlock your account by clicking the link below:'
|
34
|
+
passwords:
|
35
|
+
create:
|
36
|
+
success: Password reset instructions will be sent to your email.
|
37
|
+
edit:
|
38
|
+
set_new_password: Set new password
|
39
|
+
new:
|
40
|
+
reset_password_instructions: Send reset password instructions
|
41
|
+
set_user:
|
42
|
+
invalid_token: Password reset token is invalid.
|
43
|
+
update:
|
44
|
+
success: Your password has been successfully updated.
|
45
|
+
registrations:
|
46
|
+
create:
|
47
|
+
success: You have signed up successfully.
|
48
|
+
destroy:
|
49
|
+
success: Your account has been successfully cancelled.
|
50
|
+
edit:
|
51
|
+
cancel_account: Cancel account
|
52
|
+
confirm: Are you sure?
|
53
|
+
danger_zone: Danger zone
|
54
|
+
edit_profile: Edit profile
|
55
|
+
pending_confirmation: 'You need to confirm your new email address: %{unconfirmed_email}'
|
56
|
+
save: Save
|
57
|
+
new:
|
58
|
+
sign_up: Sign up
|
59
|
+
update:
|
60
|
+
success: Your account has been successfully updated.
|
61
|
+
sessions:
|
62
|
+
create:
|
63
|
+
invalid_email_or_password: Invalid email or password.
|
64
|
+
success: Signed in successfully.
|
65
|
+
destroy:
|
66
|
+
success: Signed out successfully.
|
67
|
+
new:
|
68
|
+
sign_in: Sign in
|
69
|
+
shared:
|
70
|
+
links:
|
71
|
+
reset_password: Reset password
|
72
|
+
send_email_confirmation_instructions: Didn't receive confirmation instructions?
|
73
|
+
send_unlock_instructions: Didn't receive unlock instructions?
|
74
|
+
sign_in: Sign in
|
75
|
+
sign_up: Sign up
|
76
|
+
unlocks:
|
77
|
+
create:
|
78
|
+
success: Unlock instructions will be sent to your email.
|
79
|
+
new:
|
80
|
+
unlock_instructions: Send unlock instructions
|
81
|
+
set_user:
|
82
|
+
invalid_token: Unlock token is invalid.
|
83
|
+
show:
|
84
|
+
success: Your account has been successfully unlocked.
|
85
|
+
activerecord:
|
86
|
+
attributes:
|
87
|
+
user:
|
88
|
+
email: Email
|
89
|
+
password: Password
|
90
|
+
password_confirmation: Password confirmation
|
@@ -0,0 +1,90 @@
|
|
1
|
+
---
|
2
|
+
es:
|
3
|
+
active_authentication:
|
4
|
+
confirmations:
|
5
|
+
create:
|
6
|
+
success: Te enviaremos un email con las instrucciones para confirmar tu cuenta.
|
7
|
+
new:
|
8
|
+
email_confirmation_instructions: Enviar instrucciones de confirmación
|
9
|
+
set_user:
|
10
|
+
invalid_token: El token es inválido.
|
11
|
+
show:
|
12
|
+
success: Tu cuenta fue confirmada exitosamente.
|
13
|
+
failure:
|
14
|
+
already_signed_in: Ya iniciaste sesión.
|
15
|
+
form_errors: "%{errors} no permitieron guardar este elemento:"
|
16
|
+
locked: Tu cuenta fue bloqueada después de %{count} intentos fallidos. Te enviaremos un email con las instrucciones de desbloqueo.
|
17
|
+
unauthenticated: Tenés que iniciar sesión antes de continuar.
|
18
|
+
mailer:
|
19
|
+
email_confirmation_instructions:
|
20
|
+
confirm_email: Confirmar mi cuenta
|
21
|
+
confirm_email_below: 'Podés confirmar tu cuenta haciendo click en el siguiente link:'
|
22
|
+
hello: Hola, %{email}!
|
23
|
+
subject: Instrucciones de confirmación
|
24
|
+
password_reset_instructions:
|
25
|
+
hello: Hola, %{email}!
|
26
|
+
reset_password: Recuperar contraseña
|
27
|
+
reset_password_below: 'Podés recuperar tu contraseña haciendo click en el siguiente link:'
|
28
|
+
subject: Instrucciones de recuperación de contraseña
|
29
|
+
unlock_instructions:
|
30
|
+
hello: Hola, %{email}!
|
31
|
+
subject: Instrucciones de desbloqueo
|
32
|
+
unlock: Desbloquear cuenta
|
33
|
+
unlock_below: 'Podés desbloquear tu contraseña haciendo click en el siguiente link:'
|
34
|
+
passwords:
|
35
|
+
create:
|
36
|
+
success: Te enviaremos un email con las instrucciones de para recuperar tu contraseña.
|
37
|
+
edit:
|
38
|
+
set_new_password: Cambiar contraseña
|
39
|
+
new:
|
40
|
+
reset_password_instructions: Enviar instrucciones para recuperar contraseña
|
41
|
+
set_user:
|
42
|
+
invalid_token: El token es inválido.
|
43
|
+
update:
|
44
|
+
success: Tu contraseña fue actualizada exitosamente.
|
45
|
+
registrations:
|
46
|
+
create:
|
47
|
+
success: Te registraste exitosamente.
|
48
|
+
destroy:
|
49
|
+
success: Tu cuenta fue cancelada exitosamente.
|
50
|
+
edit:
|
51
|
+
cancel_account: Cancelar cuenta
|
52
|
+
confirm: "¿Estás seguro?"
|
53
|
+
danger_zone: Zona de peligro
|
54
|
+
edit_profile: Editar perfil
|
55
|
+
pending_confirmation: 'Tenés que confirmar tu nuevo email: %{unconfirmed_email}'
|
56
|
+
save: Guardar
|
57
|
+
new:
|
58
|
+
sign_up: Crear una cuenta
|
59
|
+
update:
|
60
|
+
success: Tu cuenta fue actualizada exitosamente.
|
61
|
+
sessions:
|
62
|
+
create:
|
63
|
+
invalid_email_or_password: Email o contraseña inválidos.
|
64
|
+
success: Inicio de sesión existoso.
|
65
|
+
destroy:
|
66
|
+
success: Cierre de sesión exitoso.
|
67
|
+
new:
|
68
|
+
sign_in: Iniciar sesión
|
69
|
+
shared:
|
70
|
+
links:
|
71
|
+
reset_password: Recuperar contraseña
|
72
|
+
send_email_confirmation_instructions: "¿No recibiste las instrucciones de confirmación?"
|
73
|
+
send_unlock_instructions: "¿No recibiste las instrucciones de desbloqueo?"
|
74
|
+
sign_in: Iniciar sesión
|
75
|
+
sign_up: Crear una cuenta
|
76
|
+
unlocks:
|
77
|
+
create:
|
78
|
+
success: Te enviaremos un email con las instrucciones de desbloqueo.
|
79
|
+
new:
|
80
|
+
unlock_instructions: Enviar instrucciones de desbloqueo
|
81
|
+
set_user:
|
82
|
+
invalid_token: El token es inválido.
|
83
|
+
show:
|
84
|
+
success: Tu cuenta fue desbloqueada exitosamente.
|
85
|
+
activerecord:
|
86
|
+
attributes:
|
87
|
+
user:
|
88
|
+
email: Email
|
89
|
+
password: Contraseña
|
90
|
+
password_confirmation: Repetir contraseña
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Controller
|
3
|
+
module Lockable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
set_callback :failed_sign_in, :before, :increment_failed_attempts
|
8
|
+
set_callback :failed_sign_in, :after, :set_alert
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def increment_failed_attempts
|
13
|
+
user = User.find_by email: params[:email]
|
14
|
+
user&.increment_failed_attempts
|
15
|
+
end
|
16
|
+
|
17
|
+
def scope
|
18
|
+
User.unlocked
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_alert
|
22
|
+
user = User.find_by email: params[:email]
|
23
|
+
|
24
|
+
if user.locked?
|
25
|
+
flash[:alert] = t "active_authentication.failure.locked", count: user.failed_attempts
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Controller
|
3
|
+
module Trackable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
set_callback :successful_sign_in, :after, :track
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def track
|
12
|
+
current_user.track request
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Controller
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveSupport::Callbacks
|
5
|
+
|
6
|
+
included do
|
7
|
+
helper_method :current_user
|
8
|
+
helper_method :user_signed_in?
|
9
|
+
end
|
10
|
+
|
11
|
+
def authenticate_user!
|
12
|
+
redirect_to new_session_path, alert: t("active_authentication.failure.unauthenticated") unless user_signed_in?
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_user
|
16
|
+
Current.user ||= user_from_session
|
17
|
+
end
|
18
|
+
|
19
|
+
def require_no_authentication
|
20
|
+
redirect_to root_path, alert: t("active_authentication.failure.already_signed_in") if user_signed_in?
|
21
|
+
end
|
22
|
+
|
23
|
+
def sign_in(user)
|
24
|
+
reset_session
|
25
|
+
Current.user = user
|
26
|
+
session[:user_id] = user.id
|
27
|
+
end
|
28
|
+
|
29
|
+
def sign_out
|
30
|
+
reset_session
|
31
|
+
Current.user = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def user_signed_in?
|
35
|
+
current_user.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def scope
|
41
|
+
User
|
42
|
+
end
|
43
|
+
|
44
|
+
def user_from_session
|
45
|
+
User.find_by id: session[:user_id]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "active_authentication/controller"
|
2
|
+
require "active_authentication/model"
|
3
|
+
|
4
|
+
module ActiveAuthentication
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
initializer :active_authentication_controller do
|
7
|
+
ActiveSupport.on_load :action_controller_base do
|
8
|
+
include ActiveAuthentication::Controller
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveSupport.on_load :active_record do
|
12
|
+
include ActiveAuthentication::Model
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Authenticatable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_secure_password
|
8
|
+
|
9
|
+
normalizes :email, with: -> { _1.strip.downcase }
|
10
|
+
|
11
|
+
validates :email, format: {with: URI::MailTo::EMAIL_REGEXP}, presence: true, uniqueness: true
|
12
|
+
validates :password, length: {minimum: ActiveAuthentication.min_password_length}, allow_blank: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Confirmable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
generates_token_for :email_confirmation, expires_in: ActiveAuthentication.email_confirmation_token_expires_in
|
8
|
+
|
9
|
+
normalizes :unconfirmed_email, with: -> { _1.strip.downcase }
|
10
|
+
|
11
|
+
validates :unconfirmed_email, format: {with: URI::MailTo::EMAIL_REGEXP}, allow_blank: true
|
12
|
+
|
13
|
+
after_initialize do
|
14
|
+
@set_unconfirmed_email = true
|
15
|
+
@send_email_confirmation_instructions = true
|
16
|
+
end
|
17
|
+
|
18
|
+
before_update :set_unconfirmed_email, if: :set_unconfirmed_email?
|
19
|
+
after_save :send_email_confirmation_instructions, if: :send_email_confirmation_instructions?
|
20
|
+
end
|
21
|
+
|
22
|
+
def confirm
|
23
|
+
@send_email_confirmation_instructions = false
|
24
|
+
@set_unconfirmed_email = false
|
25
|
+
|
26
|
+
update email: unconfirmed_email, unconfirmed_email: nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def send_email_confirmation_instructions
|
30
|
+
token = generate_token_for :email_confirmation
|
31
|
+
ActiveAuthentication::Mailer.with(token: token, user: self).email_confirmation_instructions.deliver
|
32
|
+
end
|
33
|
+
|
34
|
+
def send_email_confirmation_instructions?
|
35
|
+
@send_email_confirmation_instructions && unconfirmed_email.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
def unconfirmed?
|
39
|
+
unconfirmed_email.present?
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def set_unconfirmed_email
|
45
|
+
self.unconfirmed_email = email
|
46
|
+
self.email = email_was
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_unconfirmed_email?
|
50
|
+
@set_unconfirmed_email && email_changed?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Lockable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
ActiveAuthentication::SessionsController.send :include, ActiveAuthentication::Controller::Lockable
|
8
|
+
|
9
|
+
generates_token_for :unlock, expires_in: ActiveAuthentication.unlock_token_expires_in
|
10
|
+
|
11
|
+
scope :unlocked, -> { where locked_at: nil }
|
12
|
+
end
|
13
|
+
|
14
|
+
def increment_failed_attempts
|
15
|
+
increment :failed_attempts
|
16
|
+
|
17
|
+
lock if failed_attempts == ActiveAuthentication.max_failed_attempts
|
18
|
+
|
19
|
+
save
|
20
|
+
end
|
21
|
+
|
22
|
+
def locked?
|
23
|
+
locked_at.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def lock
|
27
|
+
update locked_at: Time.now
|
28
|
+
|
29
|
+
send_unlock_instructions
|
30
|
+
end
|
31
|
+
|
32
|
+
def send_unlock_instructions
|
33
|
+
token = generate_token_for :unlock
|
34
|
+
ActiveAuthentication::Mailer.with(token: token, user: self).unlock_instructions.deliver
|
35
|
+
end
|
36
|
+
|
37
|
+
def unlock
|
38
|
+
update failed_attempts: 0, locked_at: nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Recoverable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
generates_token_for :password_reset, expires_in: ActiveAuthentication.password_reset_token_expires_in
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_password_reset_instructions
|
11
|
+
token = generate_token_for :password_reset
|
12
|
+
ActiveAuthentication::Mailer.with(token: token, user: self).password_reset_instructions.deliver
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Trackable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
ActiveAuthentication::SessionsController.send :include, ActiveAuthentication::Controller::Trackable
|
8
|
+
end
|
9
|
+
|
10
|
+
def track(request)
|
11
|
+
self.sign_in_count += 1
|
12
|
+
|
13
|
+
self.last_sign_in_at = current_sign_in_at
|
14
|
+
self.current_sign_in_at = Time.now
|
15
|
+
|
16
|
+
self.last_sign_in_ip = current_sign_in_ip
|
17
|
+
self.current_sign_in_ip = request.remote_ip
|
18
|
+
|
19
|
+
save
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
CONCERNS = %i[authenticatable confirmable lockable recoverable registerable trackable]
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def authenticates_with(*concerns)
|
9
|
+
include Authenticatable
|
10
|
+
concerns.each do |concern|
|
11
|
+
include const_get(concern.to_s.classify)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
alias_method :authenticates, :authenticates_with
|
15
|
+
|
16
|
+
CONCERNS.each do |concern|
|
17
|
+
define_method(:"#{concern}?") { User.included_modules.include? const_get(concern.to_s.classify) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
class Mapper
|
3
|
+
def active_authentication
|
4
|
+
scope module: :active_authentication do
|
5
|
+
ActiveAuthentication::Model::CONCERNS.each do |concern|
|
6
|
+
send(concern) if User.send(:"#{concern}?") && respond_to?(concern, true)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def authenticatable
|
14
|
+
resource :session, only: [:new, :create, :destroy]
|
15
|
+
end
|
16
|
+
|
17
|
+
def confirmable
|
18
|
+
resources :confirmations, param: :token, only: [:new, :create, :show]
|
19
|
+
end
|
20
|
+
|
21
|
+
def lockable
|
22
|
+
resources :unlocks, param: :token, only: [:new, :create, :show]
|
23
|
+
end
|
24
|
+
|
25
|
+
def registerable
|
26
|
+
resources :registrations, only: [:new, :create]
|
27
|
+
resource :profile, only: [:edit, :update, :destroy], path: :profile, controller: :registrations
|
28
|
+
end
|
29
|
+
|
30
|
+
def recoverable
|
31
|
+
resources :passwords, param: :token, only: [:new, :create, :edit, :update]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|