1 # frozen_string_literal: true
2 # == Schema Information
6 # id :bigint(8) not null, primary key
7 # email :string default(""), not null
8 # created_at :datetime not null
9 # updated_at :datetime not null
10 # encrypted_password :string default(""), not null
11 # reset_password_token :string
12 # reset_password_sent_at :datetime
13 # remember_created_at :datetime
14 # sign_in_count :integer default(0), not null
15 # current_sign_in_at :datetime
16 # last_sign_in_at :datetime
17 # current_sign_in_ip :inet
18 # last_sign_in_ip :inet
19 # admin :boolean default(FALSE), not null
20 # confirmation_token :string
21 # confirmed_at :datetime
22 # confirmation_sent_at :datetime
23 # unconfirmed_email :string
25 # encrypted_otp_secret :string
26 # encrypted_otp_secret_iv :string
27 # encrypted_otp_secret_salt :string
28 # consumed_timestep :integer
29 # otp_required_for_login :boolean default(FALSE), not null
30 # last_emailed_at :datetime
31 # otp_backup_codes :string is an Array
32 # filtered_languages :string default([]), not null, is an Array
33 # account_id :bigint(8) not null
34 # disabled :boolean default(FALSE), not null
35 # moderator :boolean default(FALSE), not null
36 # invite_id :bigint(8)
37 # remember_token :string
40 class User
< ApplicationRecord
41 include Settings
::Extend
44 ACTIVE_DURATION
= 14.days
46 devise
:two_factor_authenticatable,
47 otp_secret_encryption_key
: Rails
.configuration
.x
.otp_secret
49 devise
:two_factor_backupable,
50 otp_number_of_backup_codes
: 10
52 devise
:registerable, :recoverable, :rememberable, :trackable, :validatable,
55 devise
:pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
59 belongs_to
:account, inverse_of
: :user
60 belongs_to
:invite, counter_cache
: :uses, optional
: true
61 accepts_nested_attributes_for
:account
63 has_many
:applications, class_name
: 'Doorkeeper::Application', as
: :owner
64 has_many
:backups, inverse_of
: :user
66 validates
:locale, inclusion
: I18n
.available_locales
.map(&:to_s), if: :locale?
67 validates_with BlacklistedEmailValidator
, if: :email_changed?
69 scope
:recent, -> { order(id
: :desc) }
70 scope
:admins, -> { where(admin
: true) }
71 scope
:moderators, -> { where(moderator
: true) }
72 scope
:staff, -> { admins
.or(moderators
) }
73 scope
:confirmed, -> { where
.not(confirmed_at
: nil) }
74 scope
:inactive, -> { where(arel_table
[:current_sign_in_at].lt(ACTIVE_DURATION
.ago
)) }
75 scope
:active, -> { confirmed
.where(arel_table
[:current_sign_in_at].gteq(ACTIVE_DURATION
.ago
)).joins(:account).where(accounts
: { suspended
: false }) }
76 scope
:matches_email, ->(value
) { where(arel_table
[:email].matches("#{value}%")) }
77 scope
:with_recent_ip_address, ->(value
) { where(arel_table
[:current_sign_in_ip].eq(value
).or(arel_table
[:last_sign_in_ip].eq(value
))) }
79 before_validation
:sanitize_languages
81 # This avoids a deprecation warning from Rails 5.1
82 # It seems possible that a future release of devise-two-factor will
83 # handle this itself, and this can be removed from our User class.
86 has_many
:session_activations, dependent
: :destroy
88 delegate
:auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
89 :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_sensitive_media,
90 to
: :settings, prefix
: :setting, allow_nil
: false
92 attr_accessor
:invite_code
95 # block pam login tries on traditional account
100 return false unless Devise
.pam_authentication
101 encrypted_password
.present
? && pam_managed_user
?
105 return account
.username
if account
.present
?
109 def pam_setup(_attributes
)
110 acc
= Account
.new(username
: pam_get_name
)
111 acc
.save!
(validate
: false)
113 self.email
= "#{acc.username}@#{find_pam_suffix}" if email
.nil? && find_pam_suffix
114 self.confirmed_at
= Time
.now
.utc
118 acc
.destroy!
unless save
121 def ldap_setup(_attributes
)
122 self.confirmed_at
= Time
.now
.utc
128 confirmed_at
.present
?
159 update!
(disabled
: true,
160 last_sign_in_at
: current_sign_in_at
,
161 current_sign_in_at
: nil)
165 update!
(disabled
: false)
169 new_user
= !confirmed
?
172 prepare_new_user!
if new_user
176 new_user
= !confirmed
?
180 prepare_new_user!
if new_user
183 def update_tracked_fields!
(request
)
185 prepare_returning_user!
190 update!
(moderator
: false, admin
: true)
192 update!
(moderator
: true)
198 update!
(admin
: false, moderator
: true)
200 update!
(moderator
: false)
204 def disable_two_factor!
205 self.otp_required_for_login
= false
206 otp_backup_codes
&.clear
210 def active_for_authentication
?
214 def setting_default_privacy
215 settings
.default_privacy
|| (account
.locked
? ? 'private' : 'public')
218 def allows_digest_emails
?
219 settings
.notification_emails
['digest']
223 return nil if a
.nil? || a
.owner !
= self
224 Doorkeeper
::AccessToken
225 .find_or_create_by(application_id
: a
.id
, resource_owner_id
: id
) do |t
|
228 t
.expires_in
= Doorkeeper
.configuration
.access_token_expires_in
229 t
.use_refresh_token
= Doorkeeper
.configuration
.refresh_token_enabled
?
233 def activate_session(request
)
234 session_activations
.activate(session_id
: SecureRandom
.hex
,
235 user_agent
: request
.user_agent
,
236 ip
: request
.remote_ip
).session_id
239 def exclusive_session(id
)
240 session_activations
.exclusive(id
)
243 def session_active
?(id
)
244 session_activations
.active
? id
247 def web_push_subscription(session
)
248 session
.web_push_subscription
.nil? ? nil : session
.web_push_subscription
.as_payload
251 def invite_code
=(code
)
252 self.invite
= Invite
.find_by(code
: code
) unless code
.blank
?
256 def password_required
?
257 return false if Devise
.pam_authentication
|| Devise
.ldap_authentication
261 def send_reset_password_instructions
262 return false if encrypted_password
.blank
? && (Devise
.pam_authentication
|| Devise
.ldap_authentication
)
266 def reset_password!
(new_password
, new_password_confirmation
)
267 return false if encrypted_password
.blank
? && (Devise
.pam_authentication
|| Devise
.ldap_authentication
)
271 def self.pam_get_user(attributes
= {})
272 return nil unless attributes
[:email]
274 if Devise
.check_at_sign
&& !attributes
[:email].index('@')
275 joins(:account).find_by(accounts
: { username
: attributes
[:email] })
277 find_by(email
: attributes
[:email])
281 resource
= new(email
: attributes
[:email])
282 if Devise
.check_at_sign
&& !resource
[:email].index('@')
283 resource
[:email] = Rpam2
.getenv(resource
.find_pam_service
, attributes
[:email], attributes
[:password], 'email', false)
284 resource
[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource
[:email]
290 def self.ldap_get_user(attributes
= {})
291 resource
= joins(:account).find_by(accounts
: { username
: attributes
[Devise
.ldap_uid
.to_sym
].first
})
294 resource
= new(email
: attributes
[:mail].first
, account_attributes
: { username
: attributes
[Devise
.ldap_uid
.to_sym
].first
})
295 resource
.ldap_setup(attributes
)
301 def self.authenticate_with_pam(attributes
= {})
302 return nil unless Devise
.pam_authentication
308 def send_devise_notification(notification
, *args
)
309 devise_mailer
.send(notification
, self, *args
).deliver_later
314 def sanitize_languages
315 filtered_languages
.reject!
(&:blank?)
318 def prepare_new_user!
319 BootstrapTimelineWorker
.perform_async(account_id
)
320 ActivityTracker
.increment('activity:accounts:local')
321 UserMailer
.welcome(self).deliver_later
324 def prepare_returning_user!
325 ActivityTracker
.record('activity:logins', id
)
326 regenerate_feed!
if needs_feed_update
?
330 Redis
.current
.setnx("account:#{account_id}:regeneration", true) && Redis
.current
.expire("account:#{account_id}:regeneration", 1.day
.seconds
)
331 RegenerationWorker
.perform_async(account_id
)
334 def needs_feed_update
?
335 last_sign_in_at
< ACTIVE_DURATION
.ago