94 lines
2.6 KiB
Ruby
94 lines
2.6 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 = 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? ? CONDITIONAL_ALLOW : DISALLOW
|
|
else
|
|
ALLOW
|
|
end
|
|
end
|
|
|
|
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)
|
|
|
|
# @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
|