From 815aed34ae0404438f41d48ff640ad3c810b6155 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Tue, 2 Jul 2024 11:04:54 -0300 Subject: [PATCH] DEV: Modernize the Antivirus plugin. (#59) * DEV: Modernize the Antivirus plugin. Autoload files, and annotate models. * Use new plugin show route * DEV: Fix template If there is only a top level route for the admin show for the plugin, it will not be an `index` route, it will just be the route name itself as the top level. * Fix build and add styles to template --------- Co-authored-by: Martin Brennan --- .rubocop.yml | 2 +- ...-plugins-show-discourse-antivirus-stats.js | 8 ++++ .../show/discourse-antivirus-stats.hbs | 48 +++++++++++++++++++ .../admin/antivirus_controller.rb | 15 ++++++ .../antivirus_controller.rb | 13 ----- .../jobs}/scheduled/create_scanned_uploads.rb | 2 +- .../scheduled/fetch_antivirus_version.rb | 2 +- .../scheduled/flag_quarantined_uploads.rb | 0 .../remove_orphaned_scanned_uploads.rb | 0 {jobs => app/jobs}/scheduled/scan_batch.rb | 2 +- {models => app/models}/reviewable_upload.rb | 37 ++++++++++++++ {models => app/models}/scanned_upload.rb | 20 ++++++++ .../enable_discourse_antivirus_validator.rb | 19 ++++++++ ...in-discourse-antivirus-plugin-route-map.js | 8 ++++ .../discourse/antivirus-route-map.js | 8 ---- .../admin-plugin-configuration-nav.js | 26 ++++++++++ .../routes/admin-plugins-antivirus.js | 17 ------- .../templates/admin/plugins-antivirus.hbs | 43 ----------------- assets/stylesheets/antivirus-stats.scss | 9 ++++ config/locales/client.en.yml | 2 + config/routes.rb | 7 +-- config/settings.yml | 2 +- lib/discourse_antivirus/background_scan.rb | 2 +- .../{clamav.rb => clam_av.rb} | 4 +- ...lth_metric.rb => clam_av_health_metric.rb} | 4 +- .../{clamav_service.rb => clam_av_service.rb} | 2 +- ...vices_pool.rb => clam_av_services_pool.rb} | 4 +- lib/discourse_antivirus/engine.rb | 13 ++--- lib/discourse_antivirus_constraint.rb | 6 --- .../enable_discourse_antivirus_validator.rb | 17 ------- plugin.rb | 35 +++++--------- .../background_scan_spec.rb | 16 +++---- spec/lib/discourse_antivirus/clamav_spec.rb | 2 +- spec/plugin_spec.rb | 4 +- spec/support/fake_pool.rb | 2 +- 35 files changed, 237 insertions(+), 164 deletions(-) create mode 100644 admin/assets/javascripts/discourse/routes/admin-plugins-show-discourse-antivirus-stats.js create mode 100644 admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-antivirus-stats.hbs create mode 100644 app/controllers/discourse_antivirus/admin/antivirus_controller.rb delete mode 100644 app/controllers/discourse_antivirus/antivirus_controller.rb rename {jobs => app/jobs}/scheduled/create_scanned_uploads.rb (91%) rename {jobs => app/jobs}/scheduled/fetch_antivirus_version.rb (78%) rename {jobs => app/jobs}/scheduled/flag_quarantined_uploads.rb (100%) rename {jobs => app/jobs}/scheduled/remove_orphaned_scanned_uploads.rb (100%) rename {jobs => app/jobs}/scheduled/scan_batch.rb (85%) rename {models => app/models}/reviewable_upload.rb (58%) rename {models => app/models}/scanned_upload.rb (80%) create mode 100644 app/validators/discourse_antivirus/enable_discourse_antivirus_validator.rb create mode 100644 assets/javascripts/discourse/admin-discourse-antivirus-plugin-route-map.js delete mode 100644 assets/javascripts/discourse/antivirus-route-map.js create mode 100644 assets/javascripts/discourse/initializers/admin-plugin-configuration-nav.js delete mode 100644 assets/javascripts/discourse/routes/admin-plugins-antivirus.js delete mode 100644 assets/javascripts/discourse/templates/admin/plugins-antivirus.hbs create mode 100644 assets/stylesheets/antivirus-stats.scss rename lib/discourse_antivirus/{clamav.rb => clam_av.rb} (97%) rename lib/discourse_antivirus/{clamav_health_metric.rb => clam_av_health_metric.rb} (86%) rename lib/discourse_antivirus/{clamav_service.rb => clam_av_service.rb} (98%) rename lib/discourse_antivirus/{clamav_services_pool.rb => clam_av_services_pool.rb} (91%) delete mode 100644 lib/discourse_antivirus_constraint.rb delete mode 100644 lib/validators/enable_discourse_antivirus_validator.rb diff --git a/.rubocop.yml b/.rubocop.yml index d9dee42..fb14dfa 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,2 +1,2 @@ inherit_gem: - rubocop-discourse: stree-compat.yml \ No newline at end of file + rubocop-discourse: stree-compat.yml diff --git a/admin/assets/javascripts/discourse/routes/admin-plugins-show-discourse-antivirus-stats.js b/admin/assets/javascripts/discourse/routes/admin-plugins-show-discourse-antivirus-stats.js new file mode 100644 index 0000000..46db9dd --- /dev/null +++ b/admin/assets/javascripts/discourse/routes/admin-plugins-show-discourse-antivirus-stats.js @@ -0,0 +1,8 @@ +import { ajax } from "discourse/lib/ajax"; +import DiscourseRoute from "discourse/routes/discourse"; + +export default class DiscourseAntivirusStatsRoute extends DiscourseRoute { + model() { + return ajax("/admin/plugins/discourse-antivirus/stats"); + } +} diff --git a/admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-antivirus-stats.hbs b/admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-antivirus-stats.hbs new file mode 100644 index 0000000..683a526 --- /dev/null +++ b/admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-antivirus-stats.hbs @@ -0,0 +1,48 @@ +
+
+

{{i18n "antivirus.stats.title"}}

+
+ + + + + + + + + + + {{#each this.model.versions as |version|}} + + + + + + {{/each}} + +
{{i18n "antivirus.version"}}{{i18n "antivirus.database_version"}}{{i18n "antivirus.database_updated_at"}}
{{version.antivirus}}{{version.database}}{{version.updated_at}}
+ +
+

{{i18n "antivirus.stats.data"}}

+
+ + + + + + + + + + + + + + + + + + +
{{i18n "antivirus.stats.total_scans"}}{{i18n "antivirus.stats.recently_scanned"}}{{i18n "antivirus.stats.quarantined"}}{{i18n "antivirus.stats.found"}}
{{this.model.stats.scans}}{{this.model.stats.recently_scanned}}{{this.model.stats.quarantined}}{{this.model.stats.found}}
+ +
\ No newline at end of file diff --git a/app/controllers/discourse_antivirus/admin/antivirus_controller.rb b/app/controllers/discourse_antivirus/admin/antivirus_controller.rb new file mode 100644 index 0000000..d3733a3 --- /dev/null +++ b/app/controllers/discourse_antivirus/admin/antivirus_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module DiscourseAntivirus + module Admin + class AntivirusController < ::Admin::AdminController + requires_plugin ::DiscourseAntivirus::PLUGIN_NAME + + def index + antivirus = DiscourseAntivirus::ClamAv.instance + + render json: DiscourseAntivirus::BackgroundScan.new(antivirus).stats + end + end + end +end diff --git a/app/controllers/discourse_antivirus/antivirus_controller.rb b/app/controllers/discourse_antivirus/antivirus_controller.rb deleted file mode 100644 index dacfcf8..0000000 --- a/app/controllers/discourse_antivirus/antivirus_controller.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module DiscourseAntivirus - class AntivirusController < Admin::AdminController - requires_plugin "discourse-antivirus" - - def index - antivirus = DiscourseAntivirus::ClamAV.instance - - render json: DiscourseAntivirus::BackgroundScan.new(antivirus).stats - end - end -end diff --git a/jobs/scheduled/create_scanned_uploads.rb b/app/jobs/scheduled/create_scanned_uploads.rb similarity index 91% rename from jobs/scheduled/create_scanned_uploads.rb rename to app/jobs/scheduled/create_scanned_uploads.rb index 2d0c814..70b9b1b 100644 --- a/jobs/scheduled/create_scanned_uploads.rb +++ b/app/jobs/scheduled/create_scanned_uploads.rb @@ -7,7 +7,7 @@ class CreateScannedUploads < ::Jobs::Scheduled def execute(_args) return unless SiteSetting.discourse_antivirus_enabled? - scanner = DiscourseAntivirus::BackgroundScan.new(DiscourseAntivirus::ClamAV.instance) + scanner = DiscourseAntivirus::BackgroundScan.new(DiscourseAntivirus::ClamAv.instance) scanner.queue_batch end end diff --git a/jobs/scheduled/fetch_antivirus_version.rb b/app/jobs/scheduled/fetch_antivirus_version.rb similarity index 78% rename from jobs/scheduled/fetch_antivirus_version.rb rename to app/jobs/scheduled/fetch_antivirus_version.rb index 2e0e93a..64a9b4a 100644 --- a/jobs/scheduled/fetch_antivirus_version.rb +++ b/app/jobs/scheduled/fetch_antivirus_version.rb @@ -7,7 +7,7 @@ class FetchAntivirusVersion < ::Jobs::Scheduled def execute(_args) return unless SiteSetting.discourse_antivirus_enabled? - DiscourseAntivirus::ClamAV.instance.update_versions + DiscourseAntivirus::ClamAv.instance.update_versions end end end diff --git a/jobs/scheduled/flag_quarantined_uploads.rb b/app/jobs/scheduled/flag_quarantined_uploads.rb similarity index 100% rename from jobs/scheduled/flag_quarantined_uploads.rb rename to app/jobs/scheduled/flag_quarantined_uploads.rb diff --git a/jobs/scheduled/remove_orphaned_scanned_uploads.rb b/app/jobs/scheduled/remove_orphaned_scanned_uploads.rb similarity index 100% rename from jobs/scheduled/remove_orphaned_scanned_uploads.rb rename to app/jobs/scheduled/remove_orphaned_scanned_uploads.rb diff --git a/jobs/scheduled/scan_batch.rb b/app/jobs/scheduled/scan_batch.rb similarity index 85% rename from jobs/scheduled/scan_batch.rb rename to app/jobs/scheduled/scan_batch.rb index 0692f73..c13bf48 100644 --- a/jobs/scheduled/scan_batch.rb +++ b/app/jobs/scheduled/scan_batch.rb @@ -7,7 +7,7 @@ class ScanBatch < ::Jobs::Scheduled def execute(_args) return unless SiteSetting.discourse_antivirus_enabled? - antivirus = DiscourseAntivirus::ClamAV.instance + antivirus = DiscourseAntivirus::ClamAv.instance return unless antivirus.accepting_connections? DiscourseAntivirus::BackgroundScan.new(antivirus).scan_batch diff --git a/models/reviewable_upload.rb b/app/models/reviewable_upload.rb similarity index 58% rename from models/reviewable_upload.rb rename to app/models/reviewable_upload.rb index b15c843..dd11121 100644 --- a/models/reviewable_upload.rb +++ b/app/models/reviewable_upload.rb @@ -89,3 +89,40 @@ def build_action(actions, id, icon:, bundle: nil, confirm: false, button_class: end end end + +# == Schema Information +# +# Table name: reviewables +# +# id :bigint not null, primary key +# type :string not null +# status :integer default("pending"), not null +# created_by_id :integer not null +# reviewable_by_moderator :boolean default(FALSE), not null +# reviewable_by_group_id :integer +# category_id :integer +# topic_id :integer +# score :float default(0.0), not null +# potential_spam :boolean default(FALSE), not null +# target_id :integer +# target_type :string +# target_created_by_id :integer +# payload :json +# version :integer default(0), not null +# latest_score :datetime +# created_at :datetime not null +# updated_at :datetime not null +# force_review :boolean default(FALSE), not null +# reject_reason :text +# +# Indexes +# +# idx_reviewables_score_desc_created_at_desc (score,created_at) +# index_reviewables_on_reviewable_by_group_id (reviewable_by_group_id) +# index_reviewables_on_status_and_created_at (status,created_at) +# index_reviewables_on_status_and_score (status,score) +# index_reviewables_on_status_and_type (status,type) +# index_reviewables_on_target_id_where_post_type_eq_post (target_id) WHERE ((target_type)::text = 'Post'::text) +# index_reviewables_on_topic_id_and_status_and_created_by_id (topic_id,status,created_by_id) +# index_reviewables_on_type_and_target_id (type,target_id) UNIQUE +# diff --git a/models/scanned_upload.rb b/app/models/scanned_upload.rb similarity index 80% rename from models/scanned_upload.rb rename to app/models/scanned_upload.rb index 05fbb2f..edf7787 100644 --- a/models/scanned_upload.rb +++ b/app/models/scanned_upload.rb @@ -92,3 +92,23 @@ def handle_scan_result(result) result[:found] ? move_to_quarantine!(result[:message]) : save! end end + +# == Schema Information +# +# Table name: scanned_uploads +# +# id :bigint not null, primary key +# upload_id :integer +# next_scan_at :datetime +# quarantined :boolean default(FALSE), not null +# scans :integer default(0), not null +# virus_database_version_used :integer +# created_at :datetime not null +# updated_at :datetime not null +# last_scan_failed :boolean default(FALSE), not null +# scan_result :string +# +# Indexes +# +# index_scanned_uploads_on_upload_id (upload_id) UNIQUE +# diff --git a/app/validators/discourse_antivirus/enable_discourse_antivirus_validator.rb b/app/validators/discourse_antivirus/enable_discourse_antivirus_validator.rb new file mode 100644 index 0000000..b70f59b --- /dev/null +++ b/app/validators/discourse_antivirus/enable_discourse_antivirus_validator.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module DiscourseAntivirus + class EnableDiscourseAntivirusValidator + def initialize(opts = {}) + @opts = opts + end + + def valid_value?(val) + return true if val == "f" + + DiscourseAntivirus::ClamAv.correctly_configured? + end + + def error_message + I18n.t("site_settings.errors.antivirus_srv_record_required") + end + end +end diff --git a/assets/javascripts/discourse/admin-discourse-antivirus-plugin-route-map.js b/assets/javascripts/discourse/admin-discourse-antivirus-plugin-route-map.js new file mode 100644 index 0000000..062aedd --- /dev/null +++ b/assets/javascripts/discourse/admin-discourse-antivirus-plugin-route-map.js @@ -0,0 +1,8 @@ +export default { + resource: "admin.adminPlugins.show", + path: "/plugins", + + map() { + this.route("discourse-antivirus-stats", { path: "stats" }); + }, +}; diff --git a/assets/javascripts/discourse/antivirus-route-map.js b/assets/javascripts/discourse/antivirus-route-map.js deleted file mode 100644 index eb15794..0000000 --- a/assets/javascripts/discourse/antivirus-route-map.js +++ /dev/null @@ -1,8 +0,0 @@ -export default { - resource: "admin.adminPlugins", - path: "/plugins", - - map() { - this.route("antivirus"); - }, -}; diff --git a/assets/javascripts/discourse/initializers/admin-plugin-configuration-nav.js b/assets/javascripts/discourse/initializers/admin-plugin-configuration-nav.js new file mode 100644 index 0000000..9798055 --- /dev/null +++ b/assets/javascripts/discourse/initializers/admin-plugin-configuration-nav.js @@ -0,0 +1,26 @@ +import { PLUGIN_NAV_MODE_TOP } from "discourse/lib/admin-plugin-config-nav"; +import { withPluginApi } from "discourse/lib/plugin-api"; + +export default { + name: "discourse-antivirus-admin-plugin-configuration-nav", + + initialize(container) { + const currentUser = container.lookup("service:current-user"); + if (!currentUser || !currentUser.admin) { + return; + } + + withPluginApi("1.1.0", (api) => { + api.addAdminPluginConfigurationNav( + "discourse-antivirus", + PLUGIN_NAV_MODE_TOP, + [ + { + label: "antivirus.stats.title", + route: "adminPlugins.show.discourse-antivirus-stats", + }, + ] + ); + }); + }, +}; diff --git a/assets/javascripts/discourse/routes/admin-plugins-antivirus.js b/assets/javascripts/discourse/routes/admin-plugins-antivirus.js deleted file mode 100644 index f1e6761..0000000 --- a/assets/javascripts/discourse/routes/admin-plugins-antivirus.js +++ /dev/null @@ -1,17 +0,0 @@ -import Route from "@ember/routing/route"; -import { ajax } from "discourse/lib/ajax"; - -export default Route.extend({ - controllerName: "admin-plugins-antivirus", - - model() { - return ajax("/admin/plugins/antivirus"); - }, - - setupController(controller, model) { - controller.setProperties({ - model, - background_scan_stats: model.background_scan_stats, - }); - }, -}); diff --git a/assets/javascripts/discourse/templates/admin/plugins-antivirus.hbs b/assets/javascripts/discourse/templates/admin/plugins-antivirus.hbs deleted file mode 100644 index 4f2b263..0000000 --- a/assets/javascripts/discourse/templates/admin/plugins-antivirus.hbs +++ /dev/null @@ -1,43 +0,0 @@ -

{{i18n "antivirus.version_title"}}

- - - - - - - - - - - {{#each model.versions as |version|}} - - - - - - {{/each}} - -
{{i18n "antivirus.version"}}{{i18n "antivirus.database_version"}}{{i18n "antivirus.database_updated_at"}}
{{version.antivirus}}{{version.database}}{{version.updated_at}}
- -
- -

{{i18n "antivirus.stats_title"}}

- - - - - - - - - - - - - - - - - - -
{{i18n "antivirus.stats.total_scans"}}{{i18n "antivirus.stats.recently_scanned"}}{{i18n "antivirus.stats.quarantined"}}{{i18n "antivirus.stats.found"}}
{{background_scan_stats.scans}}{{background_scan_stats.recently_scanned}}{{background_scan_stats.quarantined}}{{background_scan_stats.found}}
\ No newline at end of file diff --git a/assets/stylesheets/antivirus-stats.scss b/assets/stylesheets/antivirus-stats.scss new file mode 100644 index 0000000..bb6a7de --- /dev/null +++ b/assets/stylesheets/antivirus-stats.scss @@ -0,0 +1,9 @@ +.antivirus-stats { + &__sub-header { + margin-top: 15px; + } + + &__header { + margin-bottom: 5px; + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 596976e..a7b0bcc 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -19,6 +19,8 @@ en: clamav_unavailable: We cannot establish a connection with the antivirus software. File scanning will be temporarily disabled. stats: + title: Stats + data: Scan results total_scans: Scanned Files recently_scanned: Recently Scanned quarantined: Quarantined diff --git a/config/routes.rb b/config/routes.rb index 3f0495e..4ab033e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -DiscourseAntivirus::Engine.routes.draw do - root to: "antivirus#index" - get "/stats" => "antivirus#index" +Discourse::Application.routes.draw do + scope "/admin/plugins/discourse-antivirus", constraints: AdminConstraint.new do + get "/stats" => "discourse_antivirus/admin/antivirus#index" + end end diff --git a/config/settings.yml b/config/settings.yml index c76f9fe..cee25c5 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -1,7 +1,7 @@ plugins: discourse_antivirus_enabled: default: false - validator: EnableDiscourseAntivirusValidator + validator: DiscourseAntivirus::EnableDiscourseAntivirusValidator antivirus_live_scan_images: default: false antivirus_srv_record: diff --git a/lib/discourse_antivirus/background_scan.rb b/lib/discourse_antivirus/background_scan.rb index e6d0e74..046d736 100644 --- a/lib/discourse_antivirus/background_scan.rb +++ b/lib/discourse_antivirus/background_scan.rb @@ -17,7 +17,7 @@ def stats { versions: @antivirus.versions, - background_scan_stats: { + stats: { scans: scanned_upload_stats[0] || 0, recently_scanned: scanned_upload_stats[1] || 0, quarantined: scanned_upload_stats[2] || 0, diff --git a/lib/discourse_antivirus/clamav.rb b/lib/discourse_antivirus/clam_av.rb similarity index 97% rename from lib/discourse_antivirus/clamav.rb rename to lib/discourse_antivirus/clam_av.rb index 797b013..da7f392 100644 --- a/lib/discourse_antivirus/clamav.rb +++ b/lib/discourse_antivirus/clam_av.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module DiscourseAntivirus - class ClamAV + class ClamAv VIRUS_FOUND = Class.new(StandardError) PLUGIN_NAME = "discourse-antivirus" STORE_KEY = "clamav-versions" @@ -9,7 +9,7 @@ class ClamAV UNAVAILABLE = "unavailable" def self.instance - new(Discourse.store, DiscourseAntivirus::ClamAVServicesPool.new) + new(Discourse.store, DiscourseAntivirus::ClamAvServicesPool.new) end def self.correctly_configured? diff --git a/lib/discourse_antivirus/clamav_health_metric.rb b/lib/discourse_antivirus/clam_av_health_metric.rb similarity index 86% rename from lib/discourse_antivirus/clamav_health_metric.rb rename to lib/discourse_antivirus/clam_av_health_metric.rb index 90dbd09..2bd1f55 100644 --- a/lib/discourse_antivirus/clamav_health_metric.rb +++ b/lib/discourse_antivirus/clam_av_health_metric.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module DiscourseAntivirus - class ClamAVHealthMetric < ::DiscoursePrometheus::InternalMetric::Custom + class ClamAvHealthMetric < ::DiscoursePrometheus::InternalMetric::Custom attribute :name, :labels, :description, :value, :type def initialize @@ -15,7 +15,7 @@ def collect last_check = @@clamav_stats[:last_check] if (!last_check || should_recheck?(last_check)) - antivirus = DiscourseAntivirus::ClamAV.instance + antivirus = DiscourseAntivirus::ClamAv.instance available = antivirus.accepting_connections? ? 1 : 0 @@clamav_stats[:status] = available diff --git a/lib/discourse_antivirus/clamav_service.rb b/lib/discourse_antivirus/clam_av_service.rb similarity index 98% rename from lib/discourse_antivirus/clamav_service.rb rename to lib/discourse_antivirus/clam_av_service.rb index ef4f9cf..bc21f02 100644 --- a/lib/discourse_antivirus/clamav_service.rb +++ b/lib/discourse_antivirus/clam_av_service.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module DiscourseAntivirus - class ClamAVService + class ClamAvService def initialize(connection_factory, hostname, port) @connection_factory = connection_factory @hostname = hostname diff --git a/lib/discourse_antivirus/clamav_services_pool.rb b/lib/discourse_antivirus/clam_av_services_pool.rb similarity index 91% rename from lib/discourse_antivirus/clamav_services_pool.rb rename to lib/discourse_antivirus/clam_av_services_pool.rb index 0246b6d..81057e3 100644 --- a/lib/discourse_antivirus/clamav_services_pool.rb +++ b/lib/discourse_antivirus/clam_av_services_pool.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module DiscourseAntivirus - class ClamAVServicesPool + class ClamAvServicesPool def online_services instances.select(&:online?) end @@ -31,7 +31,7 @@ def instances @instances ||= servers .filter { |server| server&.hostname.present? && server&.port.present? } - .map { |server| ClamAVService.new(connection_factory, server.hostname, server.port) } + .map { |server| ClamAvService.new(connection_factory, server.hostname, server.port) } end def servers diff --git a/lib/discourse_antivirus/engine.rb b/lib/discourse_antivirus/engine.rb index a415e60..6d2f108 100644 --- a/lib/discourse_antivirus/engine.rb +++ b/lib/discourse_antivirus/engine.rb @@ -1,16 +1,9 @@ # frozen_string_literal: true -module DiscourseAntivirus +module ::DiscourseAntivirus class Engine < ::Rails::Engine - engine_name "discourse-antivirus" + engine_name PLUGIN_NAME isolate_namespace DiscourseAntivirus - - config.after_initialize do - Discourse::Application.routes.append do - mount ::DiscourseAntivirus::Engine, - at: "/admin/plugins/antivirus", - constraints: AdminConstraint.new - end - end + config.autoload_paths << File.join(config.root, "lib") end end diff --git a/lib/discourse_antivirus_constraint.rb b/lib/discourse_antivirus_constraint.rb deleted file mode 100644 index 7ce5f79..0000000 --- a/lib/discourse_antivirus_constraint.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true -class DiscourseAntivirusConstraint - def matches?(request) - SiteSetting.discourse_antivirus_enabled - end -end diff --git a/lib/validators/enable_discourse_antivirus_validator.rb b/lib/validators/enable_discourse_antivirus_validator.rb deleted file mode 100644 index 95cfff4..0000000 --- a/lib/validators/enable_discourse_antivirus_validator.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -class EnableDiscourseAntivirusValidator - def initialize(opts = {}) - @opts = opts - end - - def valid_value?(val) - return true if val == "f" - - DiscourseAntivirus::ClamAV.correctly_configured? - end - - def error_message - I18n.t("site_settings.errors.antivirus_srv_record_required") - end -end diff --git a/plugin.rb b/plugin.rb index b1e5538..5d03e91 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-antivirus -# about: Scan uploads +# about: Scan your Discourse uploads using ClamAV # version: 0.1 # authors: romanrizzi # url: https://github.com/discourse/discourse-antivirus @@ -9,28 +9,19 @@ gem "dns-sd", "0.1.3" enabled_site_setting :discourse_antivirus_enabled + register_asset "stylesheets/reviewable-upload.scss" +register_asset "stylesheets/antivirus-stats.scss" + +module ::DiscourseAntivirus + PLUGIN_NAME = "discourse-antivirus" +end require_relative "lib/discourse_antivirus/engine" -require_relative "lib/validators/enable_discourse_antivirus_validator" -add_admin_route "antivirus.title", "antivirus" +add_admin_route("antivirus.title", "discourse-antivirus", { use_new_show_route: true }) after_initialize do - require_relative "app/controllers/discourse_antivirus/antivirus_controller.rb" - require_relative "lib/discourse_antivirus/clamav_services_pool.rb" - require_relative "lib/discourse_antivirus/clamav_service.rb" - require_relative "lib/discourse_antivirus/clamav.rb" - require_relative "lib/discourse_antivirus/background_scan.rb" - require_relative "models/scanned_upload.rb" - require_relative "models/reviewable_upload.rb" - require_relative "serializers/reviewable_upload_serializer.rb" - require_relative "jobs/scheduled/scan_batch.rb" - require_relative "jobs/scheduled/create_scanned_uploads.rb" - require_relative "jobs/scheduled/fetch_antivirus_version.rb" - require_relative "jobs/scheduled/remove_orphaned_scanned_uploads.rb" - require_relative "jobs/scheduled/flag_quarantined_uploads.rb" - register_reviewable_type ReviewableUpload add_to_serializer( @@ -40,8 +31,8 @@ include_condition: -> { SiteSetting.discourse_antivirus_enabled? && scope.is_staff? }, ) do !!PluginStore.get( - DiscourseAntivirus::ClamAV::PLUGIN_NAME, - DiscourseAntivirus::ClamAV::UNAVAILABLE, + DiscourseAntivirus::ClamAv::PLUGIN_NAME, + DiscourseAntivirus::ClamAv::UNAVAILABLE, ) end @@ -53,7 +44,7 @@ should_scan_file = !upload.for_export && (!is_image || SiteSetting.antivirus_live_scan_images) if validate && should_scan_file && upload.valid? - antivirus = DiscourseAntivirus::ClamAV.instance + antivirus = DiscourseAntivirus::ClamAv.instance response = antivirus.scan_file(file) is_positive = response[:found] @@ -63,9 +54,9 @@ end if defined?(::DiscoursePrometheus) - require_relative "lib/discourse_antivirus/clamav_health_metric.rb" + require_relative "lib/discourse_antivirus/clam_av_health_metric.rb" - DiscoursePluginRegistry.register_global_collector(DiscourseAntivirus::ClamAVHealthMetric, self) + DiscoursePluginRegistry.register_global_collector(DiscourseAntivirus::ClamAvHealthMetric, self) end add_reviewable_score_link(:malicious_file, "plugin:discourse-antivirus") diff --git a/spec/lib/discourse_antivirus/background_scan_spec.rb b/spec/lib/discourse_antivirus/background_scan_spec.rb index 40b3358..4cedec9 100644 --- a/spec/lib/discourse_antivirus/background_scan_spec.rb +++ b/spec/lib/discourse_antivirus/background_scan_spec.rb @@ -15,8 +15,8 @@ updated_at: "Wed Jun 24 10:13:27 2020", } PluginStore.set( - DiscourseAntivirus::ClamAV::PLUGIN_NAME, - DiscourseAntivirus::ClamAV::STORE_KEY, + DiscourseAntivirus::ClamAv::PLUGIN_NAME, + DiscourseAntivirus::ClamAv::STORE_KEY, [version_data], ) end @@ -55,7 +55,7 @@ .with(upload, max_file_size_kb: filesize) .raises(OpenURI::HTTPError.new("forbidden", nil)) - antivirus = DiscourseAntivirus::ClamAV.new(store, build_fake_pool(socket)) + antivirus = DiscourseAntivirus::ClamAv.new(store, build_fake_pool(socket)) scanner = described_class.new(antivirus) scanned_upload = ScannedUpload.create_new!(upload) @@ -63,7 +63,7 @@ scanned_upload.reload expect(scanned_upload.scans).to eq(0) - expect(scanned_upload.scan_result).to eq(DiscourseAntivirus::ClamAV::DOWNLOAD_FAILED) + expect(scanned_upload.scan_result).to eq(DiscourseAntivirus::ClamAv::DOWNLOAD_FAILED) expect(scanned_upload.next_scan_at).to be_present expect(scanned_upload.last_scan_failed).to eq(true) end @@ -75,7 +75,7 @@ filesize = upload.filesize + 2.megabytes store.expects(:download).with(upload, max_file_size_kb: filesize).returns(nil) - antivirus = DiscourseAntivirus::ClamAV.new(store, build_fake_pool(socket)) + antivirus = DiscourseAntivirus::ClamAv.new(store, build_fake_pool(socket)) scanner = described_class.new(antivirus) scanned_upload = ScannedUpload.create_new!(upload) @@ -83,7 +83,7 @@ scanned_upload.reload expect(scanned_upload.scans).to eq(0) - expect(scanned_upload.scan_result).to eq(DiscourseAntivirus::ClamAV::DOWNLOAD_FAILED) + expect(scanned_upload.scan_result).to eq(DiscourseAntivirus::ClamAv::DOWNLOAD_FAILED) expect(scanned_upload.next_scan_at).to be_present expect(scanned_upload.last_scan_failed).to eq(true) end @@ -251,7 +251,7 @@ def create_scanned_upload(database_version: db_version, next_scan_at: nil) end def get_stats(stat) - build_scanner.stats.dig(:background_scan_stats, stat) + build_scanner.stats.dig(:stats, stat) end def create_scanned_upload(updated_at: 6.hours.ago, quarantined: false, scans: 0) @@ -272,7 +272,7 @@ def build_fake_pool(socket) def build_scanner(quarantine_files: false) IO.stubs(:select) socket = quarantine_files ? FakeTCPSocket.positive : FakeTCPSocket.negative - antivirus = DiscourseAntivirus::ClamAV.new(Discourse.store, build_fake_pool(socket)) + antivirus = DiscourseAntivirus::ClamAv.new(Discourse.store, build_fake_pool(socket)) described_class.new(antivirus) end end diff --git a/spec/lib/discourse_antivirus/clamav_spec.rb b/spec/lib/discourse_antivirus/clamav_spec.rb index da037b5..e426513 100644 --- a/spec/lib/discourse_antivirus/clamav_spec.rb +++ b/spec/lib/discourse_antivirus/clamav_spec.rb @@ -4,7 +4,7 @@ require_relative "../../support/fake_pool" require_relative "../../support/fake_tcp_socket" -describe DiscourseAntivirus::ClamAV do +describe DiscourseAntivirus::ClamAv do fab!(:upload) { Fabricate(:image_upload) } let(:file) { File.open(Discourse.store.path_for(upload)) } diff --git a/spec/plugin_spec.rb b/spec/plugin_spec.rb index 948582b..8a865c3 100644 --- a/spec/plugin_spec.rb +++ b/spec/plugin_spec.rb @@ -108,7 +108,7 @@ def mock_antivirus(socket) IO.stubs(:select).returns(true) pool = FakePool.new([FakeTCPSocket.online, socket]) - antivirus = DiscourseAntivirus::ClamAV.new(Discourse.store, pool) - DiscourseAntivirus::ClamAV.expects(:instance).returns(antivirus) + antivirus = DiscourseAntivirus::ClamAv.new(Discourse.store, pool) + DiscourseAntivirus::ClamAv.expects(:instance).returns(antivirus) end end diff --git a/spec/support/fake_pool.rb b/spec/support/fake_pool.rb index 5adf860..9d7944f 100644 --- a/spec/support/fake_pool.rb +++ b/spec/support/fake_pool.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class FakePool < DiscourseAntivirus::ClamAVServicesPool +class FakePool < DiscourseAntivirus::ClamAvServicesPool def initialize(sockets) @sockets = sockets @connections = 0