MDL-50887 antivirus: Add antivirus plugin infrastructure.

This commit is contained in:
Ruslan Kabalin
2016-02-25 09:54:05 +00:00
parent 03b8b55f10
commit 146eeb7651
9 changed files with 580 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Allows admin to configure antiviruses.
*
* @package core_antivirus
* @copyright 2015 Ruslan Kabalin, Lancaster University.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/tablelib.php');
$action = required_param('action', PARAM_ALPHANUMEXT);
$antivirus = required_param('antivirus', PARAM_PLUGIN);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/antiviruses.php', array('action'=>$action, 'antivirus'=>$antivirus));
$PAGE->set_context(context_system::instance());
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageantiviruses";
// Get currently installed and enabled antivirus plugins.
$available_antiviruses = antiviruses_get_available();
if (!empty($antivirus) and empty($available_antiviruses[$antivirus])) {
redirect ($returnurl);
}
$active_antiviruses = explode(',', $CFG->antiviruses);
foreach ($active_antiviruses as $key=>$active) {
if (empty($available_antiviruses[$active])) {
unset($active_antiviruses[$key]);
}
}
if (!confirm_sesskey()) {
redirect($returnurl);
}
switch ($action) {
case 'disable':
// Remove from enabled list.
$key = array_search($antivirus, $active_antiviruses);
unset($active_antiviruses[$key]);
break;
case 'enable':
// Add to enabled list.
if (!in_array($antivirus, $active_antiviruses)) {
$active_antiviruses[] = $antivirus;
$active_antiviruses = array_unique($active_antiviruses);
}
break;
case 'down':
$key = array_search($antivirus, $active_antiviruses);
// Check auth plugin is valid.
if ($key !== false) {
// move down the list
if ($key < (count($active_antiviruses) - 1)) {
$fsave = $active_antiviruses[$key];
$active_antiviruses[$key] = $active_antiviruses[$key + 1];
$active_antiviruses[$key + 1] = $fsave;
}
}
break;
case 'up':
$key = array_search($antivirus, $active_antiviruses);
// Check auth is valid.
if ($key !== false) {
// move up the list
if ($key >= 1) {
$fsave = $active_antiviruses[$key];
$active_antiviruses[$key] = $active_antiviruses[$key - 1];
$active_antiviruses[$key - 1] = $fsave;
}
}
break;
default:
break;
}
set_config('antiviruses', implode(',', $active_antiviruses));
core_plugin_manager::reset_caches();
redirect ($returnurl);
+10
View File
@@ -138,6 +138,16 @@ if ($hassiteconfig) {
$plugin->load_settings($ADMIN, 'editorsettings', $hassiteconfig);
}
/// Antivirus plugins
$ADMIN->add('modules', new admin_category('antivirussettings', new lang_string('antiviruses', 'antivirus')));
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
$temp->add(new admin_setting_manageantiviruses());
$ADMIN->add('antivirussettings', $temp);
foreach (core_plugin_manager::instance()->get_plugins_of_type('antivirus') as $plugin) {
/** @var \core\plugininfo\antivirus $plugin */
$plugin->load_settings($ADMIN, 'antivirussettings', $hassiteconfig);
}
/// License types
$ADMIN->add('modules', new admin_category('licensesettings', new lang_string('licenses')));
$temp = new admin_settingpage('managelicenses', new lang_string('managelicenses', 'admin'));
+28
View File
@@ -0,0 +1,28 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component 'antivirus', language 'en'
*
* @package core_antivirus
* @copyright 2015 Ruslan Kabalin, Lancaster University.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['actantivirushdr'] = 'Available antiviruses';
$string['antiviruses'] = 'Antiviruses';
$string['antivirussettings'] = 'Manage antiviruses';
$string['configantivirusplugins'] = 'Please choose the antivirus plugins you wish to use and arrange them in order of being applied.';
+173
View File
@@ -6494,6 +6494,179 @@ class admin_setting_manageeditors extends admin_setting {
}
}
/**
* Special class for antiviruses administration.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_manageantiviruses extends admin_setting {
/**
* Calls parent::__construct with specific arguments
*/
public function __construct() {
$this->nosave = true;
parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', '');
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_setting() {
return true;
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_defaultsetting() {
return true;
}
/**
* Always returns '', does not write anything
*
* @return string Always returns ''
*/
public function write_setting($data) {
// do not write any setting
return '';
}
/**
* Checks if $query is one of the available editors
*
* @param string $query The string to search for
* @return bool Returns true if found, false if not
*/
public function is_related($query) {
if (parent::is_related($query)) {
return true;
}
$antiviruses_available = antiviruses_get_available();
foreach ($antiviruses_available as $antivirus=>$antivirusstr) {
if (strpos($antivirus, $query) !== false) {
return true;
}
if (strpos(core_text::strtolower($antivirusstr), $query) !== false) {
return true;
}
}
return false;
}
/**
* Builds the XHTML to display the control
*
* @param string $data Unused
* @param string $query
* @return string
*/
public function output_html($data, $query='') {
global $CFG, $OUTPUT;
// display strings
$txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
'up', 'down', 'none'));
$struninstall = get_string('uninstallplugin', 'core_admin');
$txt->updown = "$txt->up/$txt->down";
$antiviruses_available = antiviruses_get_available();
$active_antiviruses = explode(',', $CFG->antiviruses);
$active_antiviruses = array_reverse($active_antiviruses);
foreach ($active_antiviruses as $key=>$antivirus) {
if (empty($antiviruses_available[$antivirus])) {
unset($active_antiviruses[$key]);
} else {
$name = $antiviruses_available[$antivirus];
unset($antiviruses_available[$antivirus]);
$antiviruses_available[$antivirus] = $name;
}
}
$antiviruses_available = array_reverse($antiviruses_available, true);
$return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true);
$return .= $OUTPUT->box_start('generalbox antivirusesui');
$table = new html_table();
$table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
$table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
$table->id = 'antivirusmanagement';
$table->attributes['class'] = 'admintable generaltable';
$table->data = array();
// iterate through auth plugins and add to the display table
$updowncount = 1;
$antiviruscount = count($active_antiviruses);
$url = "antiviruses.php?sesskey=" . sesskey();
foreach ($antiviruses_available as $antivirus => $name) {
// hide/show link
$class = '';
if (in_array($antivirus, $active_antiviruses)) {
$hideshow = "<a href=\"$url&amp;action=disable&amp;antivirus=$antivirus\">";
$hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"disable\" /></a>";
$enabled = true;
$displayname = $name;
}
else {
$hideshow = "<a href=\"$url&amp;action=enable&amp;antivirus=$antivirus\">";
$hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"enable\" /></a>";
$enabled = false;
$displayname = $name;
$class = 'dimmed_text';
}
// up/down link (only if auth is enabled)
$updown = '';
if ($enabled) {
if ($updowncount > 1) {
$updown .= "<a href=\"$url&amp;action=up&amp;antivirus=$antivirus\">";
$updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
}
else {
$updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
}
if ($updowncount < $antiviruscount) {
$updown .= "<a href=\"$url&amp;action=down&amp;antivirus=$antivirus\">";
$updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
}
else {
$updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
}
++ $updowncount;
}
// settings link
if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) {
$eurl = new moodle_url('/admin/settings.php', array('section'=>'antivirussettings'.$antivirus));
$settings = "<a href='$eurl'>{$txt->settings}</a>";
} else {
$settings = '';
}
$uninstall = '';
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) {
$uninstall = html_writer::link($uninstallurl, $struninstall);
}
// Add a row to the table.
$row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
if ($class) {
$row->attributes['class'] = $class;
}
$table->data[] = $row;
}
$return .= html_writer::table($table);
$return .= get_string('configantivirusplugins', 'antivirus').'<br />'.get_string('tablenosave', 'admin');
$return .= $OUTPUT->box_end();
return highlight($query, $return);
}
}
/**
* Special class for license administration.
+140
View File
@@ -0,0 +1,140 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Utility classes and functions for antivirus integration.
*
* @package core_antivirus
* @copyright 2015 Ruslan Kabalin, Lancaster University.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Returns list of enabled antiviruses.
*
* @return array Array ('antivirusname'=>stdClass antivirus object).
*/
function antiviruses_get_enabled() {
global $CFG;
$active = array();
if (empty($CFG->antiviruses)) {
return $active;
}
foreach(explode(',', $CFG->antiviruses) as $e) {
if ($antivirus = antiviruses_get_antivirus($e)) {
if ($antivirus->is_configured()) {
$active[$e] = $antivirus;
}
}
}
return $active;
}
/**
* Scan file using all enabled antiviruses, throws exception in case of infected file.
*
* @param string $file Full path to the file.
* @param bool $deleteinfected whether infected file needs to be deleted.
* @throws moodle_exception If file is infected.
* @return void
*/
function antiviruses_scan_file($file, $deleteinfected) {
$antiviruses = antiviruses_get_enabled();
foreach ($antiviruses as $antivirus) {
$antivirus->scan_file($file, $deleteinfected);
}
}
/**
* Returns instance of antivirus.
*
* @param string $antivirusname name of antivirus.
* @return object|bool antivirus instance or false if does not exist.
*/
function antiviruses_get_antivirus($antivirusname) {
global $CFG;
$libfile = "$CFG->libdir/antivirus/$antivirusname/lib.php";
if (!file_exists($libfile)) {
return false;
}
require_once($libfile);
$classname = 'antivirus_' . $antivirusname;
if (!class_exists($classname)) {
return false;
}
return new $classname();
}
/**
* Get the list of available antiviruses.
*
* @return array Array ('antivirusname'=>'localised antivirus name').
*/
function antiviruses_get_available() {
$antiviruses = array();
foreach (core_component::get_plugin_list('antivirus') as $antivirusname => $dir) {
$antiviruses[$antivirusname] = get_string('pluginname', 'antivirus_'.$antivirusname);
}
return $antiviruses;
}
/**
* Base abstract antivirus class.
*
* @package core
* @subpackage antivirus
* @copyright 2015 Ruslan Kabalin, Lancaster University.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class antivirus {
/** @var stdClass the config for antivirus */
protected $config;
/**
* Class constructor.
*
* @return void.
*/
public function __construct() {
// Populate config variable, child class name is matching full plugin name,
// so we can use it directly to retrieve plugin configuration.
$this->config = get_config(get_class($this));
}
/**
* Are the antivirus settings configured?
*
* @return bool True if plugin has been configured.
*/
public abstract function is_configured();
/**
* Scan file, throws exception in case of infected file.
*
* @param string $file Full path to the file.
* @param string $filename Name of the file (could be different from physical file if temp file is used).
* @param bool $deleteinfected whether infected file needs to be deleted.
* @throws moodle_exception If file is infected.
* @return void
*/
public abstract function scan_file($file, $filename, $deleteinfected);
}
+2
View File
@@ -341,6 +341,7 @@ $cache = '.var_export($cache, true).';
$info = array(
'access' => null,
'admin' => $CFG->dirroot.'/'.$CFG->admin,
'antivirus' => $CFG->dirroot . '/lib/antivirus',
'auth' => $CFG->dirroot.'/auth',
'availability' => $CFG->dirroot . '/availability',
'backup' => $CFG->dirroot.'/backup/util/ui',
@@ -417,6 +418,7 @@ $cache = '.var_export($cache, true).';
global $CFG;
$types = array(
'antivirus' => $CFG->dirroot . '/lib/antivirus',
'availability' => $CFG->dirroot . '/availability/condition',
'qtype' => $CFG->dirroot.'/question/type',
'mod' => $CFG->dirroot.'/mod',
+119
View File
@@ -0,0 +1,119 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines classes used for plugin info.
*
* @package core_antivirus
* @copyright 2015 Ruslan Kabalin, Lancaster University.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\plugininfo;
use moodle_url, part_of_admin_tree, admin_settingpage;
defined('MOODLE_INTERNAL') || die();
/**
* Class for Antiviruses
*/
class antivirus extends base {
/**
* Finds all enabled plugins, the result may include missing plugins.
* @return array|null of enabled plugins $pluginname=>$pluginname, null means unknown
*/
public static function get_enabled_plugins() {
global $CFG;
if (empty($CFG->antiviruses)) {
return array();
}
$enabled = array();
foreach (explode(',', $CFG->antiviruses) as $antivirus) {
$enabled[$antivirus] = $antivirus;
}
return $enabled;
}
public function get_settings_section_name() {
return 'antivirussettings' . $this->name;
}
public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
global $CFG, $USER, $DB, $OUTPUT, $PAGE; // In case settings.php wants to refer to them.
$ADMIN = $adminroot; // May be used in settings.php.
$plugininfo = $this; // Also can be used inside settings.php.
$antivirus = $this; // Also can be used inside settings.php.
if (!$this->is_installed_and_upgraded()) {
return;
}
if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) {
return;
}
$section = $this->get_settings_section_name();
$settings = new admin_settingpage($section, $this->displayname, 'moodle/site:config', $this->is_enabled() === false);
include($this->full_path('settings.php')); // This may also set $settings to null.
if ($settings) {
$ADMIN->add($parentnodename, $settings);
}
}
/**
* Clamav antivirus can not be uninstalled.
*/
public function is_uninstall_allowed() {
if ($this->name === 'clamav') {
return false;
} else {
return true;
}
}
/**
* Return URL used for management of plugins of this type.
* @return moodle_url
*/
public static function get_manage_url() {
return new moodle_url('/admin/settings.php', array('section'=>'manageantiviruses'));
}
/**
* Pre-uninstall hook.
*/
public function uninstall_cleanup() {
global $CFG;
if (!empty($CFG->antiviruses)) {
$antiviruses = explode(',', $CFG->antiviruses);
$antiviruses = array_unique($antiviruses);
} else {
$antiviruses = array();
}
if (($key = array_search($this->name, $antiviruses)) !== false) {
unset($antiviruses[$key]);
set_config('antiviruses', implode(',', $antiviruses));
}
parent::uninstall_cleanup();
}
}
+1
View File
@@ -130,6 +130,7 @@ function xmldb_main_install() {
'stringfilters' => '', // These two are managed in a strange way by the filters
'filterall' => 0, // setting page, so have to be initialised here.
'texteditors' => 'atto,tinymce,textarea',
'antiviruses' => '',
'upgrade_minmaxgradestepignored' => 1, // New installs should not run this upgrade step.
'upgrade_extracreditweightsstepignored' => 1, // New installs should not run this upgrade step.
'upgrade_calculatedgradeitemsignored' => 1, // New installs should not run this upgrade step.
+1
View File
@@ -607,6 +607,7 @@ require_once($CFG->libdir .'/editorlib.php'); // All text editor related f
require_once($CFG->libdir .'/messagelib.php'); // Messagelib functions
require_once($CFG->libdir .'/modinfolib.php'); // Cached information on course-module instances
require_once($CFG->dirroot.'/cache/lib.php'); // Cache API
require_once($CFG->libdir .'/antiviruslib.php'); // Antivirus functions and classes.
// make sure PHP is not severly misconfigured
setup_validate_php_configuration();