2020-01-29 13:08:47 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Spam
|
2020-04-21 11:21:10 -04:00
|
|
|
class SpamActionService
|
|
|
|
include SpamConstants
|
2020-01-29 13:08:47 -05:00
|
|
|
|
2020-02-27 07:09:12 -05:00
|
|
|
attr_accessor :target, :request, :options
|
2020-01-29 13:08:47 -05:00
|
|
|
attr_reader :spam_log
|
|
|
|
|
2020-06-08 02:08:19 -04:00
|
|
|
def initialize(spammable:, request:, user:, context: {})
|
2020-02-27 07:09:12 -05:00
|
|
|
@target = spammable
|
2020-01-29 13:08:47 -05:00
|
|
|
@request = request
|
2020-06-08 02:08:19 -04:00
|
|
|
@user = user
|
|
|
|
@context = context
|
2020-01-29 13:08:47 -05:00
|
|
|
@options = {}
|
|
|
|
|
|
|
|
if @request
|
|
|
|
@options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s
|
|
|
|
@options[:user_agent] = @request.env['HTTP_USER_AGENT']
|
|
|
|
@options[:referrer] = @request.env['HTTP_REFERRER']
|
|
|
|
else
|
2020-02-27 07:09:12 -05:00
|
|
|
@options[:ip_address] = @target.ip_address
|
|
|
|
@options[:user_agent] = @target.user_agent
|
2020-01-29 13:08:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-06-08 02:08:19 -04:00
|
|
|
def execute(api: false, recaptcha_verified:, spam_log_id:)
|
2020-01-29 13:08:47 -05:00
|
|
|
if recaptcha_verified
|
2020-04-21 14:09:31 -04:00
|
|
|
# If it's a request which is already verified through reCAPTCHA,
|
2020-01-29 13:08:47 -05:00
|
|
|
# update the spam log accordingly.
|
2020-05-04 23:09:46 -04:00
|
|
|
SpamLog.verify_recaptcha!(user_id: user.id, id: spam_log_id)
|
2020-01-29 13:08:47 -05:00
|
|
|
else
|
2020-05-06 08:09:36 -04:00
|
|
|
return if allowlisted?(user)
|
2020-04-21 11:21:10 -04:00
|
|
|
return unless request
|
|
|
|
return unless check_for_spam?
|
|
|
|
|
|
|
|
perform_spam_service_check(api)
|
2020-01-29 13:08:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
delegate :check_for_spam?, to: :target
|
|
|
|
|
2020-01-29 13:08:47 -05:00
|
|
|
private
|
|
|
|
|
2020-06-08 02:08:19 -04:00
|
|
|
attr_reader :user, :context
|
|
|
|
|
2020-05-06 08:09:36 -04:00
|
|
|
def allowlisted?(user)
|
2020-10-19 05:08:58 -04:00
|
|
|
user.try(:gitlab_employee?) || user.try(:gitlab_bot?) || user.try(:gitlab_service_user?)
|
2020-05-06 08:09:36 -04:00
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
def perform_spam_service_check(api)
|
|
|
|
# since we can check for spam, and recaptcha is not verified,
|
|
|
|
# ask the SpamVerdictService what to do with the target.
|
|
|
|
spam_verdict_service.execute.tap do |result|
|
|
|
|
case result
|
2020-05-25 23:08:02 -04:00
|
|
|
when CONDITIONAL_ALLOW
|
|
|
|
# at the moment, this means "ask for reCAPTCHA"
|
2020-04-21 11:21:10 -04:00
|
|
|
create_spam_log(api)
|
2020-01-29 13:08:47 -05:00
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
break if target.allow_possible_spam?
|
2020-01-29 13:08:47 -05:00
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
target.needs_recaptcha!
|
|
|
|
when DISALLOW
|
|
|
|
# TODO: remove `unless target.allow_possible_spam?` once this flag has been passed to `SpamVerdictService`
|
|
|
|
# https://gitlab.com/gitlab-org/gitlab/-/issues/214739
|
|
|
|
target.spam! unless target.allow_possible_spam?
|
|
|
|
create_spam_log(api)
|
|
|
|
when ALLOW
|
|
|
|
target.clear_spam_flags!
|
|
|
|
end
|
|
|
|
end
|
2020-01-29 13:08:47 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def create_spam_log(api)
|
|
|
|
@spam_log = SpamLog.create!(
|
|
|
|
{
|
2020-02-27 07:09:12 -05:00
|
|
|
user_id: target.author_id,
|
|
|
|
title: target.spam_title,
|
|
|
|
description: target.spam_description,
|
2020-01-29 13:08:47 -05:00
|
|
|
source_ip: options[:ip_address],
|
|
|
|
user_agent: options[:user_agent],
|
2020-06-08 02:08:19 -04:00
|
|
|
noteable_type: notable_type,
|
2020-01-29 13:08:47 -05:00
|
|
|
via_api: api
|
|
|
|
}
|
|
|
|
)
|
2020-04-21 11:21:10 -04:00
|
|
|
|
|
|
|
target.spam_log = spam_log
|
|
|
|
end
|
|
|
|
|
|
|
|
def spam_verdict_service
|
|
|
|
SpamVerdictService.new(target: target,
|
2020-06-08 02:08:19 -04:00
|
|
|
user: user,
|
2020-04-21 11:21:10 -04:00
|
|
|
request: @request,
|
2020-06-08 02:08:19 -04:00
|
|
|
options: options,
|
|
|
|
context: context.merge(target_type: notable_type))
|
|
|
|
end
|
|
|
|
|
|
|
|
def notable_type
|
|
|
|
@notable_type ||= target.class.to_s
|
2020-01-29 13:08:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|