Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/user.rb')
-rw-r--r--app/models/user.rb121
1 files changed, 107 insertions, 14 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index 50da6f9e491..96cdbb192bc 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -31,6 +31,7 @@ class User < ApplicationRecord
include RestrictedSignup
include StripAttribute
include EachBatch
+ include SafelyChangeColumnDefault
DEFAULT_NOTIFICATION_LEVEL = :participating
@@ -56,8 +57,14 @@ class User < ApplicationRecord
FORBIDDEN_SEARCH_STATES = %w(blocked banned ldap_blocked).freeze
- add_authentication_token_field :incoming_email_token, token_generator: -> { SecureRandom.hex.to_i(16).to_s(36) }
- add_authentication_token_field :feed_token
+ INCOMING_MAIL_TOKEN_PREFIX = 'glimt-'
+ FEED_TOKEN_PREFIX = 'glft-'
+
+ columns_changing_default :notified_of_own_activity
+
+ # lib/tasks/tokens.rake needs to be updated when changing mail and feed tokens
+ add_authentication_token_field :incoming_email_token, token_generator: -> { self.generate_incoming_mail_token }
+ add_authentication_token_field :feed_token, format_with_prefix: :prefix_for_feed_token
add_authentication_token_field :static_object_token, encrypted: :optional
attribute :admin, default: false
@@ -91,6 +98,7 @@ class User < ApplicationRecord
# Must be included after `devise`
include EncryptedUserPassword
+ include RecoverableByAnyEmail
include AdminChangedPasswordNotifier
@@ -215,8 +223,11 @@ class User < ApplicationRecord
has_many :releases, dependent: :nullify, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :subscriptions, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_many :abuse_reports, dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent
- has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent
+ has_many :abuse_reports, dependent: :nullify, foreign_key: :user_id, inverse_of: :user # rubocop:disable Cop/ActiveRecordDependent
+ has_many :reported_abuse_reports, dependent: :nullify, foreign_key: :reporter_id, class_name: "AbuseReport", inverse_of: :reporter # rubocop:disable Cop/ActiveRecordDependent
+ has_many :assigned_abuse_reports, foreign_key: :assignee_id, class_name: "AbuseReport", inverse_of: :assignee
+ has_many :resolved_abuse_reports, foreign_key: :resolved_by_id, class_name: "AbuseReport", inverse_of: :resolved_by
+ has_many :abuse_events, foreign_key: :user_id, class_name: 'Abuse::Event', inverse_of: :user
has_many :spam_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :abuse_trust_scores, class_name: 'Abuse::TrustScore', foreign_key: :user_id
has_many :builds, class_name: 'Ci::Build'
@@ -343,7 +354,7 @@ class User < ApplicationRecord
enum dashboard: { projects: 0, stars: 1, your_activity: 10, project_activity: 2, starred_project_activity: 3, groups: 4, todos: 5, issues: 6, merge_requests: 7, operations: 8, followed_user_activity: 9 }
# User's Project preference
- enum project_view: { readme: 0, activity: 1, files: 2 }
+ enum project_view: { readme: 0, activity: 1, files: 2, wiki: 3 }
# User's role
enum role: { software_developer: 0, development_team_lead: 1, devops_engineer: 2, systems_administrator: 3, security_analyst: 4, data_analyst: 5, product_manager: 6, product_designer: 7, other: 8 }, _suffix: true
@@ -360,6 +371,7 @@ class User < ApplicationRecord
:sourcegraph_enabled, :sourcegraph_enabled=,
:gitpod_enabled, :gitpod_enabled=,
:setup_for_company, :setup_for_company=,
+ :project_shortcut_buttons, :project_shortcut_buttons=,
:render_whitespace_in_code, :render_whitespace_in_code=,
:markdown_surround_selection, :markdown_surround_selection=,
:markdown_automatic_lists, :markdown_automatic_lists=,
@@ -960,6 +972,10 @@ class User < ApplicationRecord
def get_ids_by_ids_or_usernames(ids, usernames)
by_ids_or_usernames(ids, usernames).pluck(:id)
end
+
+ def generate_incoming_mail_token
+ "#{INCOMING_MAIL_TOKEN_PREFIX}#{SecureRandom.hex.to_i(16).to_s(36)}"
+ end
end
#
@@ -1664,16 +1680,19 @@ class User < ApplicationRecord
DELETION_DELAY_IN_DAYS = 7.days
def delete_async(deleted_by:, params: {})
- is_deleting_own_record = deleted_by.id == id
+ if should_delay_delete?(deleted_by)
+ new_note = format(_("User deleted own account on %{timestamp}"), timestamp: Time.zone.now)
+ self.note = "#{new_note}\n#{note}".strip
- if is_deleting_own_record && ::Feature.enabled?(:delay_delete_own_user)
- block
+ block_or_ban
DeleteUserWorker.perform_in(DELETION_DELAY_IN_DAYS, deleted_by.id, id, params.to_h)
- else
- block if params[:hard_delete]
- DeleteUserWorker.perform_async(deleted_by.id, id, params.to_h)
+ return
end
+
+ block if params[:hard_delete]
+
+ DeleteUserWorker.perform_async(deleted_by.id, id, params.to_h)
end
# rubocop: disable CodeReuse/ServiceClass
@@ -2155,6 +2174,14 @@ class User < ApplicationRecord
callout_dismissed?(callout, ignore_dismissal_earlier_than)
end
+ def dismissed_callout_before?(feature_name, dismissed_before)
+ callout = callouts_by_feature_name[feature_name]
+
+ return false unless callout
+
+ callout.dismissed_before?(dismissed_before)
+ end
+
def dismissed_callout_for_group?(feature_name:, group:, ignore_dismissal_earlier_than: nil)
source_feature_name = "#{feature_name}_#{group.id}"
callout = group_callouts_by_feature_name[source_feature_name]
@@ -2252,10 +2279,26 @@ class User < ApplicationRecord
namespace_commit_emails.find_by(namespace: project.root_namespace)
end
+ def spammer?
+ spam_score > Abuse::TrustScore::SPAMCHECK_HAM_THRESHOLD
+ end
+
def spam_score
abuse_trust_scores.spamcheck.average(:score) || 0.0
end
+ def telesign_score
+ abuse_trust_scores.telesign.order(created_at: :desc).first&.score || 0.0
+ end
+
+ def arkose_global_score
+ abuse_trust_scores.arkose_global_score.order(created_at: :desc).first&.score || 0.0
+ end
+
+ def arkose_custom_score
+ abuse_trust_scores.arkose_custom_score.order(created_at: :desc).first&.score || 0.0
+ end
+
def trust_scores_for_source(source)
abuse_trust_scores.where(source: source)
end
@@ -2267,6 +2310,12 @@ class User < ApplicationRecord
}
end
+ def namespace_commit_email_for_namespace(namespace)
+ return if namespace.nil?
+
+ namespace_commit_emails.find_by(namespace: namespace)
+ end
+
protected
# override, from Devise::Validatable
@@ -2305,6 +2354,45 @@ class User < ApplicationRecord
private
+ def block_or_ban
+ if spammer? && account_age_in_days < 7
+ ban_and_report
+ else
+ block
+ end
+ end
+
+ def ban_and_report
+ msg = 'Potential spammer account deletion'
+ attrs = { user_id: id, reporter: User.security_bot, category: 'spam' }
+ abuse_report = AbuseReport.find_by(attrs)
+
+ if abuse_report.nil?
+ abuse_report = AbuseReport.create!(attrs.merge(message: msg))
+ else
+ abuse_report.update(message: "#{abuse_report.message}\n\n#{msg}")
+ end
+
+ UserCustomAttribute.set_banned_by_abuse_report(abuse_report)
+
+ ban
+ end
+
+ def has_possible_spam_contributions?
+ events
+ .for_action('commented')
+ .or(events.for_action('created').where(target_type: %w[Issue MergeRequest]))
+ .any?
+ end
+
+ def should_delay_delete?(deleted_by)
+ is_deleting_own_record = deleted_by.id == id
+
+ is_deleting_own_record &&
+ ::Feature.enabled?(:delay_delete_own_user) &&
+ has_possible_spam_contributions?
+ end
+
def pbkdf2?
return false unless otp_backup_codes&.any?
@@ -2357,9 +2445,10 @@ class User < ApplicationRecord
def authorized_groups_without_shared_membership
Group.from_union(
[
- groups.select(*Namespace.cached_column_list),
- authorized_projects.joins(:namespace).select(*Namespace.cached_column_list)
- ])
+ groups,
+ Group.id_in(authorized_projects.select(:namespace_id))
+ ]
+ )
end
def authorized_groups_with_shared_membership
@@ -2515,6 +2604,10 @@ class User < ApplicationRecord
Ci::NamespaceMirror.contains_traversal_ids(traversal_ids)
end
+
+ def prefix_for_feed_token
+ FEED_TOKEN_PREFIX
+ end
end
User.prepend_mod_with('User')