MDL-66222 antivirus: Added antivirus failure reporting
This commit is contained in:
committed by
Peter Burnett
parent
a0fc902eb1
commit
adbe92ce0a
@@ -167,6 +167,29 @@ if ($hassiteconfig) {
|
||||
$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());
|
||||
|
||||
// Common settings.
|
||||
$temp->add(new admin_setting_heading('antiviruscommonsettings', new lang_string('antiviruscommonsettings', 'antivirus'), ''));
|
||||
|
||||
// Alert email.
|
||||
$temp->add(new admin_setting_configtext('antivirus/notifyemail',
|
||||
new lang_string('notifyemail', 'antivirus'),
|
||||
new lang_string('notifyemail_help', 'antivirus'), '', PARAM_EMAIL)
|
||||
);
|
||||
|
||||
// Enable quarantine.
|
||||
$temp->add(new admin_setting_configcheckbox('antivirus/enablequarantine',
|
||||
new lang_string('enablequarantine', 'antivirus'),
|
||||
new lang_string('enablequarantine_help', 'antivirus',
|
||||
\core\antivirus\quarantine::DEFAULT_QUARANTINE_FOLDER), 0));
|
||||
|
||||
// Quarantine time.
|
||||
$temp->add(new admin_setting_configduration('antivirus/quarantinetime',
|
||||
new lang_string('quarantinetime', 'antivirus'),
|
||||
new lang_string('quarantinetime_desc', 'antivirus'),
|
||||
\core\antivirus\quarantine::DEFAULT_QUARANTINE_TIME)
|
||||
);
|
||||
|
||||
$ADMIN->add('antivirussettings', $temp);
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('antivirus');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
|
||||
@@ -24,9 +24,38 @@
|
||||
|
||||
$string['actantivirushdr'] = 'Available antivirus plugins';
|
||||
$string['antiviruses'] = 'Antivirus plugins';
|
||||
$string['antiviruscommonsettings'] = 'Common antivirus settings';
|
||||
$string['antivirussettings'] = 'Manage antivirus plugins';
|
||||
$string['configantivirusplugins'] = 'Please choose the antivirus plugins you wish to use and arrange them in order of being applied.';
|
||||
$string['confirmdelete'] = 'Do you really want to delete this file';
|
||||
$string['confirmdeleteall'] = 'Do you really want to delete all files';
|
||||
$string['datastream'] = 'Data';
|
||||
$string['datainfecteddesc'] = 'There is a virus infected data';
|
||||
$string['datainfectedname'] = 'Data infected';
|
||||
$string['emailsubject'] = '{$a} :: Antivirus notification';
|
||||
$string['enablequarantine'] = 'Enable quarantine';
|
||||
$string['enablequarantine_help'] = 'When quarantine is enabled, any files which are detected as viruses will be kept in a quarantine folder for later inspection ([dataroot]/{$a}).
|
||||
The upload into Moodle will still fail.
|
||||
If you have any file system level virus scanning in place, the quarantine folder should be excluded from the antivirus check to avoid detecting the quarantined files.';
|
||||
$string['fileinfectedname'] = 'File infected';
|
||||
$string['incidencedetails'] = 'Infected file detected:
|
||||
Report: {$a->report}
|
||||
File name: {$a->filename}
|
||||
File size: {$a->filesize}
|
||||
File content hash: {$a->contenthash}
|
||||
File content type: {$a->contenttype}
|
||||
Uploaded by: {$a->author}
|
||||
IP: {$a->ipaddress}
|
||||
REFERER: {$a->referer}
|
||||
Date: {$a->date}
|
||||
{$a->notice}';
|
||||
$string['notifyemail'] = 'Antivirus alert email';
|
||||
$string['notifyemail_help'] = 'If set, then only the specified email will be notified when a virus is detected.
|
||||
If blank, then all site admins will be notified by email when a virus is detected.';
|
||||
$string['privacy:metadata'] = 'The Antivirus system does not store any personal data.';
|
||||
$string['quarantinedfiles'] = 'Antivirus quarantined files';
|
||||
$string['quarantinetime'] = 'Maximum quarantine time';
|
||||
$string['quarantinetime_desc'] = 'Quarantined files older than specified period will be removed.';
|
||||
$string['taskcleanup'] = 'Clean up quarantined files.';
|
||||
$string['unknown'] = 'Unknown';
|
||||
$string['virusfound'] = '{$a->item} has been scanned by a virus checker and found to be infected!';
|
||||
|
||||
@@ -228,6 +228,9 @@ class scanner extends \core\antivirus\scanner {
|
||||
$notice .= "\n\n". implode("\n", $output);
|
||||
$this->set_scanning_notice($notice);
|
||||
return self::SCAN_RESULT_ERROR;
|
||||
} else {
|
||||
$notice = "\n\n". implode("\n", $output);
|
||||
$this->set_scanning_notice($notice);
|
||||
}
|
||||
|
||||
return (int)$return;
|
||||
@@ -384,6 +387,8 @@ class scanner extends \core\antivirus\scanner {
|
||||
$parts = explode(' ', $message);
|
||||
$status = array_pop($parts);
|
||||
if ($status === 'FOUND') {
|
||||
$notice = "\n\n" . $output;
|
||||
$this->set_scanning_notice($notice);
|
||||
return self::SCAN_RESULT_FOUND;
|
||||
} else {
|
||||
$notice = get_string('clamfailed', 'antivirus_clamav', $this->get_clam_error_code(2));
|
||||
|
||||
@@ -67,11 +67,28 @@ class manager {
|
||||
* @return void
|
||||
*/
|
||||
public static function scan_file($file, $filename, $deleteinfected) {
|
||||
global $USER;
|
||||
$antiviruses = self::get_enabled();
|
||||
foreach ($antiviruses as $antivirus) {
|
||||
$result = $antivirus->scan_file($file, $filename);
|
||||
if ($result === $antivirus::SCAN_RESULT_FOUND) {
|
||||
// Infection found.
|
||||
// Infection found, send notification.
|
||||
$notice = $antivirus->get_scanning_notice();
|
||||
$incidencedetails = $antivirus->get_incidence_details($file, $filename, $notice);
|
||||
$antivirus->message_admins($notice, FORMAT_MOODLE, 'infected');
|
||||
|
||||
// Move to quarantine folder.
|
||||
$zipfile = \core\antivirus\quarantine::quarantine_file($file, $filename, $incidencedetails, $notice);
|
||||
|
||||
// Log file infected event.
|
||||
$params = array(
|
||||
'context' => \context_system::instance(),
|
||||
'relateduserid' => $USER->id,
|
||||
'other' => ['filename' => $filename, 'zipfile' => $zipfile, 'incidencedetails' => $incidencedetails],
|
||||
);
|
||||
$event = \core\event\antivirus_file_infected::create($params);
|
||||
$event->trigger();
|
||||
|
||||
if ($deleteinfected) {
|
||||
unlink($file);
|
||||
}
|
||||
@@ -83,15 +100,34 @@ class manager {
|
||||
/**
|
||||
* Scan data steam using all enabled antiviruses, throws exception in case of infected data.
|
||||
*
|
||||
* @param string $data The varaible containing the data to scan.
|
||||
* @param string $data The variable containing the data to scan.
|
||||
* @throws \core\antivirus\scanner_exception If data is infected.
|
||||
* @return void
|
||||
*/
|
||||
public static function scan_data($data) {
|
||||
global $USER;
|
||||
$antiviruses = self::get_enabled();
|
||||
foreach ($antiviruses as $antivirus) {
|
||||
$result = $antivirus->scan_data($data);
|
||||
if ($result === $antivirus::SCAN_RESULT_FOUND) {
|
||||
// Infection found, send notification.
|
||||
$filename = get_string('datastream', 'antivirus');
|
||||
$notice = $antivirus->get_scanning_notice();
|
||||
$incidencedetails = $antivirus->get_incidence_details('', $filename, $notice);
|
||||
$antivirus->message_admins($notice, FORMAT_MOODLE, 'infected');
|
||||
|
||||
// Copy data to quarantine folder.
|
||||
$zipfile = \core\antivirus\quarantine::quarantine_data($data, $filename, $incidencedetails, $notice);
|
||||
|
||||
// Log file infected event.
|
||||
$params = array(
|
||||
'context' => \context_system::instance(),
|
||||
'relateduserid' => $USER->id,
|
||||
'other' => ['filename' => $filename, 'zipfile' => $zipfile, 'incidencedetails' => $incidencedetails],
|
||||
);
|
||||
$event = \core\event\antivirus_data_infected::create($params);
|
||||
$event->trigger();
|
||||
|
||||
throw new \core\antivirus\scanner_exception('virusfound', '', array('item' => get_string('datastream', 'antivirus')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Quarantine file
|
||||
*
|
||||
* @package core_antivirus
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\antivirus;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
/**
|
||||
* Quarantine file
|
||||
*
|
||||
* @package core_antivirus
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quarantine {
|
||||
|
||||
/** Default quarantine folder */
|
||||
const DEFAULT_QUARANTINE_FOLDER = 'antivirus_quarantine';
|
||||
|
||||
/** Zip infected file */
|
||||
const FILE_ZIP_INFECTED = '_infected_file.zip';
|
||||
|
||||
/** Zip all infected file */
|
||||
const FILE_ZIP_ALL_INFECTED = '_all_infected_files.zip';
|
||||
|
||||
/** Incidence details file */
|
||||
const FILE_HTML_DETAILS = '_details.html';
|
||||
|
||||
/** Incidence details file */
|
||||
const DEFAULT_QUARANTINE_TIME = DAYSECS * 28;
|
||||
|
||||
/** Date format in filename */
|
||||
const FILE_NAME_DATE_FORMAT = '%Y%m%d%H%M%S';
|
||||
|
||||
/**
|
||||
* Move the infected file to the quarantine folder
|
||||
*
|
||||
* @param string $file infected file
|
||||
* @param string $filename infected file name
|
||||
* @param string $incidencedetails incidence details
|
||||
* @param string $notice notice details
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public static function quarantine_file($file, $filename, $incidencedetails, $notice) {
|
||||
if (!self::is_allowed_quarantine()) {
|
||||
return;
|
||||
}
|
||||
// Generate file names.
|
||||
$date = userdate(time(), self::FILE_NAME_DATE_FORMAT) . "_" . rand();
|
||||
$zipfilepath = self::get_quarantine_folder() . $date . self::FILE_ZIP_INFECTED;
|
||||
$detailsfilename = $date . self::FILE_HTML_DETAILS;
|
||||
|
||||
// Create Zip file.
|
||||
$ziparchive = new \zip_archive();
|
||||
if ($ziparchive->open($zipfilepath, \file_archive::CREATE)) {
|
||||
$ziparchive->add_file_from_string($detailsfilename, format_text($incidencedetails, FORMAT_MOODLE));
|
||||
$ziparchive->add_file_from_pathname($filename, $file);
|
||||
$ziparchive->close();
|
||||
}
|
||||
$zipfile = basename($zipfilepath);
|
||||
self::create_infected_file_record($filename, $zipfile, $notice);
|
||||
return $zipfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the infected file to the quarantine folder
|
||||
*
|
||||
* @param string $data data which is infected
|
||||
* @param string $filename infected file name
|
||||
* @param string $incidencedetails incidence details
|
||||
* @param string $notice notice details
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public static function quarantine_data($data, $filename, $incidencedetails, $notice) {
|
||||
if (!self::is_allowed_quarantine()) {
|
||||
return;
|
||||
}
|
||||
// Generate file names.
|
||||
$date = userdate(time(), self::FILE_NAME_DATE_FORMAT) . "_" . rand();
|
||||
$zipfilepath = self::get_quarantine_folder() . $date . self::FILE_ZIP_INFECTED;
|
||||
$detailsfilename = $date . self::FILE_HTML_DETAILS;
|
||||
|
||||
// Create Zip file.
|
||||
$ziparchive = new \zip_archive();
|
||||
if ($ziparchive->open($zipfilepath, \file_archive::CREATE)) {
|
||||
$ziparchive->add_file_from_string($detailsfilename, format_text($incidencedetails, FORMAT_MOODLE));
|
||||
$ziparchive->add_file_from_string($filename, $data);
|
||||
$ziparchive->close();
|
||||
}
|
||||
$zipfile = basename($zipfilepath);
|
||||
self::create_infected_file_record($filename, $zipfile, $notice);
|
||||
return $zipfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the virus quarantine is allowed
|
||||
*
|
||||
* @return bool
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public static function is_allowed_quarantine() {
|
||||
return !empty(get_config("antivirus", "enablequarantine"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quarantine folder
|
||||
*
|
||||
* @return string path of quarantine folder
|
||||
*/
|
||||
public static function get_quarantine_folder() {
|
||||
global $CFG;
|
||||
$quarantinefolder = $CFG->dataroot . DIRECTORY_SEPARATOR . self::DEFAULT_QUARANTINE_FOLDER;
|
||||
if (!file_exists($quarantinefolder)) {
|
||||
make_upload_directory(self::DEFAULT_QUARANTINE_FOLDER);
|
||||
}
|
||||
return $quarantinefolder . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download quarantined file
|
||||
*
|
||||
* @param string $filename name of file to be downloaded
|
||||
*/
|
||||
public static function download_quarantined_file($filename) {
|
||||
$file = self::get_quarantine_folder() . $filename;
|
||||
// send_file($file, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete quarantined file
|
||||
*
|
||||
* @param string $filename name of file to be deleted
|
||||
*/
|
||||
public static function delete_quarantined_file($filename) {
|
||||
self::delete_infected_file_record($filename);
|
||||
$file = self::get_quarantine_folder() . $filename;
|
||||
if (file_exists($file)) {
|
||||
// unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download all quarantined files
|
||||
*
|
||||
*/
|
||||
public static function download_all_quarantined_files() {
|
||||
$files = new \DirectoryIterator(self::get_quarantine_folder());
|
||||
// Add all infected file to a zip file.
|
||||
$date = userdate(time(), self::FILE_NAME_DATE_FORMAT);
|
||||
$zipfilename = $date . self::FILE_ZIP_ALL_INFECTED;
|
||||
$zipfilepath = self::get_quarantine_folder() . DIRECTORY_SEPARATOR . $zipfilename;
|
||||
$tempfilestocleanup = [];
|
||||
$ziparchive = new \zip_archive();
|
||||
if ($ziparchive->open($zipfilepath, \file_archive::CREATE)) {
|
||||
foreach ($files as $file) {
|
||||
if (!$file->isDot()) {
|
||||
$filename = $file->getFilename();
|
||||
$filepath = $file->getPathname();
|
||||
$ziparchive->add_file_from_pathname($filename, $filepath);
|
||||
}
|
||||
}
|
||||
$ziparchive->close();
|
||||
}
|
||||
// Clean up temp files.
|
||||
foreach ($tempfilestocleanup as $tempfile) {
|
||||
if (file_exists($tempfile)) {
|
||||
unlink($tempfile);
|
||||
}
|
||||
}
|
||||
// send_temp_file($zipfilepath, $zipfilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of quarantined files
|
||||
*
|
||||
* @return array list of quarantined files
|
||||
*/
|
||||
public static function get_quarantined_files() {
|
||||
$files = new \DirectoryIterator(self::get_quarantine_folder());
|
||||
$filestosort = [];
|
||||
foreach ($files as $file) {
|
||||
$filename = $file->getFilename();
|
||||
if (!$file->isDot() && strpos($filename, self::FILE_ZIP_INFECTED) !== false) {
|
||||
$filestosort[$filename] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
krsort($filestosort, SORT_NATURAL);
|
||||
return $filestosort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up quarantine folder
|
||||
*
|
||||
* @param int $timetocleanup time to clean up
|
||||
*/
|
||||
public static function clean_up_quarantine_folder($timetocleanup) {
|
||||
$files = new \DirectoryIterator(self::get_quarantine_folder());
|
||||
// Clean up the folder.
|
||||
foreach ($files as $file) {
|
||||
$filename = $file->getFilename();
|
||||
if (!$file->isDot() && strpos($filename, self::FILE_ZIP_INFECTED) !== false) {
|
||||
$modifiedtime = $file->getMTime();
|
||||
if ($modifiedtime <= $timetocleanup) {
|
||||
unlink($file->getPathname());
|
||||
self::delete_infected_file_record($filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an infected file record
|
||||
*
|
||||
* @param string $filename original file name
|
||||
* @param string $zipfile quarantined file name
|
||||
* @param string $reason failure reason
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
private static function create_infected_file_record($filename, $zipfile, $reason) {
|
||||
global $DB, $USER;
|
||||
$record = new \stdClass();
|
||||
$record->filename = $filename;
|
||||
$record->quarantinedfile = $zipfile;
|
||||
$record->author = fullname($USER);
|
||||
$record->reason = $reason;
|
||||
$record->timecreated = time();
|
||||
$DB->insert_record('infected_files', $record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an infected_file_record
|
||||
*
|
||||
* @param string $zipfile quarantined file name
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
private static function delete_infected_file_record($zipfile) {
|
||||
global $DB;
|
||||
$DB->delete_records('infected_files', ['quarantinedfile' => $zipfile]);
|
||||
}
|
||||
}
|
||||
@@ -133,27 +133,77 @@ abstract class scanner {
|
||||
* Email admins about antivirus scan outcomes.
|
||||
*
|
||||
* @param string $notice The body of the email to be sent.
|
||||
* @param string $format The body format.
|
||||
* @param string $eventname event name
|
||||
* @return void
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function message_admins($notice) {
|
||||
|
||||
public function message_admins($notice, $format = FORMAT_PLAIN, $eventname = 'errors') {
|
||||
$noticehtml = $format !== FORMAT_PLAIN ? format_text($notice, $format) : '';
|
||||
$site = get_site();
|
||||
|
||||
$subject = get_string('emailsubject', 'antivirus', format_string($site->fullname));
|
||||
$notifyemail = get_config('antivirus', 'notifyemail');
|
||||
if (!empty($notifyemail)) {
|
||||
$user = new \stdClass();
|
||||
$user->id = -1;
|
||||
$user->email = $notifyemail;
|
||||
email_to_user($user, get_admin(), $subject, $noticehtml);
|
||||
return;
|
||||
}
|
||||
|
||||
$admins = get_admins();
|
||||
foreach ($admins as $admin) {
|
||||
$eventdata = new \core\message\message();
|
||||
$eventdata->courseid = SITEID;
|
||||
$eventdata->component = 'moodle';
|
||||
$eventdata->name = 'errors';
|
||||
$eventdata->name = $eventname;
|
||||
$eventdata->userfrom = get_admin();
|
||||
$eventdata->userto = $admin;
|
||||
$eventdata->subject = $subject;
|
||||
$eventdata->fullmessage = $notice;
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = '';
|
||||
$eventdata->fullmessageformat = $format;
|
||||
$eventdata->fullmessagehtml = $noticehtml;
|
||||
$eventdata->smallmessage = '';
|
||||
message_send($eventdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return incidence details
|
||||
*
|
||||
* @param string $file full path to the file
|
||||
* @param string $filename original name of the file
|
||||
* @param string $notice notice from antivirus
|
||||
* @return string the incidence details
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_incidence_details($file = '', $filename = '', $notice = '') {
|
||||
global $USER;
|
||||
if (empty($notice)) {
|
||||
$notice = $this->get_scanning_notice();
|
||||
}
|
||||
$content = new \stdClass();
|
||||
$unknown = get_string('unknown', 'antivirus');;
|
||||
$content->filename = !empty($filename) ? $filename : $unknown;
|
||||
if (!empty($file)) {
|
||||
$content->filesize = filesize($file);
|
||||
$content->contenthash = \file_storage::hash_from_string(file_get_contents($file));
|
||||
$content->contenttype = mime_content_type($file);
|
||||
} else {
|
||||
$content->filesize = $unknown;
|
||||
$content->contenthash = $unknown;
|
||||
$content->contenttype = $unknown;
|
||||
}
|
||||
|
||||
$content->author = \core_user::is_real_user($USER->id) ? fullname($USER) . " ($USER->username)" : $unknown;
|
||||
$content->ipaddress = getremoteaddr();
|
||||
$content->date = userdate(time(), get_string('strftimedatetimeshort'));
|
||||
$content->referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $unknown;
|
||||
$content->notice = $notice;
|
||||
$report = new \moodle_url('/report/infectedfiles/index.php');
|
||||
$content->report = $report->out();
|
||||
return get_string('incidencedetails', 'antivirus', $content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Data infected event
|
||||
*
|
||||
* @package core
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
/**
|
||||
* Data infected event
|
||||
*
|
||||
* @package core
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class antivirus_data_infected extends \core\event\base {
|
||||
/**
|
||||
* Event data
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event description
|
||||
*
|
||||
* @return string description
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_description() {
|
||||
return isset($this->other['incidencedetails']) ?
|
||||
format_text($this->other['incidencedetails'], FORMAT_MOODLE) : 'Infected data';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event name
|
||||
*
|
||||
* @return string name
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('datainfectedname', 'antivirus');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event report link
|
||||
* @return \moodle_url
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/report/infectedfiles/index.php');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fle infected event
|
||||
*
|
||||
* @package core
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
/**
|
||||
* Fle infected event
|
||||
*
|
||||
* @package core
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class antivirus_file_infected extends \core\event\base {
|
||||
/**
|
||||
* Event data
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event description
|
||||
*
|
||||
* @return string description
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_description() {
|
||||
return isset($this->other['incidencedetails']) ?
|
||||
format_text($this->other['incidencedetails'], FORMAT_MOODLE) : 'Infected file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event name
|
||||
*
|
||||
* @return string name
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('fileinfectedname', 'antivirus');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return event report link
|
||||
* @return \moodle_url
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/report/infectedfiles/index.php');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Clean up task for core antivirus
|
||||
*
|
||||
* @package core_antivirus
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Clean up task for core antivirus
|
||||
*
|
||||
* @package core_antivirus
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class antivirus_cleanup_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskcleanup', 'antivirus');
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes workflows.
|
||||
*/
|
||||
public function execute() {
|
||||
$quarantinetime = get_config('antivirus', 'quarantinetime');
|
||||
if (empty($quarantinetime)) {
|
||||
$quarantinetime = \core\antivirus\quarantine::DEFAULT_QUARANTINE_TIME;
|
||||
set_config('quarantinetime', $quarantinetime, 'antivirus');
|
||||
}
|
||||
$timetocleanup = time() - $quarantinetime;
|
||||
\core\antivirus\quarantine::clean_up_quarantine_folder($timetocleanup);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4275,5 +4275,15 @@
|
||||
<INDEX NAME="instance" UNIQUE="false" FIELDS="contextid, contenttype, instanceid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="infected_files" COMMENT="Store virus infected file details">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="filename" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Original file name"/>
|
||||
<FIELD NAME="quarantinedfile" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Quarantine zip file"/>
|
||||
<FIELD NAME="author" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="User who uploaded the infected files"/>
|
||||
<FIELD NAME="reason" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Failure reason"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
@@ -142,4 +142,9 @@ $messageproviders = array (
|
||||
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
|
||||
),
|
||||
],
|
||||
|
||||
// Infected files.
|
||||
'infected' => array (
|
||||
'capability' => 'moodle/site:config'
|
||||
),
|
||||
);
|
||||
|
||||
@@ -401,4 +401,13 @@ $tasks = array(
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
array(
|
||||
'classname' => 'core\task\antivirus_cleanup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '0',
|
||||
'hour' => '0',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2539,5 +2539,25 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2020072300.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2020080500.01) {
|
||||
// Define table to store virus infected details.
|
||||
$table = new xmldb_table('infected_files');
|
||||
|
||||
// Adding fields.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('filename', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('quarantinedfile', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('author', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('reason', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
|
||||
|
||||
// Adding keys.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
upgrade_main_savepoint(true, 2020080500.01);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,67 @@ class core_antivirus_testcase extends advanced_testcase {
|
||||
$this->assertFileNotExists($this->tempfile);
|
||||
}
|
||||
|
||||
public function test_manager_send_message_to_user_email_scan_file_virus() {
|
||||
$sink = $this->redirectEmails();
|
||||
$exception = null;
|
||||
try {
|
||||
set_config('notifyemail', '[email protected]', 'antivirus');
|
||||
\core\antivirus\manager::scan_file($this->tempfile, 'FOUND', true);
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
$result = $sink->get_messages();
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertContains('[email protected]', $result[0]->to);
|
||||
$sink->close();
|
||||
}
|
||||
|
||||
public function test_manager_send_message_to_admin_email_scan_file_virus() {
|
||||
$sink = $this->redirectMessages();
|
||||
$exception = null;
|
||||
try {
|
||||
\core\antivirus\manager::scan_file($this->tempfile, 'FOUND', true);
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
$result = $sink->get_messages();
|
||||
$admins = array_keys(get_admins());
|
||||
$this->assertCount(1, $admins);
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertEquals($result[0]->useridto, reset($admins));
|
||||
$sink->close();
|
||||
}
|
||||
|
||||
public function test_manager_quarantine_file_virus() {
|
||||
try {
|
||||
set_config('enablequarantine', true, 'antivirus');
|
||||
\core\antivirus\manager::scan_file($this->tempfile, 'FOUND', true);
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
// Quarantined files.
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(1, count($quarantinedfiles));
|
||||
// Clean up.
|
||||
\core\antivirus\quarantine::clean_up_quarantine_folder(time());
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(0, count($quarantinedfiles));
|
||||
}
|
||||
|
||||
public function test_manager_none_quarantine_file_virus() {
|
||||
try {
|
||||
\core\antivirus\manager::scan_file($this->tempfile, 'FOUND', true);
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(0, count($quarantinedfiles));
|
||||
}
|
||||
|
||||
public function test_manager_scan_data_no_virus() {
|
||||
// Run mock scanning.
|
||||
$this->assertEmpty(\core\antivirus\manager::scan_data('OK'));
|
||||
@@ -100,4 +161,69 @@ class core_antivirus_testcase extends advanced_testcase {
|
||||
$this->expectException(\core\antivirus\scanner_exception::class);
|
||||
$this->assertEmpty(\core\antivirus\manager::scan_data('FOUND'));
|
||||
}
|
||||
|
||||
public function test_manager_send_message_to_user_email_scan_data_virus() {
|
||||
$sink = $this->redirectEmails();
|
||||
set_config('notifyemail', '[email protected]', 'antivirus');
|
||||
$exception = null;
|
||||
try {
|
||||
\core\antivirus\manager::scan_data('FOUND');
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
$result = $sink->get_messages();
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertContains('[email protected]', $result[0]->to);
|
||||
$sink->close();
|
||||
}
|
||||
|
||||
public function test_manager_send_message_to_admin_email_scan_data_virus() {
|
||||
$sink = $this->redirectMessages();
|
||||
$exception = null;
|
||||
try {
|
||||
\core\antivirus\manager::scan_data('FOUND');
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
$result = $sink->get_messages();
|
||||
$admins = array_keys(get_admins());
|
||||
$this->assertCount(1, $admins);
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertEquals($result[0]->useridto, reset($admins));
|
||||
$sink->close();
|
||||
}
|
||||
|
||||
public function test_manager_quarantine_data_virus() {
|
||||
set_config('enablequarantine', true, 'antivirus');
|
||||
$exception = null;
|
||||
try {
|
||||
\core\antivirus\manager::scan_data('FOUND');
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
// Quarantined files.
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(1, count($quarantinedfiles));
|
||||
// Clean up.
|
||||
\core\antivirus\quarantine::clean_up_quarantine_folder(time());
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(0, count($quarantinedfiles));
|
||||
}
|
||||
|
||||
|
||||
public function test_manager_none_quarantine_data_virus() {
|
||||
$exception = null;
|
||||
try {
|
||||
\core\antivirus\manager::scan_data('FOUND');
|
||||
} catch (\core\antivirus\scanner_exception $ex) {
|
||||
$exception = $ex;
|
||||
}
|
||||
$this->assertNotEmpty($exception);
|
||||
// No Quarantined files.
|
||||
$quarantinedfiles = \core\antivirus\quarantine::get_quarantined_files();
|
||||
$this->assertEquals(0, count($quarantinedfiles));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace report_infectedfiles\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class infectedfiles_table extends \table_sql implements \renderable {
|
||||
/**
|
||||
* Table constructor
|
||||
*
|
||||
* @param int $uniqueid table id
|
||||
* @param \moodle_url $url page url
|
||||
* @param int $page current page
|
||||
* @param int $perpage number or record per page
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function __construct($uniqueid, \moodle_url $url, $page = 0, $perpage = 30) {
|
||||
parent::__construct($uniqueid);
|
||||
|
||||
$this->set_attribute('class', 'report_infectedfiles');
|
||||
|
||||
// Set protected properties.
|
||||
$this->pagesize = $perpage;
|
||||
$this->page = $page;
|
||||
|
||||
// Define columns in the table.
|
||||
$this->define_table_columns();
|
||||
|
||||
// Define configs.
|
||||
$this->define_table_configs($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Table columns and corresponding headers
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function define_table_columns() {
|
||||
$cols = array(
|
||||
'filename' => get_string('filename', 'report_infectedfiles'),
|
||||
'quarantinedfile' => get_string('quarantinedfile', 'report_infectedfiles'),
|
||||
'author' => get_string('author', 'report_infectedfiles'),
|
||||
'reason' => get_string('reason', 'report_infectedfiles'),
|
||||
'timecreated' => get_string('timecreated', 'report_infectedfiles'),
|
||||
'actions' => get_string('actions'),
|
||||
);
|
||||
|
||||
$this->define_columns(array_keys($cols));
|
||||
$this->define_headers(array_values($cols));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define table configuration
|
||||
*
|
||||
* @param \moodle_url $url
|
||||
*/
|
||||
protected function define_table_configs(\moodle_url $url) {
|
||||
// Set table url.
|
||||
$this->define_baseurl($url);
|
||||
|
||||
// Set table configs.
|
||||
$this->collapsible(false);
|
||||
$this->sortable(false);
|
||||
$this->pageable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the SQL query.
|
||||
*
|
||||
* @param bool $count When true, return the count SQL.
|
||||
* @return array containing sql to use and an array of params.
|
||||
*/
|
||||
protected function get_sql_and_params($count = false) {
|
||||
if ($count) {
|
||||
$select = "COUNT(1)";
|
||||
} else {
|
||||
$select = "*";
|
||||
}
|
||||
|
||||
$sql = "SELECT $select
|
||||
FROM {infected_files}";
|
||||
|
||||
$params = array();
|
||||
|
||||
if (!$count) {
|
||||
$sql .= " ORDER BY timecreated DESC";
|
||||
}
|
||||
|
||||
return array($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data.
|
||||
*
|
||||
* @param int $pagesize number of records to fetch
|
||||
* @param bool $useinitialsbar initial bar
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
global $DB;
|
||||
|
||||
list($countsql, $countparams) = $this->get_sql_and_params(true);
|
||||
list($sql, $params) = $this->get_sql_and_params();
|
||||
$total = $DB->count_records_sql($countsql, $countparams);
|
||||
$this->pagesize($pagesize, $total);
|
||||
$this->rawdata = $DB->get_records_sql($sql, $params, $this->get_page_start(), $this->get_page_size());
|
||||
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
$this->initialbars($total > $pagesize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom actions column
|
||||
*
|
||||
* @param \stdClass $row an incidence record
|
||||
* @return string content of action column
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
protected function col_actions($row) {
|
||||
global $OUTPUT;
|
||||
$filename = $row->quarantinedfile;
|
||||
$zipfile = \core\antivirus\quarantine::get_quarantine_folder() . $filename;
|
||||
if (!file_exists($zipfile)) {
|
||||
return '';
|
||||
}
|
||||
$links = '';
|
||||
$managefilepage = new \moodle_url('/report/infectedfiles/manage_infected_files.php');
|
||||
|
||||
// Download.
|
||||
$downloadparams = ['filename' => $filename, 'action' => 'download', 'sesskey' => sesskey()];
|
||||
$downloadurl = new \moodle_url($managefilepage, $downloadparams);
|
||||
$icon = $OUTPUT->pix_icon('t/download', get_string('download'));
|
||||
$downloadlink = \html_writer::link($downloadurl, $icon);
|
||||
$links .= ' ' . $downloadlink;
|
||||
|
||||
// Delete.
|
||||
$deleteparams = ['filename' => $filename, 'action' => 'confirmdelete', 'sesskey' => sesskey()];
|
||||
$deleteurl = new \moodle_url($managefilepage, $deleteparams);
|
||||
$icon = $OUTPUT->pix_icon('t/delete', get_string('delete'));
|
||||
$deletelink = \html_writer::link($deleteurl, $icon);
|
||||
$links .= ' ' . $deletelink;
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom time column
|
||||
*
|
||||
* @param \stdClass $row an incidence record
|
||||
* @return string time created in user-friendly format
|
||||
*/
|
||||
protected function col_timecreated($row) {
|
||||
return userdate($row->timecreated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display table with download all and delete all buttons
|
||||
*
|
||||
* @param int $pagesize number or records perpage
|
||||
* @param bool $useinitialsbar use the bar or not
|
||||
* @param string $downloadhelpbutton help button
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function display($pagesize, $useinitialsbar, $downloadhelpbutton='') {
|
||||
$this->out($pagesize, $useinitialsbar, $downloadhelpbutton);
|
||||
|
||||
$managefilepage = new \moodle_url('/report/infectedfiles/manage_infected_files.php');
|
||||
// Delete All.
|
||||
$button = \html_writer::tag('button', get_string('deleteall'), ['class' => 'btn btn-primary']);
|
||||
$deleteallparams = ['action' => 'confirmdeleteall', 'sesskey' => sesskey()];
|
||||
$deleteallurl = new \moodle_url($managefilepage, $deleteallparams);
|
||||
echo \html_writer::link($deleteallurl, $button);
|
||||
|
||||
echo " ";
|
||||
|
||||
// Download All.
|
||||
$button = \html_writer::tag('button', get_string('downloadall'), ['class' => 'btn btn-primary']);
|
||||
$downloadallparams = ['action' => 'downloadall', 'sesskey' => sesskey()];
|
||||
$downloadallurl = new \moodle_url($managefilepage, $downloadallparams);
|
||||
echo \html_writer::link($downloadallurl, $button);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report renderer
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace report_infectedfiles\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Infected file report renderer
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends \plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Render the table
|
||||
*
|
||||
* @param infectedfiles_table $table table of infected files
|
||||
* @return false|string return html code of the table
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
protected function render_infectedfiles_table(infectedfiles_table $table) {
|
||||
ob_start();
|
||||
$table->display($table->pagesize, false);
|
||||
$o = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace report_infectedfiles\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements \core_privacy\local\metadata\null_provider {
|
||||
|
||||
/**
|
||||
* This plugin does not contain any personal data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason() : string {
|
||||
return 'privacy:metadata';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('reportinfectedfiles', '', null, '', array('pagelayout' => 'report'));
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('infectedfiles', 'report_infectedfiles'));
|
||||
$table = new \report_infectedfiles\output\infectedfiles_table('report-infectedfiles-report-table', $PAGE->url, $page);
|
||||
$table->define_baseurl($PAGE->url);
|
||||
echo $PAGE->get_renderer('report_infectedfiles')->render($table);
|
||||
echo $OUTPUT->footer();
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
$string['author'] = 'Author';
|
||||
$string['confirmdelete'] = 'Do you really want to delete this file';
|
||||
$string['confirmdeleteall'] = 'Do you really want to delete all files';
|
||||
$string['filename'] = 'File name';
|
||||
$string['infectedfiles'] = 'Infected files';
|
||||
$string['privacy:metadata'] = 'This plugin does not contain any personal data';
|
||||
$string['pluginname'] = 'Infected files';
|
||||
$string['quarantinedfile'] = 'Quarantined file';
|
||||
$string['reason'] = 'Failure reason';
|
||||
$string['timecreated'] = 'Time created';
|
||||
@@ -0,0 +1,77 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Manage infected files.
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
use \core\antivirus\quarantine;
|
||||
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$action = optional_param('action', '', PARAM_TEXT);
|
||||
$reportpage = new moodle_url('/report/infectedfiles/index.php');
|
||||
$thispage = new moodle_url('/report/infectedfiles/manage_infected_files.php');
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_url($thispage);
|
||||
$PAGE->navbar->add(get_string('infectedfiles', 'report_infectedfiles'), $reportpage);
|
||||
|
||||
switch ($action) {
|
||||
case 'download':
|
||||
$filename = required_param('filename', PARAM_TEXT);
|
||||
quarantine::download_quarantined_file($filename);
|
||||
case 'downloadall':
|
||||
quarantine::download_all_quarantined_files();
|
||||
case 'confirmdelete':
|
||||
$filename = required_param('filename', PARAM_TEXT);
|
||||
$deleteparams = ['filename' => $filename, 'action' => 'delete', 'sesskey' => sesskey()];
|
||||
$confirmeddelete = new single_button(new moodle_url($thispage, $deleteparams), get_string('delete'), 'post');
|
||||
$cancel = new single_button(new moodle_url($reportpage), get_string('cancel'), 'post');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('infectedfiles', 'report_infectedfiles'));
|
||||
echo $OUTPUT->confirm(get_string('confirmdelete', 'report_infectedfiles'), $confirmeddelete, $cancel);
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
case 'delete':
|
||||
$filename = required_param('filename', PARAM_TEXT);
|
||||
quarantine::delete_quarantined_file($filename);
|
||||
redirect($reportpage);
|
||||
case 'confirmdeleteall':
|
||||
require_sesskey();
|
||||
$deleteallparams = ['action' => 'deleteall', 'sesskey' => sesskey()];
|
||||
$confirmeddeleteall = new single_button(new moodle_url($thispage, $deleteallparams), get_string('delete'), 'post');
|
||||
$cancel = new single_button(new moodle_url($reportpage), get_string('cancel'), 'post');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('infectedfiles', 'report_infectedfiles'));
|
||||
echo $OUTPUT->confirm(get_string('confirmdeleteall', 'report_infectedfiles'), $confirmeddeleteall, $cancel);
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
case 'deleteall':
|
||||
require_sesskey();
|
||||
// Remove file until current time.
|
||||
quarantine::clean_up_quarantine_folder(time());
|
||||
redirect($reportpage);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$ADMIN->add('reports', new admin_externalpage('reportinfectedfiles',
|
||||
get_string('infectedfiles', 'report_infectedfiles'),
|
||||
"$CFG->wwwroot/report/infectedfiles/index.php"));
|
||||
|
||||
$settings = null;
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Infected file report
|
||||
*
|
||||
* @package report_infectedfiles
|
||||
* @author Nathan Nguyen <[email protected]>
|
||||
* @copyright Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2020031800;
|
||||
$plugin->requires = 2019111200;
|
||||
$plugin->component = 'report_infectedfiles';
|
||||
Reference in New Issue
Block a user