|
|
|
@ -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 <<= ?', 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)
|
|
|
|
|