active_authentication 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +120 -0
  3. data/Rakefile +8 -0
  4. data/app/controllers/active_authentication/confirmations_controller.rb +29 -0
  5. data/app/controllers/active_authentication/passwords_controller.rb +37 -0
  6. data/app/controllers/active_authentication/registrations_controller.rb +42 -0
  7. data/app/controllers/active_authentication/sessions_controller.rb +36 -0
  8. data/app/controllers/active_authentication/unlocks_controller.rb +29 -0
  9. data/app/mailers/active_authentication/mailer.rb +21 -0
  10. data/app/views/active_authentication/confirmations/new.html.erb +14 -0
  11. data/app/views/active_authentication/mailer/email_confirmation_instructions.html.erb +5 -0
  12. data/app/views/active_authentication/mailer/password_reset_instructions.html.erb +5 -0
  13. data/app/views/active_authentication/mailer/unlock_instructions.html.erb +5 -0
  14. data/app/views/active_authentication/passwords/edit.html.erb +28 -0
  15. data/app/views/active_authentication/passwords/new.html.erb +14 -0
  16. data/app/views/active_authentication/registrations/edit.html.erb +42 -0
  17. data/app/views/active_authentication/registrations/new.html.erb +35 -0
  18. data/app/views/active_authentication/sessions/new.html.erb +19 -0
  19. data/app/views/active_authentication/shared/_links.html.erb +19 -0
  20. data/app/views/active_authentication/unlocks/new.html.erb +14 -0
  21. data/config/i18n-tasks.yml +159 -0
  22. data/config/locales/en.yml +90 -0
  23. data/config/locales/es.yml +90 -0
  24. data/lib/active_authentication/controller/lockable.rb +31 -0
  25. data/lib/active_authentication/controller/trackable.rb +17 -0
  26. data/lib/active_authentication/controller.rb +48 -0
  27. data/lib/active_authentication/current.rb +5 -0
  28. data/lib/active_authentication/engine.rb +16 -0
  29. data/lib/active_authentication/model/authenticatable.rb +16 -0
  30. data/lib/active_authentication/model/confirmable.rb +54 -0
  31. data/lib/active_authentication/model/lockable.rb +42 -0
  32. data/lib/active_authentication/model/recoverable.rb +16 -0
  33. data/lib/active_authentication/model/registerable.rb +7 -0
  34. data/lib/active_authentication/model/trackable.rb +23 -0
  35. data/lib/active_authentication/model.rb +21 -0
  36. data/lib/active_authentication/routes.rb +34 -0
  37. data/lib/active_authentication/test/helpers.rb +13 -0
  38. data/lib/active_authentication/version.rb +3 -0
  39. data/lib/active_authentication.rb +42 -0
  40. data/lib/generators/active_authentication/install/install_generator.rb +53 -0
  41. data/lib/generators/active_authentication/install/templates/initializer.rb +14 -0
  42. data/lib/generators/active_authentication/install/templates/migration.rb +26 -0
  43. data/lib/generators/active_authentication/views/views_generator.rb +17 -0
  44. 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,5 @@
1
+ module ActiveAuthentication
2
+ class Current < ActiveSupport::CurrentAttributes
3
+ attribute :user
4
+ end
5
+ 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,7 @@
1
+ module ActiveAuthentication
2
+ module Model
3
+ module Registerable
4
+ extend ActiveSupport::Concern
5
+ end
6
+ end
7
+ 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