|
|
@ -14,8 +14,6 @@ |
|
|
|
# sign_in_count :integer default(0), not null |
|
|
|
# current_sign_in_at :datetime |
|
|
|
# last_sign_in_at :datetime |
|
|
|
# current_sign_in_ip :inet |
|
|
|
# last_sign_in_ip :inet |
|
|
|
# admin :boolean default(FALSE), not null |
|
|
|
# confirmation_token :string |
|
|
|
# confirmed_at :datetime |
|
|
@ -81,6 +79,7 @@ class User < ApplicationRecord |
|
|
|
has_many :invites, inverse_of: :user |
|
|
|
has_many :markers, inverse_of: :user, dependent: :destroy |
|
|
|
has_many :webauthn_credentials, dependent: :destroy |
|
|
|
has_many :ips, class_name: 'UserIp', inverse_of: :user |
|
|
|
|
|
|
|
has_one :invite_request, class_name: 'UserInviteRequest', inverse_of: :user, dependent: :destroy |
|
|
|
accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text } |
|
|
@ -107,7 +106,7 @@ class User < ApplicationRecord |
|
|
|
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } |
|
|
|
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) } |
|
|
|
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) } |
|
|
|
scope :matches_ip, ->(value) { where('current_sign_in_ip <<= ?', value).or(where('users.sign_up_ip <<= ?', value)).or(where('users.last_sign_in_ip <<= ?'span>, value)).or(where(id: SessionActivation.select(:user_id).where('ip <<= ?', value))) } |
|
|
|
scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value) } |
|
|
|
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) } |
|
|
|
|
|
|
|
before_validation :sanitize_languages |
|
|
@ -174,15 +173,11 @@ class User < ApplicationRecord |
|
|
|
prepare_new_user! if new_user && approved? |
|
|
|
end |
|
|
|
|
|
|
|
def update_sign_in!(request, new_sign_in: false) |
|
|
|
def update_sign_in!(new_sign_in: false) |
|
|
|
old_current, new_current = current_sign_in_at, Time.now.utc |
|
|
|
self.last_sign_in_at = old_current || new_current |
|
|
|
self.current_sign_in_at = new_current |
|
|
|
|
|
|
|
old_current, new_current = current_sign_in_ip, request.remote_ip |
|
|
|
self.last_sign_in_ip = old_current || new_current |
|
|
|
self.current_sign_in_ip = new_current |
|
|
|
|
|
|
|
if new_sign_in |
|
|
|
self.sign_in_count ||= 0 |
|
|
|
self.sign_in_count += 1 |
|
|
@ -201,7 +196,7 @@ class User < ApplicationRecord |
|
|
|
end |
|
|
|
|
|
|
|
def suspicious_sign_in?(ip) |
|
|
|
!otp_required_for_login? && !skip_sign_in_token? && current_sign_in_at.present? && !recent_ip?(ip) |
|
|
|
!otp_required_for_login? && !skip_sign_in_token? && current_sign_in_at.present? && !ips.where(ip: ip).exists? |
|
|
|
end |
|
|
|
|
|
|
|
def functional? |
|
|
@ -277,31 +272,28 @@ class User < ApplicationRecord |
|
|
|
@shows_application ||= settings.show_application |
|
|
|
end |
|
|
|
|
|
|
|
# rubocop:disable Naming/MethodParameterName |
|
|
|
def token_for_app(a) |
|
|
|
return nil if a.nil? || a.owner != self |
|
|
|
Doorkeeper::AccessToken.find_or_create_by(application_id: a.id, resource_owner_id: id) do |t| |
|
|
|
t.scopes = a.scopes |
|
|
|
t.expires_in = Doorkeeper.configuration.access_token_expires_in |
|
|
|
def token_for_app(app) |
|
|
|
return nil if app.nil? || app.owner != self |
|
|
|
|
|
|
|
Doorkeeper::AccessToken.find_or_create_by(application_id: app.id, resource_owner_id: id) do |t| |
|
|
|
t.scopes = app.scopes |
|
|
|
t.expires_in = Doorkeeper.configuration.access_token_expires_in |
|
|
|
t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled? |
|
|
|
end |
|
|
|
end |
|
|
|
# rubocop:enable Naming/MethodParameterName |
|
|
|
|
|
|
|
def activate_session(request) |
|
|
|
session_activations.activate(session_id: SecureRandom.hex, |
|
|
|
user_agent: request.user_agent, |
|
|
|
ip: request.remote_ip).session_id |
|
|
|
session_activations.activate( |
|
|
|
session_id: SecureRandom.hex, |
|
|
|
user_agent: request.user_agent, |
|
|
|
ip: request.remote_ip |
|
|
|
).session_id |
|
|
|
end |
|
|
|
|
|
|
|
def clear_other_sessions(id) |
|
|
|
session_activations.exclusive(id) |
|
|
|
end |
|
|
|
|
|
|
|
def session_active?(id) |
|
|
|
session_activations.active? id |
|
|
|
end |
|
|
|
|
|
|
|
def web_push_subscription(session) |
|
|
|
session.web_push_subscription.nil? ? nil : session.web_push_subscription |
|
|
|
end |
|
|
@ -364,22 +356,6 @@ class User < ApplicationRecord |
|
|
|
setting_display_media == 'hide_all' |
|
|
|
end |
|
|
|
|
|
|
|
def recent_ips |
|
|
|
@recent_ips ||= begin |
|
|
|
arr = [] |
|
|
|
|
|
|
|
session_activations.each do |session_activation| |
|
|
|
arr << [session_activation.updated_at, session_activation.ip] |
|
|
|
end |
|
|
|
|
|
|
|
arr << [current_sign_in_at, current_sign_in_ip] if current_sign_in_ip.present? |
|
|
|
arr << [last_sign_in_at, last_sign_in_ip] if last_sign_in_ip.present? |
|
|
|
arr << [created_at, sign_up_ip] if sign_up_ip.present? |
|
|
|
|
|
|
|
arr.sort_by { |pair| pair.first || Time.now.utc }.uniq(&:last).reverse! |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
def sign_in_token_expired? |
|
|
|
sign_in_token_sent_at.nil? || sign_in_token_sent_at < 5.minutes.ago |
|
|
|
end |
|
|
@ -410,10 +386,6 @@ class User < ApplicationRecord |
|
|
|
|
|
|
|
private |
|
|
|
|
|
|
|
def recent_ip?(ip) |
|
|
|
recent_ips.any? { |(_, recent_ip)| recent_ip == ip } |
|
|
|
end |
|
|
|
|
|
|
|
def send_pending_devise_notifications |
|
|
|
pending_devise_notifications.each do |notification, args, kwargs| |
|
|
|
render_and_send_devise_message(notification, *args, **kwargs) |
|
|
|