about summary refs log tree commit diff
path: root/app/models/user.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/user.rb')
-rw-r--r--app/models/user.rb76
1 files changed, 67 insertions, 9 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index 9bdbac76d..d3ac464d7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -42,6 +42,8 @@
 #  sign_in_token_sent_at     :datetime
 #  webauthn_id               :string
 #  sign_up_ip                :inet
+#  username                  :string
+#  kobold                    :string
 #
 
 class User < ApplicationRecord
@@ -90,7 +92,7 @@ class User < ApplicationRecord
   validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
 
   scope :recent, -> { order(id: :desc) }
-  scope :pending, -> { where(approved: false) }
+  scope :pending, -> { where(approved: false).where.not(kobold: '') }
   scope :approved, -> { where(approved: true) }
   scope :confirmed, -> { where.not(confirmed_at: nil) }
   scope :enabled, -> { where(disabled: false) }
@@ -100,6 +102,7 @@ class User < ApplicationRecord
   scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
   scope :matches_ip, ->(value) { left_joins(:session_activations).where('users.current_sign_in_ip <<= ?', value).or(left_joins(:session_activations).where('users.sign_up_ip <<= ?', value)).or(left_joins(:session_activations).where('users.last_sign_in_ip <<= ?', value)).or(left_joins(:session_activations).where('session_activations.ip <<= ?', value)) }
   scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
+  scope :lower_username, ->(username) { where('lower(users.username) = lower(?)', username) }
 
   before_validation :sanitize_languages
   before_create :set_approved
@@ -114,9 +117,15 @@ class User < ApplicationRecord
 
   delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
            :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_network, :hide_followers_count,
-           :expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
+           :expand_spoilers, :default_language, :show_application,
            :advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
            :disable_swiping, :default_content_type, :system_emoji_font,
+           :manual_publish, :style_dashed_nest, :style_underline_a, :style_css_profile,
+           :style_css_profile_errors, :style_css_webapp, :style_css_webapp_errors,
+           :style_wide_media, :style_lowercase,
+           :publish_in, :unpublish_in, :unpublish_delete, :boost_every, :boost_jitter,
+           :boost_random, :unpublish_on_delete, :home_reblogs,
+           :filter_unknown, :max_history_public, :max_history_private, :web_push,
            to: :settings, prefix: :setting, allow_nil: false
 
   attr_reader :invite_code, :sign_in_token_attempt
@@ -150,7 +159,7 @@ class User < ApplicationRecord
 
     if new_user && approved?
       prepare_new_user!
-    elsif new_user
+    elsif new_user && user_might_not_be_a_spam_bot
       notify_staff_about_pending_account!
     end
   end
@@ -192,7 +201,7 @@ class User < ApplicationRecord
   end
 
   def suspicious_sign_in?(ip)
-    !otp_required_for_login? && current_sign_in_at.present? && current_sign_in_at < 2.weeks.ago && !recent_ip?(ip)
+    !otp_required_for_login? && current_sign_in_at.present? && current_sign_in_at < 12.weeks.ago && !recent_ip?(ip)
   end
 
   def functional?
@@ -260,14 +269,26 @@ class User < ApplicationRecord
     @hides_network ||= settings.hide_network
   end
 
-  def aggregates_reblogs?
-    @aggregates_reblogs ||= settings.aggregate_reblogs
-  end
-
   def shows_application?
     @shows_application ||= settings.show_application
   end
 
+  def home_reblogs?
+    @home_reblogs ||= settings.home_reblogs
+  end
+
+  def filters_unknown?
+    @filters_unknown ||= settings.filter_unknown
+  end
+
+  def max_history_private
+    @max_history_private ||= settings.max_history_private.to_i
+  end
+
+  def max_history_public
+    @max_history_public ||= [settings.max_history_public.to_i, max_history_private].min
+  end
+
   # rubocop:disable Naming/MethodParameterName
   def token_for_app(a)
     return nil if a.nil? || a.owner != self
@@ -321,6 +342,17 @@ class User < ApplicationRecord
     super
   end
 
+  def send_confirmation_instructions
+    unless approved? || user_might_not_be_a_spam_bot
+      invite_request&.destroy
+      account&.destroy
+      destroy
+      return false
+    end
+
+    super
+  end
+
   def reset_password!(new_password, new_password_confirmation)
     return false if encrypted_password.blank?
 
@@ -440,7 +472,7 @@ class User < ApplicationRecord
 
   def notify_staff_about_pending_account!
     User.staff.includes(:account).find_each do |u|
-      next unless u.allows_pending_account_emails?
+      next unless u.account.actor_type == 'Person' && u.allows_pending_account_emails?
       AdminMailer.new_pending_account(u.account, self).deliver_later
     end
   end
@@ -458,4 +490,30 @@ class User < ApplicationRecord
   def validate_email_dns?
     email_changed? && !(Rails.env.test? || Rails.env.development?)
   end
+
+  def user_might_not_be_a_spam_bot
+    return false unless username.downcase == account.username.downcase
+
+    update(username: account.username) unless username == account.username
+    invited? || (invite_request&.text.present? && kobold_hash_matches?)
+  end
+
+  def kobold_hash_matches?
+    kobold.present? && kobold == kobold_hash
+  end
+
+  def kobold_hash
+    value = [account.username, username.downcase, email, invite_request.text.gsub(/\r\n?/, "\n")].compact.map(&:downcase).join("\u{F0666}")
+    Digest::SHA512.hexdigest(value).upcase
+  end
+
+  class << self
+    def find_by_lower_username(username)
+      lower_username(username).first
+    end
+
+    def find_by_lower_username!(username)
+      lower_username(username).first!
+    end
+  end
 end