diff options
Diffstat (limited to 'app/services/spam/spam_verdict_service.rb')
-rw-r--r-- | app/services/spam/spam_verdict_service.rb | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/app/services/spam/spam_verdict_service.rb b/app/services/spam/spam_verdict_service.rb index 2b4d5f4a984..68f1135ae28 100644 --- a/app/services/spam/spam_verdict_service.rb +++ b/app/services/spam/spam_verdict_service.rb @@ -5,22 +5,90 @@ module Spam include AkismetMethods include SpamConstants - def initialize(target:, request:, options:) + def initialize(user:, target:, request:, options:, context: {}) @target = target @request = request + @user = user @options = options + @verdict_params = assemble_verdict_params(context) end def execute + external_spam_check_result = spam_verdict + akismet_result = akismet_verdict + + # filter out anything we don't recognise, including nils. + valid_results = [external_spam_check_result, akismet_result].compact.select { |r| SUPPORTED_VERDICTS.key?(r) } + # Treat nils - such as service unavailable - as ALLOW + return ALLOW unless valid_results.any? + + # Favour the most restrictive result. + valid_results.min_by { |v| SUPPORTED_VERDICTS[v][:priority] } + end + + private + + attr_reader :user, :target, :request, :options, :verdict_params + + def akismet_verdict if akismet.spam? - Gitlab::Recaptcha.enabled? ? REQUIRE_RECAPTCHA : DISALLOW + Gitlab::Recaptcha.enabled? ? CONDITIONAL_ALLOW : DISALLOW else ALLOW end end - private + def spam_verdict + return unless Gitlab::CurrentSettings.spam_check_endpoint_enabled + return if endpoint_url.blank? + + begin + result = Gitlab::HTTP.post(endpoint_url, body: verdict_params.to_json, headers: { 'Content-Type' => 'application/json' }) + return unless result + + json_result = Gitlab::Json.parse(result).with_indifferent_access + # @TODO metrics/logging + # Expecting: + # error: (string or nil) + # result: (string or nil) + verdict = json_result[:verdict] + return unless SUPPORTED_VERDICTS.include?(verdict) - attr_reader :target, :request, :options + # @TODO log if json_result[:error] + + json_result[:verdict] + rescue *Gitlab::HTTP::HTTP_ERRORS => e + # @TODO: log error via try_post https://gitlab.com/gitlab-org/gitlab/-/issues/219223 + Gitlab::ErrorTracking.log_exception(e) + return + rescue + # @TODO log + ALLOW + end + end + + def assemble_verdict_params(context) + return {} unless endpoint_url.present? + + project = target.try(:project) + + context.merge({ + target: { + title: target.spam_title, + description: target.spam_description, + type: target.class.to_s + }, + user: { + created_at: user.created_at, + email: user.email, + username: user.username + }, + user_in_project: user.authorized_project?(project) + }) + end + + def endpoint_url + @endpoint_url ||= Gitlab::CurrentSettings.current_application_settings.spam_check_endpoint_url + end end end |