Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.4.1 #93

Merged
merged 7 commits into from
Dec 31, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Changelog

### 1.4.0 ###
* **English**
* Option to provide a custom key for the Google Safe Browsing API
* Scan files of parent theme if a child theme is active
* Verify checksums of WP core files (integrated functionality from _Checksum Verifier_ plugin)
* Ability to enable _Safe Browsing_ and _Checksum Verifier_ as cronjob without Theme scan
* **Deutsch**
* Möglichkeit einen eigenen Schlüssel für die Google Safe Browsing API zu verwenden
* Dateien des übergeordneten Themes scannen, falls ein Child-Theme aktiv ist
* Verifiziere Prüfsummen der WP Core Dateien (Funktionalität des _Checksum Verifier_ Plugins integriert)
* Möglichkeit _Safe Browsing_ und _Checksum Verifier_ als Cronjob ohne Theme-Scan zu aktivieren
### 1.4.1 ###
* Fix some spelling mistakes and correct translations (#85)
* Fix file name sanitization in manual theme scan causing errors to be not shown in the admin area (#88, #89)
* Fix theme file collection for child themes with duplicate names (#86)
* Consider all levels in theme file check instead of one only (#87, #90)
* Support translations in old WordPress versions (#91)

### 1.4.0 ###
* Option to provide a custom key for the Google Safe Browsing API (#69)
* Scan files of parent theme if a child theme is active (#1, #62)
* Verify checksums of WP core files (integrated functionality from _Checksum Verifier_ plugin (#5, #56)
* Allow to enable _Safe Browsing_ and _Checksum Verifier_ as cronjob without theme scan (#66)
* Update code style check and add build script (#68)

### 1.3.10 ###
* **English**
43 changes: 21 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -2,30 +2,28 @@
* Contributors: pluginkollektiv
* Tags: antivirus, malware, scanner, phishing, safe browsing, vulnerability
* Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TD4AMD2D8EMZW
* Requires at least: 4.6
* Requires at least: 4.1
* Requires PHP: 5.2
* Tested up to: 5.6
* Stable tag: 1.4.0
* Stable tag: 1.4.1
* License: GPLv2 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.html

Security plugin to protect your blog or website against exploits and spam injections.

## Description ##
*AntiVirus for WordPress* is a easy-to-use, safe tool to harden your WordPress site against exploits, malware and spam injections.
You can configure *AntiVirus* to perform an automated daily scan of your theme files. If the plugin happens to detect any suspicious code injections, it will send out a notification to a previously configured e-mail address.
*AntiVirus* is an easy-to-use, safe tool to harden your WordPress site against exploits, malware and spam injections.
You can configure *AntiVirus* to perform an automated daily scan of your theme files. If the plugin detects any suspicious code injections, it will send out a notification to a previously configured e-mail address.

In case your WordPress site has been hacked, *AntiVirus* will help you to become aware of the problem very quickly in order for you to take immediate action.

### Features ###
* Virus alert in the admin bar
* Cleaning up after plugin removal
* Daily scan with email notifications
* Theme template checks
* Whitelist solution: Mark suspected cases as "no virus"
* Manual check of template files with alerts on suspected cases
* Scan for suspicious code in the theme files (daily scan with email notifications and manual scan) with an option to mark detected cases as false positive
* Checksum verification for WordPress Core files
* Optional: Google Safe Browsing for malware and phishing monitoring.

A complete documentation is available on the [AntiVirus website](https://antivirus.pluginkollektiv.org/documentation/).

### Support ###
* Community support via the [support forums on wordpress.org](https://wordpress.org/support/plugin/antivirus)
* We don’t handle support via e-mail, Twitter, GitHub issues etc.
@@ -38,23 +36,24 @@ In case your WordPress site has been hacked, *AntiVirus* will help you to become

### Credits ###
* Author: [Sergej Müller](https://sergejmueller.github.io/)
* Maintainers: [pluginkollektiv](http://pluginkollektiv.org/)


## Frequently Asked Questions ##
* Maintainers: [pluginkollektiv](https://pluginkollektiv.org)

### Will AntiVirus protect my site from being hacked? ###
Not literally "protect from". The plugin’s purpose is to *detect* any "hack" that has already happened and enable you to take immediate action upon it.

A complete documentation is available on the [AntiVirus website](https://antivirus.pluginkollektiv.org/documentation/).

## Changelog ##

### 1.4.1 ###
* Fix some spelling mistakes and correct translations (#85)
* Fix file name sanitization in manual theme scan causing errors to be not shown in the admin area (#88, #89)
* Fix theme file collection for child themes with duplicate names (#86)
* Consider all levels in theme file check instead of one only (#87, #90)
* Support translations in old WordPress versions (#91)

### 1.4.0 ###
* Option to provide a custom key for the Google Safe Browsing API
* Scan files of parent theme if a child theme is active
* Verify checksums of WP core files (integrated functionality from _Checksum Verifier_ plugin)
* Ability to enable _Safe Browsing_ and _Checksum Verifier_ as cronjob without Theme scan
* Option to provide a custom key for the Google Safe Browsing API (#69)
* Scan files of parent theme if a child theme is active (#1, #62)
* Verify checksums of WP core files (integrated functionality from _Checksum Verifier_ plugin (#5, #56)
* Allow to enable _Safe Browsing_ and _Checksum Verifier_ as cronjob without theme scan (#66)
* Update code style check and add build script (#68)

### 1.3.10 ###
* Updated PayPal link for donations
4 changes: 1 addition & 3 deletions antivirus.php
Original file line number Diff line number Diff line change
@@ -8,9 +8,7 @@
* Text Domain: antivirus
* License: GPLv2 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
* Version: 1.4.0
*
* [](http://coderisk.com/wp/plugin/antivirus/RIPS-x1EDAuZC-C)
* Version: 1.4.1
*
* @package AntiVirus
*/
2 changes: 1 addition & 1 deletion inc/class-antivirus-checkinternals.php
Original file line number Diff line number Diff line change
@@ -165,7 +165,7 @@ private static function _php_match_pattern() {
*
* @return array|bool An array of matched lines or false on failure.
*/
private static function _check_file_line( $line = '', $num ) {
private static function _check_file_line( $line, $num ) {
// Trim value.
$line = trim( (string) $line );

2 changes: 1 addition & 1 deletion inc/class-antivirus-checksumverifier.php
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ public static function verify_files() {
esc_html__( 'Checksum Verifier Alert', 'antivirus' ),
sprintf(
"%s:\r\n\r\n- %s",
esc_html__( 'Official checksums do not match for the following files', 'antivirus' ),
esc_html__( 'Checksums do not match for the following files', 'antivirus' ),
implode( "\r\n- ", $matches )
)
);
10 changes: 5 additions & 5 deletions inc/class-antivirus-safebrowsing.php
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ public static function check_safe_browsing() {
array(
'client' => array(
'clientId' => 'wpantivirus',
'clientVersion' => '1.4.0',
'clientVersion' => '1.4.1',
),
'threatInfo' => array(
'threatTypes' => array(
@@ -92,8 +92,8 @@ public static function check_safe_browsing() {
// Invalid request (most likely invalid key) or expired/exceeded key.
$mail_body = sprintf(
"%s\r\n\r\n%s",
esc_html__( 'Checking yout site against the Google Safe Browsing API has failed.', 'antivirus' ),
esc_html__( 'This does not mean that your site has been infected, but that the status could not be determinined.', 'antivirus' )
esc_html__( 'Checking your site against the Google Safe Browsing API has failed.', 'antivirus' ),
esc_html__( 'This does not mean that your site has been infected, but that the status could not be determined.', 'antivirus' )
);

// Add (sanitized) error message, if available.
@@ -109,12 +109,12 @@ public static function check_safe_browsing() {
if ( $custom_key ) {
$mail_body .= sprintf(
"\r\n%s",
esc_html__( 'Please check if your API key is correct and its limit not exceeded. If everything is correct and the error persists for the next requests, please contact the Plugin support.', 'antivirus' )
esc_html__( 'Please check if your API key is correct and its limit not exceeded. If everything is correct and the error persists for the next requests, please contact the plugin support.', 'antivirus' )
);
} else {
$mail_body .= sprintf(
"\r\n%s",
esc_html__( 'This might be due to an exceeded rate limit on the shared API key. To ensure this does not happen please consider providing your own key using the Plugin settings page.', 'antivirus' )
esc_html__( 'This might be due to an exceeded rate limit on the shared API key. To ensure this does not happen please provide your own key using the settings page.', 'antivirus' )
);
}

29 changes: 11 additions & 18 deletions inc/class-antivirus.php
Original file line number Diff line number Diff line change
@@ -44,6 +44,9 @@ public static function init() {
// Save the plugin basename.
self::$base = plugin_basename( ANTIVIRUS_FILE );

// Load translations. Required due to support for WP versions before 4.6.
load_plugin_textdomain( 'antivirus' );

// Register the daily cronjob.
add_action( 'antivirus_daily_cronjob', array( __CLASS__, 'do_daily_cronjob' ) );

@@ -393,7 +396,7 @@ private static function _get_theme_data( $theme ) {
// Extract data.
$name = $theme->get( 'Name' );
$slug = $theme->get_stylesheet();
$files = $theme->get_files( 'php', 1 );
$files = array_values( $theme->get_files( 'php', -1 ) );

// Append parent's data, if we got a child theme.
$parent = self::_get_theme_data( $theme->parent() );
@@ -520,7 +523,7 @@ public static function get_ajax_response() {

case 'check_theme_file':
if ( ! empty( $_POST['_theme_file'] ) ) {
$theme_file = sanitize_file_name( wp_unslash( $_POST['_theme_file'] ) );
$theme_file = filter_var( wp_unslash( $_POST['_theme_file'] ), FILTER_SANITIZE_STRING );
$lines = AntiVirus_CheckInternals::check_theme_file( $theme_file );
if ( $lines ) {
foreach ( $lines as $num => $line ) {
@@ -719,12 +722,12 @@ public static function show_admin_menu() {

<p class="description">
<?php
/* translators: Link for transparency report in english */
/* translators: Link for transparency report */
$start_tag = sprintf( '<a href="%s">', esc_attr__( 'https://transparencyreport.google.com/safe-browsing/search?hl=en', 'antivirus' ) );
$end_tag = '</a>';
echo wp_kses(
/* translators: First placeholder (%s) starting link tag to transparency report, second placeholder closing link tag */
sprintf( __( 'Diagnosis and notification in suspicion case. For more details read %1$s the transparency report %2$s.', 'antivirus' ), $start_tag, $end_tag ),
/* translators: First placeholder (%1$s) starting link tag to transparency report, second placeholder (%2$s) closing link tag */
sprintf( __( 'Diagnosis and notification in suspicion case. For more details read %1$sthe transparency report%2$s.', 'antivirus' ), $start_tag, $end_tag ),
array( 'a' => array( 'href' => array() ) )
);
?>
@@ -752,13 +755,11 @@ public static function show_admin_menu() {
<label for="av_checksum_verifier">
<input type="checkbox" name="av_checksum_verifier" id="av_checksum_verifier"
value="1" <?php checked( self::_get_option( 'checksum_verifier' ), 1 ); ?> />
<?php esc_html_e( 'Checksum verification of WP core files', 'antivirus' ); ?>
<?php esc_html_e( 'Checksum verification of WordPress core files', 'antivirus' ); ?>
</label>

<p class="description">
<?php
esc_html_e( 'Matches checksums of all WordPress core files against the values provided by the official API.', 'antivirus' );
?>
<?php esc_html_e( 'Matches checksums of all WordPress core files against the values provided by the official API.', 'antivirus' ); ?>
</p>
</fieldset>

@@ -772,7 +773,7 @@ class="regular-text"
placeholder="<?php esc_attr_e( 'Email address for notifications', 'antivirus' ); ?>" />

<p class="description">
<?php esc_html_e( 'If the field is empty, the blog admin will be notified', 'antivirus' ); ?>
<?php esc_html_e( 'If the field is empty, the blog admin will be notified.', 'antivirus' ); ?>
</p>
</fieldset>
</td>
@@ -792,14 +793,6 @@ class="regular-text"
?>
&bull;
<?php
printf(
'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
esc_attr__( 'https://wordpress.org/plugins/antivirus/faq/', 'antivirus' ),
esc_html__( 'FAQ', 'antivirus' )
);
?>
&bull;
<?php
printf(
'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
'https://antivirus.pluginkollektiv.org/documentation/',
24 changes: 12 additions & 12 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<?xml version="1.0"?>
<ruleset name="AntiVirus">
<description>Sniffs for the coding standards of the plugin</description>
<description>Sniffs for the coding standards of the plugin</description>

<arg value="psvn"/>
<arg name="colors"/>
<arg value="psvn"/>
<arg name="colors"/>

<!-- Files to sniff -->
<file>antivirus.php</file>
<file>inc</file>
<!-- Files to sniff -->
<file>antivirus.php</file>
<file>inc</file>
<file>tests</file>

<!-- Extend from WPCS ruleset -->
<config name="minimum_supported_wp_version" value="4.6"/>
<rule ref="WordPress"/>
<!-- Extend from WPCS ruleset -->
<config name="minimum_supported_wp_version" value="4.1"/>
<rule ref="WordPress"/>

<!-- Verify i18n text domain -->
<rule ref="WordPress.WP.I18n">
@@ -26,9 +26,9 @@
<exclude-pattern>tests</exclude-pattern>
</rule>

<!-- PHP compatibility level -->
<config name="testVersion" value="5.2-"/>
<rule ref="PHPCompatibility">
<!-- PHP compatibility level -->
<config name="testVersion" value="5.2-"/>
<rule ref="PHPCompatibility">
<exclude-pattern>tests</exclude-pattern>
</rule>
</ruleset>
1 change: 1 addition & 0 deletions tests/antivirustestcase.php
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ abstract class AntiVirus_TestCase extends WP_Mock\Tools\TestCase {
public function setUp(): void {
WP_Mock::setUp();

WP_Mock::passthruFunction( 'load_plugin_textdomain' );
WP_Mock::passthruFunction( 'wp_parse_args' );
WP_Mock::userFunction( 'get_option' )->with( 'antivirus' )->andReturnUsing(
function () {
85 changes: 85 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -8,7 +8,92 @@
// phpcs:ignore Squiz.Commenting.FileComment.Missing
require_once __DIR__ . '/../vendor/autoload.php';

// Override WP_CONTENT_DIR to use own resources instead of WP_Mock dummy files.
define( 'WP_CONTENT_DIR', __DIR__ . '/resources' );

WP_Mock::bootstrap();

require_once __DIR__ . '/antivirustestcase.php';
require_once __DIR__ . '/../inc/class-antivirus.php';

/**
* Class WP_Theme_Mock.
*
* Mock-implementation of {@link WP_Theme}.
*/
class WP_Theme_Mock {
/**
* Theme data.
*
* @var array
*/
private $data;

/**
* WP_Theme_Mock constructor.
*
* @param string $name Theme name.
* @param string $stylesheet Theme stylesheet name.
* @param array $files Theme files.
* @param WP_Theme_Mock|null $parent Parent theme (optional).
*/
public function __construct( string $name, string $stylesheet, array $files, WP_Theme_Mock $parent = null ) {
$this->data = array(
'Name' => $name,
'stylesheet' => $stylesheet,
'files' => $files,
'parent' => $parent ?? false,
);
}

/**
* Get theme attribute.
*
* @param string $key Attribute key.
*
* @return mixed Attribute value.
*/
public function get( string $key ) {
return $this->data[ $key ] ?? false;
}

/**
* Set theme attribute.
*
* @param string $key Attribute key.
* @param mixed $val Attribute value.
*/
public function set( string $key, $val ): void {
$this->data[ $key ] = $val;
}

/**
* Get stylesheet name.
*
* @return string Stylesheet name.
*/
public function get_stylesheet(): string {
return $this->get( 'stylesheet' );
}

/**
* Get theme files.
*
* @param string $suffix File suffix (ignored here).
* @param int $deptn File hierarchy depth (ignored here).
*
* @return false|mixed
*/
public function get_files( string $suffix, int $deptn ) {
return $this->get( 'files' );
}

/**
* Get parent theme.
*
* @return false|WP_Theme_Mock Parent theme or false.
*/
public function parent() {
return $this->get( 'parent' );
}
}
1 change: 1 addition & 0 deletions tests/resources/themes/theme1/themefile1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content 1
1 change: 1 addition & 0 deletions tests/resources/themes/theme1/themefile2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test content 2
1 change: 1 addition & 0 deletions tests/resources/themes/theme2/themefile1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
testcontent 1a
1 change: 1 addition & 0 deletions tests/resources/themes/theme2/themefile3
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
testcontent 3
71 changes: 71 additions & 0 deletions tests/test-checkinternals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
/**
* Test our plugin.
*
* @package AntiVirus
*/

/**
* Class AntiVirus_Checkinternals_Test.
*
* Unit tests for the the {@link AntiVirus_CheckInternals} module.
*/
class AntiVirus_Checkinternals_Test extends AntiVirus_TestCase {

/**
* Set up test.
*
* @inheritdoc
*/
public function setUp(): void {
parent::setUp();

require_once __DIR__ . '/../inc/class-antivirus-checkinternals.php';
}

/**
* Test theme file checks.
*/
public function test_theme_files(): void {
$theme = new WP_Theme_Mock(
'Theme 1',
'theme1',
array(
'themefile1' => '/themes/theme1/themefile1',
'themefile2' => '/themes/theme1/themefile2',
)
);
$parent_theme = new WP_Theme_Mock(
'Theme 2',
'theme2',
array(
'themefile1' => '/themes/theme2/themefile1',
'themefile3' => '/themes/theme2/themefile3',
)
);

$checked_files = array();
WP_Mock::userFunction( 'wp_get_theme' )
->andReturn( $theme );
WP_Mock::userFunction( 'validate_file' )
->andReturnUsing(
function ( $file ) use ( &$checked_files ) {
$checked_files[] = $file;

return 0;
}
);

// Check standalone theme.
self::assertFalse( AntiVirus_CheckInternals::_check_theme_files(), 'failed checking empty files' );
self::assertEquals( 2, count( $checked_files ), 'unexpected number of checked files for standlone theme' );

// Again with child theme.
$theme->set( 'parent', $parent_theme );
$checked_files = array();
self::assertFalse( AntiVirus_CheckInternals::_check_theme_files(), 'failed checking empty files' );
self::assertEquals( 4, count( $checked_files ), 'unexpected number of checked files for child theme' );

// TODO: add some real content checks.
}
}