decidim-spam_signal 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +661 -0
- data/README.md +277 -0
- data/Rakefile +93 -0
- data/app/commands/decidim/comments/create_comment.rb +75 -0
- data/app/commands/decidim/spam_signal/admin/add_rule_command.rb +48 -0
- data/app/commands/decidim/spam_signal/admin/add_scanner_command.rb +46 -0
- data/app/commands/decidim/spam_signal/admin/remove_cop_command.rb +31 -0
- data/app/commands/decidim/spam_signal/admin/remove_rule_command.rb +31 -0
- data/app/commands/decidim/spam_signal/admin/remove_scanner_command.rb +31 -0
- data/app/commands/decidim/spam_signal/admin/update_cop_command.rb +41 -0
- data/app/commands/decidim/spam_signal/admin/update_rule_command.rb +47 -0
- data/app/commands/decidim/spam_signal/admin/update_scanner_command.rb +47 -0
- data/app/commands/decidim/spam_signal/application_handler.rb +27 -0
- data/app/commands/decidim/spam_signal/command.rb +14 -0
- data/app/commands/decidim/spam_signal/cops/cop_handler.rb +72 -0
- data/app/commands/decidim/spam_signal/cops/lock_cop_command.rb +58 -0
- data/app/commands/decidim/spam_signal/cops/sinalize_cop_command.rb +25 -0
- data/app/commands/decidim/spam_signal/scans/allowed_tlds_scan_command.rb +50 -0
- data/app/commands/decidim/spam_signal/scans/forbidden_tlds_scan_command.rb +49 -0
- data/app/commands/decidim/spam_signal/scans/scan_handler.rb +24 -0
- data/app/commands/decidim/spam_signal/scans/word_scan_command.rb +40 -0
- data/app/controllers/concerns/decidim/user_blocked_checker.rb +48 -0
- data/app/controllers/decidim/spam_signal/admin/application_controller.rb +18 -0
- data/app/controllers/decidim/spam_signal/admin/application_cops_controller.rb +122 -0
- data/app/controllers/decidim/spam_signal/admin/application_rules_controller.rb +136 -0
- data/app/controllers/decidim/spam_signal/admin/application_scans_controller.rb +110 -0
- data/app/controllers/decidim/spam_signal/admin/comment_cops_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/comment_rules_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/comment_scans_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/profile_cops_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/profile_rules_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/profile_scans_controller.rb +13 -0
- data/app/controllers/decidim/spam_signal/admin/spam_filter_reports_controller.rb +41 -0
- data/app/forms/decidim/spam_signal/cops/lock_settings_form.rb +14 -0
- data/app/forms/decidim/spam_signal/cops/no_settings_form.rb +11 -0
- data/app/forms/decidim/spam_signal/cops/sinalize_settings_form.rb +13 -0
- data/app/forms/decidim/spam_signal/no_settings_form.rb +9 -0
- data/app/forms/decidim/spam_signal/rule_form.rb +10 -0
- data/app/forms/decidim/spam_signal/scans/allowed_tlds_form.rb +13 -0
- data/app/forms/decidim/spam_signal/scans/forbidden_tlds_form.rb +13 -0
- data/app/forms/decidim/spam_signal/scans/word_settings_form.rb +13 -0
- data/app/forms/decidim/spam_signal/settings_form.rb +27 -0
- data/app/helpers/decidim/spam_signal/admin/spam_signal_helper.rb +22 -0
- data/app/helpers/decidim/spam_signal/application_helper.rb +10 -0
- data/app/models/decidim/spam_signal/config.rb +48 -0
- data/app/overrides/profiles_noindex.rb +17 -0
- data/app/packs/images/decidim/spam_signal/entrypoints/spam_signal.js +1 -0
- data/app/packs/images/decidim/spam_signal/icon.svg +1 -0
- data/app/repositories/decidim/spam_signal/spam_config_repo.rb +160 -0
- data/app/views/decidim/admin/moderated_users/_report.html.erb +15 -0
- data/app/views/decidim/admin/moderated_users/index.html.erb +82 -0
- data/app/views/decidim/comments/comments/error.js.erb +4 -0
- data/app/views/decidim/spam_signal/admin/comment_cops/edit.html.erb +9 -0
- data/app/views/decidim/spam_signal/admin/comment_rules/edit.html.erb +8 -0
- data/app/views/decidim/spam_signal/admin/comment_rules/new.html.erb +9 -0
- data/app/views/decidim/spam_signal/admin/comment_scans/edit.html.erb +8 -0
- data/app/views/decidim/spam_signal/admin/comment_scans/new.html.erb +8 -0
- data/app/views/decidim/spam_signal/admin/profile_cops/edit.html.erb +9 -0
- data/app/views/decidim/spam_signal/admin/profile_rules/edit.html.erb +8 -0
- data/app/views/decidim/spam_signal/admin/profile_rules/new.html.erb +9 -0
- data/app/views/decidim/spam_signal/admin/profile_scans/edit.html.erb +7 -0
- data/app/views/decidim/spam_signal/admin/profile_scans/new.html.erb +8 -0
- data/app/views/decidim/spam_signal/admin/shared/cops/_edit.html.erb +48 -0
- data/app/views/decidim/spam_signal/admin/shared/rules/_edit.html.erb +27 -0
- data/app/views/decidim/spam_signal/admin/shared/rules/_new.html.erb +28 -0
- data/app/views/decidim/spam_signal/admin/shared/scans/_edit.html.erb +25 -0
- data/app/views/decidim/spam_signal/admin/shared/scans/_new.html.erb +39 -0
- data/app/views/decidim/spam_signal/admin/spam_filter_reports/index.html.erb +282 -0
- data/config/assets.rb +8 -0
- data/config/i18n-tasks.yml +9 -0
- data/config/initializers/spam_signal.rb +7 -0
- data/config/locales/en.yml +114 -0
- data/config/locales/fr.yml +115 -0
- data/config/routes.rb +3 -0
- data/lib/decidim/spam_signal/admin.rb +10 -0
- data/lib/decidim/spam_signal/admin_engine.rb +42 -0
- data/lib/decidim/spam_signal/cop_bot.rb +41 -0
- data/lib/decidim/spam_signal/cops/cops_repository.rb +37 -0
- data/lib/decidim/spam_signal/engine.rb +23 -0
- data/lib/decidim/spam_signal/extractors/comment_extractor.rb +15 -0
- data/lib/decidim/spam_signal/extractors/extractor.rb +13 -0
- data/lib/decidim/spam_signal/extractors/profile_extractor.rb +15 -0
- data/lib/decidim/spam_signal/scans/scans_repository.rb +44 -0
- data/lib/decidim/spam_signal/spam_settings_form_builder.rb +22 -0
- data/lib/decidim/spam_signal/test/factories.rb +24 -0
- data/lib/decidim/spam_signal/test/scan_factories.rb +17 -0
- data/lib/decidim/spam_signal/validators/comment_spam_validator.rb +119 -0
- data/lib/decidim/spam_signal/validators/profile_spam_validator.rb +133 -0
- data/lib/decidim/spam_signal/version.rb +14 -0
- data/lib/decidim/spam_signal.rb +31 -0
- data/lib/tasks/antispam.rb +23 -0
- metadata +210 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Admin
|
6
|
+
class UpdateRuleCommand < Decidim::SpamSignal::Command
|
7
|
+
attr_reader :form,
|
8
|
+
:current_config,
|
9
|
+
:settings_repo,
|
10
|
+
:id
|
11
|
+
|
12
|
+
def initialize(config, settings_repo, form, id)
|
13
|
+
@current_config = config
|
14
|
+
@settings_repo = settings_repo
|
15
|
+
@form = form
|
16
|
+
@id = id
|
17
|
+
raise ArgumentError, "missing current_config" unless current_config
|
18
|
+
raise ArgumentError, "missing settings_repo" unless settings_repo
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
return broadcast(:invalid) if form.invalid?
|
23
|
+
begin
|
24
|
+
rule = {}
|
25
|
+
rule["#{id}"] = attributes
|
26
|
+
rule["#{id}"]["handler_name"] = form.handler_name
|
27
|
+
settings_repo.set_rule(rule)
|
28
|
+
current_config.save_settings
|
29
|
+
broadcast(:ok, settings_repo)
|
30
|
+
rescue StandardError => e
|
31
|
+
broadcast(:invalid, e.message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def form_blank?(form)
|
38
|
+
return true if form.nil?
|
39
|
+
attributes.blank?
|
40
|
+
end
|
41
|
+
def attributes
|
42
|
+
form.attributes.stringify_keys!
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Admin
|
6
|
+
class UpdateScannerCommand < Decidim::SpamSignal::Command
|
7
|
+
attr_reader :form,
|
8
|
+
:current_config,
|
9
|
+
:settings_repo
|
10
|
+
|
11
|
+
def initialize(config, settings_repo, form)
|
12
|
+
@current_config = config
|
13
|
+
@settings_repo = settings_repo
|
14
|
+
@form = form
|
15
|
+
raise ArgumentError, "missing current_config" unless current_config
|
16
|
+
raise ArgumentError, "missing settings_repo" unless settings_repo
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
return broadcast(:invalid) if form.invalid?
|
21
|
+
return broadcast(:invalid) if attributes.blank?
|
22
|
+
|
23
|
+
begin
|
24
|
+
settings_repo.set_scan(
|
25
|
+
form.handler_name,
|
26
|
+
attributes
|
27
|
+
)
|
28
|
+
current_config.save_settings
|
29
|
+
broadcast(:ok, settings_repo)
|
30
|
+
rescue StandardError => e
|
31
|
+
broadcast(:invalid, e.message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def form_blank?(form)
|
38
|
+
return true if form.nil?
|
39
|
+
attributes.blank?
|
40
|
+
end
|
41
|
+
def attributes
|
42
|
+
form.attributes.stringify_keys!
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
class ApplicationHandler < Decidim::SpamSignal::Command
|
6
|
+
def self.form
|
7
|
+
raise Error, "Handler need to define a form or return null"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.handler_name
|
11
|
+
name.demodulize.underscore.sub(/(_cop|_scan)(_form|_command)/, "")
|
12
|
+
end
|
13
|
+
|
14
|
+
def handler_name
|
15
|
+
self.class.handler_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.i18n_key
|
19
|
+
raise Error, "Not Implemented"
|
20
|
+
end
|
21
|
+
|
22
|
+
def config
|
23
|
+
raise Error, "Not Implemented"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
# maintains compatibility with v0.26 which uses Rectify
|
6
|
+
if defined? ::Decidim::Command
|
7
|
+
class Command < ::Decidim::Command
|
8
|
+
end
|
9
|
+
else
|
10
|
+
class Command < ::Rectify::Command
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Cops
|
6
|
+
class CopHandler < ApplicationHandler
|
7
|
+
attr_reader :errors, :error_key, :suspicious_user, :justification, :admin_reporter, :config, :reportable, :current_organization
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
errors:,
|
11
|
+
error_key: :base,
|
12
|
+
suspicious_user:,
|
13
|
+
config:,
|
14
|
+
reportable: nil,
|
15
|
+
justification: nil,
|
16
|
+
admin_reporter: nil
|
17
|
+
)
|
18
|
+
@errors = errors
|
19
|
+
@error_key = error_key
|
20
|
+
@reportable = reportable || suspicious_user
|
21
|
+
@suspicious_user = suspicious_user
|
22
|
+
@current_organization = suspicious_user.organization
|
23
|
+
|
24
|
+
@config = config
|
25
|
+
@justification = justification
|
26
|
+
@admin_reporter = admin_reporter || CopBot.get(suspicious_user.organization)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.i18n_key
|
30
|
+
"decidim.spam_signal.cops.#{handler_name}"
|
31
|
+
end
|
32
|
+
def now_tag
|
33
|
+
"\n[#{DateTime.now.strftime("%d/%m/%Y %H:%M")}]"
|
34
|
+
end
|
35
|
+
def sinalize!(send_emails=true)
|
36
|
+
is_user_reported = reportable == suspicious_user
|
37
|
+
if is_user_reported
|
38
|
+
moderation = Decidim::UserModeration.find_or_create_by!(user: suspicious_user) do |moderation|
|
39
|
+
moderation.report_count = 0
|
40
|
+
end
|
41
|
+
else
|
42
|
+
moderation = Decidim::Moderation.find_or_create_by!(reportable: reportable, participatory_space: reportable.participatory_space) do |moderation|
|
43
|
+
moderation.report_count = 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
is_new = moderation.report_count == 0
|
47
|
+
moderation.update(report_count: moderation.report_count + 1)
|
48
|
+
if is_user_reported
|
49
|
+
user_report = Decidim::UserReport.find_or_create_by!(moderation: moderation) do |report|
|
50
|
+
report.moderation = moderation
|
51
|
+
report.user = admin_reporter
|
52
|
+
report.reason = "spam"
|
53
|
+
report.details = "#{now_tag}#{justification}"
|
54
|
+
end
|
55
|
+
else
|
56
|
+
user_report = Decidim::Report.find_or_create_by!(moderation: moderation) do |report|
|
57
|
+
report.moderation = moderation
|
58
|
+
report.user = admin_reporter
|
59
|
+
report.reason = "spam"
|
60
|
+
report.details = "#{now_tag}#{justification}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
# append the new bad things (to have a log).
|
64
|
+
user_report.update(details: "#{user_report.details}#{now_tag} #{justification}") unless is_new
|
65
|
+
admin_accountable = Decidim::User.where(admin: true, email: ENV.fetch("ANTISPAM_ADMIN", "antispam@example.org")).first
|
66
|
+
Decidim::UserReportJob.perform_later(admin, admin_reporter, "spam", reportable)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Cops
|
6
|
+
class LockCopCommand < CopHandler
|
7
|
+
def self.form
|
8
|
+
::Decidim::SpamSignal::Cops::LockSettingsForm
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
errors.add(
|
13
|
+
error_key,
|
14
|
+
I18n.t("errors.spam",
|
15
|
+
scope: "decidim.spam_signal",
|
16
|
+
default: "this looks like spam."
|
17
|
+
)
|
18
|
+
) unless config['forbid_creation_enabled']
|
19
|
+
unless suspicious_user.access_locked?
|
20
|
+
hide_comment! if config["hide_comments_enabled"]
|
21
|
+
sinalize! if config["sinalize_user_enabled"]
|
22
|
+
lock!
|
23
|
+
end
|
24
|
+
broadcast(config['forbid_creation_enabled'] ? :restore_value : :save)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def hide_comment!
|
29
|
+
suspicious_comments = Decidim::Comments::Comment.where(author: suspicious_user)
|
30
|
+
suspicious_comments.each do |spam|
|
31
|
+
moderation = Decidim::Moderation.find_or_create_by!(
|
32
|
+
reportable: spam,
|
33
|
+
participatory_space: spam.participatory_space
|
34
|
+
)
|
35
|
+
is_new = moderation.report_count == 0
|
36
|
+
moderation.update(reported_content: spam.body[admin_reporter.locale]) if !moderation.reported_content && spam.body[admin_reporter.locale]
|
37
|
+
report = Decidim::Report.find_or_create_by!(
|
38
|
+
moderation: moderation.reload,
|
39
|
+
user: admin_reporter) do |report|
|
40
|
+
report.locale = admin_reporter.locale
|
41
|
+
report.reason = "spam"
|
42
|
+
report.details = "#{now_tag}cascade: #{spam}"
|
43
|
+
end
|
44
|
+
report.update(details: "#{report.details}#{now_tag}cascade: #{spam}")unless is_new
|
45
|
+
moderation.update!(report_count: moderation.report_count + 1, hidden_at: Time.current)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def lock!
|
50
|
+
suspicious_user.lock_access!(
|
51
|
+
send_instructions: true
|
52
|
+
)
|
53
|
+
suspicious_user.save!(validate: false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Cops
|
6
|
+
class SinalizeCopCommand < CopHandler
|
7
|
+
def self.form
|
8
|
+
::Decidim::SpamSignal::Cops::SinalizeSettingsForm
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
errors.add(
|
13
|
+
error_key,
|
14
|
+
I18n.t("errors.spam",
|
15
|
+
scope: "decidim.spam_signal",
|
16
|
+
default: "this looks like spam."
|
17
|
+
)
|
18
|
+
) if config['forbid_creation_enabled']
|
19
|
+
sinalize!(config['send_emails_enabled'])
|
20
|
+
broadcast(config['forbid_creation_enabled'] ? :restore_value : :save)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Scans
|
6
|
+
class AllowedTldsScanCommand < ScanHandler
|
7
|
+
def self.form
|
8
|
+
::Decidim::SpamSignal::Scans::AllowedTldsForm
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return broadcast(:ok) if allowed_tlds_csv.empty?
|
13
|
+
return broadcast(:ok) if all_allowed?
|
14
|
+
broadcast(:not_allowed_tlds_found)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.output_symbols
|
18
|
+
[:not_allowed_tlds_found]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def allowed_tlds_csv
|
24
|
+
@allowed_tlds_csv ||= (
|
25
|
+
config["allowed_tlds_csv"] || ""
|
26
|
+
).split(",").map(&:strip).filter { |tlds| !tlds.empty? }
|
27
|
+
end
|
28
|
+
|
29
|
+
def all_allowed?
|
30
|
+
hosts.filter { |url| !allowed_tlds_csv.any? { |tld| url.include? tld } }.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def hosts
|
34
|
+
URI.extract(suspicious_content, ["http", "https", "", "mailto" ]).map do |uri|
|
35
|
+
begin
|
36
|
+
(scheme, subdomain, host) = URI.split(uri)
|
37
|
+
host || ""
|
38
|
+
rescue URI::InvalidURIError
|
39
|
+
""
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def regex(patterns)
|
45
|
+
Regexp.union(patterns).source
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Scans
|
6
|
+
class ForbiddenTldsScanCommand < ScanHandler
|
7
|
+
def self.form
|
8
|
+
::Decidim::SpamSignal::Scans::ForbiddenTldsForm
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return broadcast(:forbidden_tlds_found) if any_forbidden_tlds?
|
13
|
+
broadcast(:ok)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.output_symbols
|
17
|
+
[:forbidden_tlds_found]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def forbidden_tlds_csv
|
23
|
+
@forbidden_tlds_csv ||= (
|
24
|
+
config["forbidden_tlds_csv"] || ""
|
25
|
+
).split(",").map(&:strip)
|
26
|
+
end
|
27
|
+
|
28
|
+
def any_forbidden_tlds?
|
29
|
+
hosts.filter { |url| forbidden_tlds_csv.any? { |tld| url.include? tld } }.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def hosts
|
33
|
+
URI.extract(suspicious_content, ["http", "https", "", "mailto" ]).map do |uri|
|
34
|
+
begin
|
35
|
+
(scheme, subdomain, host) = URI.split(uri)
|
36
|
+
host
|
37
|
+
rescue URI::InvalidURIError
|
38
|
+
""
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def regex(patterns)
|
44
|
+
Regexp.union(patterns).source
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Scans
|
6
|
+
class ScanHandler < ApplicationHandler
|
7
|
+
attr_reader :suspicious_content, :config
|
8
|
+
|
9
|
+
def initialize(suspicious_content, config)
|
10
|
+
@suspicious_content = suspicious_content
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.i18n_key
|
15
|
+
"decidim.spam_signal.scans.#{handler_name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.output_symbols
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Scans
|
6
|
+
class WordScanCommand < ScanHandler
|
7
|
+
def self.form
|
8
|
+
::Decidim::SpamSignal::Scans::WordSettingsForm
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return broadcast(:ok) if suspicious_content.empty?
|
13
|
+
return broadcast(:word_found) if contains_stop_words?
|
14
|
+
broadcast(:ok)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.output_symbols
|
18
|
+
[:word_found]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def contains_stop_words?
|
23
|
+
@contains_stop_words ||= suspicious_content.match(
|
24
|
+
/#{regex(stop_list_words)}/i
|
25
|
+
).to_s.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def regex(patterns)
|
29
|
+
Regexp.union(patterns).source
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop_list_words
|
33
|
+
@stop_list_words ||= (
|
34
|
+
config["stop_list_words_csv"] || ""
|
35
|
+
).split("\n").map(&:strip)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module UserBlockedChecker
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
before_action :check_user_not_blocked
|
11
|
+
around_action :store_request_metadata
|
12
|
+
end
|
13
|
+
|
14
|
+
def store_request_metadata
|
15
|
+
Thread.current[:current_request] = ::ActiveSupport::HashWithIndifferentAccess.new(
|
16
|
+
real_ip: request.ip || request.headers['X-Real-IP'],
|
17
|
+
user_agent: request.headers['User-Agent'],
|
18
|
+
xhr: request.xhr?,
|
19
|
+
id: request.request_id,
|
20
|
+
remote_ip: request.remote_ip,
|
21
|
+
referrer: request.headers['Refer'],
|
22
|
+
country: request.headers['X-GEO-COUNTRY-CODE']
|
23
|
+
)
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
Thread.current[:current_request] = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_user_not_blocked
|
30
|
+
check_user_block_status(current_user)
|
31
|
+
end
|
32
|
+
|
33
|
+
def check_user_block_status(user)
|
34
|
+
if user.present? && user.blocked?
|
35
|
+
sign_out user
|
36
|
+
flash.delete(:notice)
|
37
|
+
flash[:error] = t("decidim.account.blocked")
|
38
|
+
root_path
|
39
|
+
end
|
40
|
+
if user.present? && user.access_locked?
|
41
|
+
sign_out user
|
42
|
+
flash.delete(:notice)
|
43
|
+
flash[:error] = t("decidim.account.locked")
|
44
|
+
root_path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Admin
|
6
|
+
# This controller is the abstract class from which all other controllers of
|
7
|
+
# this engine inherit.
|
8
|
+
#
|
9
|
+
# Note that it inherits from `Decidim::Admin::Components::BaseController`, which
|
10
|
+
# override its layout and provide all kinds of useful methods.
|
11
|
+
class ApplicationController < Decidim::Admin::ApplicationController
|
12
|
+
before_action do
|
13
|
+
enforce_permission_to :update, :organization, organization: current_organization
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module SpamSignal
|
5
|
+
module Admin
|
6
|
+
class ApplicationCopsController < ApplicationController
|
7
|
+
include FormFactory
|
8
|
+
before_action :config
|
9
|
+
helper Decidim::SpamSignal::Admin::SpamSignalHelper
|
10
|
+
helper_method :cop_type, :available_cops, :current_config, :current_cop
|
11
|
+
def index
|
12
|
+
output_symbols = scan_repository.strategies.map do |scan_name|
|
13
|
+
scanKlass = scan_repository.strategy(scan_name)
|
14
|
+
scanKlass.output_symbols
|
15
|
+
end.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy
|
19
|
+
raise "Missing id" unless cop_type
|
20
|
+
RemoveCopCommand.call(
|
21
|
+
current_config,
|
22
|
+
resource_config,
|
23
|
+
cop_type
|
24
|
+
) do |on|
|
25
|
+
on(:invalid) { flash[:alert] = "Can not remove the agent" }
|
26
|
+
on(:ok) { flash[:notice] = "Remove has been removed" }
|
27
|
+
redirect_to spam_filter_reports_path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def update
|
32
|
+
raise "No agent found" unless current_cop
|
33
|
+
form = current_cop.form.from_params(params.require("#{cop_key}")).with_context(
|
34
|
+
handler_name: current_cop.handler_name,
|
35
|
+
type: cop_type
|
36
|
+
)
|
37
|
+
UpdateCopCommand.call(
|
38
|
+
current_config,
|
39
|
+
resource_config,
|
40
|
+
form
|
41
|
+
) do |on|
|
42
|
+
on(:invalid) { flash[:alert] = "Can not update the agent" }
|
43
|
+
on(:ok) { flash[:notice] = "Agent has been updated" }
|
44
|
+
redirect_to spam_filter_reports_path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def edit
|
49
|
+
@form = nil
|
50
|
+
if current_cop && current_cop.form
|
51
|
+
@form = current_cop.form.new(
|
52
|
+
**(resource_config.cop_options(current_cop.handler_name, cop_type) || {})
|
53
|
+
).with_context(
|
54
|
+
config: current_config,
|
55
|
+
handler_name: current_cop.handler_name
|
56
|
+
)
|
57
|
+
elsif current_cop
|
58
|
+
@form = Decidim::SpamSignal::NoSettingsForm.new.with_context(
|
59
|
+
config: current_config,
|
60
|
+
handler_name: current_cop.handler_name
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def create
|
66
|
+
raise "No scanner found" unless current_cop
|
67
|
+
form = current_cop.form.from_params(
|
68
|
+
params.require("#{cop_type}".to_sym)
|
69
|
+
).with_context(
|
70
|
+
handler_name: current_cop.handler_name,
|
71
|
+
type: cop_type
|
72
|
+
)
|
73
|
+
AddScannerCommand.call(
|
74
|
+
current_config,
|
75
|
+
resource_config,
|
76
|
+
form
|
77
|
+
) do |on|
|
78
|
+
on(:invalid) { flash[:alert] = "Can not create the agent" }
|
79
|
+
on(:ok) { flash[:notice] = "Agent has been created" }
|
80
|
+
redirect_to spam_filter_reports_path
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def resource_config
|
85
|
+
raise Error, "Not implemented"
|
86
|
+
end
|
87
|
+
private
|
88
|
+
def available_cops
|
89
|
+
cop_repository.strategies.map do |cop, copKlass|
|
90
|
+
cop_repository.strategy cop
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def cop_repository
|
95
|
+
Decidim::SpamSignal::Cops::CopsRepository.instance
|
96
|
+
end
|
97
|
+
|
98
|
+
def current_settings
|
99
|
+
resource_config
|
100
|
+
end
|
101
|
+
def cop_type
|
102
|
+
params.permit(:id)["id"] || nil
|
103
|
+
end
|
104
|
+
def cop_key
|
105
|
+
params.permit(:cop)["cop"] || nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def current_cop
|
109
|
+
return nil unless cop_type && cop_key
|
110
|
+
cop_repository.strategy(cop_key)
|
111
|
+
end
|
112
|
+
|
113
|
+
def current_config
|
114
|
+
@current_config ||= Decidim::SpamSignal::Config.where(
|
115
|
+
id: params.require(:config_id),
|
116
|
+
organization: current_organization
|
117
|
+
).first!
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|