gitlab-org--gitlab-foss/app/services/spam/spam_verdict_service.rb

91 lines
2.5 KiB
Ruby

# frozen_string_literal: true
module Spam
class SpamVerdictService
include AkismetMethods
include SpamConstants
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 = external_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? ? CONDITIONAL_ALLOW : DISALLOW
else
ALLOW
end
end
def external_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)
# verdict: (string or nil)
# @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)
nil
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