Module: Sessions::HasSessions
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/sessions/models/concerns/has_sessions.rb
Overview
What ‘has_sessions` includes into the auth model. On Rails 8 omakase apps the generated `has_many :sessions, dependent: :destroy` already exists and is left alone; on Devise apps the association is declared here. Either way the model gains the events trail and the revocation verbs:
current_user.sessions.active
current_user.session_events.failed_logins.last_24_hours
current_user.revoke_other_sessions! # "sign out everywhere else"
current_user.revoke_all_sessions! # the account-takeover hammer
Plus the ASVS 3.3.3 default: changing the password revokes every other session (‘config.revoke_on_password_change`), detected on whichever digest column the auth stack uses (password_digest / encrypted_password).
Constant Summary collapse
- PASSWORD_COLUMNS =
%w[password_digest encrypted_password].freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#revoke_all_sessions!(by: nil, reason: :admin_revoked) ⇒ Object
The admin hammer — the account-takeover response.
-
#revoke_other_sessions!(current: nil, by: nil, reason: :logout_everywhere) ⇒ Object
GitHub’s “sign out everywhere else”: revoke every session except
current(defaulting to the one serving this request, so a controller can call it bare). -
#session_history ⇒ Object
The user’s COMPLETE trail slice — owned events PLUS the failed attempts typed against their email.
Class Method Details
.polymorphic_sessions? ⇒ Boolean
48 49 50 51 52 |
# File 'lib/sessions/models/concerns/has_sessions.rb', line 48 def self.polymorphic_sessions? Sessions.session_model.column_names.include?("user_type") rescue StandardError false end |
Instance Method Details
#revoke_all_sessions!(by: nil, reason: :admin_revoked) ⇒ Object
The admin hammer — the account-takeover response. Revokes EVERYTHING, including the session serving this request if it belongs to this user.
86 87 88 89 |
# File 'lib/sessions/models/concerns/has_sessions.rb', line 86 def revoke_all_sessions!(by: nil, reason: :admin_revoked) sessions.each { |session| session.revoke!(reason: reason, by: by) } true end |
#revoke_other_sessions!(current: nil, by: nil, reason: :logout_everywhere) ⇒ Object
GitHub’s “sign out everywhere else”: revoke every session except current (defaulting to the one serving this request, so a controller can call it bare). Each revocation writes its event and fires hooks.
75 76 77 78 79 80 81 82 |
# File 'lib/sessions/models/concerns/has_sessions.rb', line 75 def revoke_other_sessions!(current: nil, by: nil, reason: :logout_everywhere) current = Sessions.current if current.nil? scope = sessions scope = scope.where.not(id: current.id) if current.respond_to?(:id) scope.each { |session| session.revoke!(reason: reason, by: by || self) } true end |
#session_history ⇒ Object
The user’s COMPLETE trail slice — owned events PLUS the failed attempts typed against their email. Failures deliberately never link to accounts (‘session_events` alone can’t see them — recording a failure must not confirm an account exists); matching the resolved user’s own identity here is the safe read side. This is what the engine’s history page renders:
user.session_history.recent # everything, newest first
user.session_history.failed_logins # including identity-matched ones
63 64 65 66 67 68 69 70 |
# File 'lib/sessions/models/concerns/has_sessions.rb', line 63 def session_history scope = Sessions::Event.where(authenticatable: self) identity = Sessions::Event.normalize_identity(try(:email_address) || try(:email)) scope = scope.or(Sessions::Event.where(identity: identity)) if identity scope end |