Skip to content

Commit

Permalink
Merge branch 'release-0.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
chesio committed Jul 21, 2017
2 parents 411d684 + fa4f7d9 commit 833a1f5
Show file tree
Hide file tree
Showing 13 changed files with 717 additions and 19 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ BC Security allows you to:

BC Security maintains a list of IP addresses with limited access to the website. Currently, this list is only populated by [Login Security](#login-security) module.

### Notifications

BC Security allows to send automatic email notification to configured recipients on following occasions:

1. WordPress update is available.
1. Plugin update is available.
1. Theme update is available.
1. User with administrator privileges has logged in.
1. Known IP address has been locked out (see note below).
1. BC Security plugin has been deactivated.

Note: _Known IP address_ is an IP address from which a successful login attempt had been previously made. Information about successful login attempts is fetched from [event logs](#events-logging).

### Events logging

BC Security logs both short and long lockout events (see [Login Security](#login-security) feature) and the following events triggered by WordPress core:
Expand Down
6 changes: 4 additions & 2 deletions bc-security.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: BC Security
* Plugin URI: https://github.com/chesio/bc-security
* Description: Helps keeping WordPress websites secure. Plugin requires PHP 5.6 or newer to run.
* Version: 0.2.0
* Version: 0.3.0
* Author: Česlav Przywara <[email protected]>
* Author URI: https://www.chesio.com
* Requires at least: 4.7
Expand Down Expand Up @@ -44,6 +44,8 @@
// Construct plugin instance.
$bc_security = new \BlueChip\Security\Plugin($GLOBALS['wpdb']);
// Register activation hook.
register_activation_hook(BC_SECURITY_PLUGIN_FILE, [$bc_security, 'install']);
register_activation_hook(BC_SECURITY_PLUGIN_FILE, [$bc_security, 'activate']);
// Register deactivation hook.
register_deactivation_hook(BC_SECURITY_PLUGIN_FILE, [$bc_security, 'deactivate']);
// Load the plugin.
$bc_security->load();
28 changes: 22 additions & 6 deletions classes/BlueChip/Security/Helpers/FormHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public function renderCheckbox(array $args)
echo '<input ' . $this->printFieldProperties($hidden_properties) . '>';
}
echo '<input ' . $this->printFieldProperties($properties) . '>';

$this->printAppendix($args, true);
}


Expand All @@ -62,9 +64,7 @@ public function renderNumberInput(array $args)

echo '<input ' . $this->printFieldProperties($properties) . '>';

if (isset($args['append'])) {
echo ' ' . esc_html($args['append']);
}
$this->printAppendix($args, true);
}


Expand All @@ -84,6 +84,8 @@ public function renderSelect(array $args)
echo '<option value="' . esc_attr($key) . '"' . selected($key, $args['value'], false) . '>' . esc_html($value) . '</option>';
}
echo '</select>';

$this->printAppendix($args, true);
}


Expand All @@ -105,9 +107,7 @@ public function renderTextArea(array $args)

echo '<textarea ' . $this->printFieldProperties($properties) . '>' . esc_html(implode(PHP_EOL, $args['value'])) . '</textarea>';

if (isset($args['append'])) {
echo '<br>' . esc_html($args['append']);
}
$this->printAppendix($args, false);
}


Expand Down Expand Up @@ -138,4 +138,20 @@ function($key, $value) {
// Join all properties into single string
return implode(' ', $mapped);
}


/**
* Print optional appendix information provided by "description" or "append"
* keys in $args. Note that "description" takes precedence over "append".
* @param array $args
* @param bool $inline
*/
protected function printAppendix(array $args, $inline)
{
if (isset($args['description'])) {
echo sprintf('<%1$s class="description">%2$s</%1$s>', $inline ? 'span' : 'p', esc_html($args['description']));
} elseif (isset($args['append'])) {
echo ($inline ? ' ' : '<br>') . esc_html($args['append']);
}
}
}
22 changes: 22 additions & 0 deletions classes/BlueChip/Security/Helpers/Is.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* @package BC_Security
*/
namespace BlueChip\Security\Helpers;

/**
* Various is::xxx() helpers.
*/
class Is
{
/**
* Return true, if current user is an admin.
*
* @param \WP_User $user
* @return bool
*/
public static function admin(\WP_User $user)
{
return is_multisite() ? user_can($user, 'manage_network') : user_can($user, 'manage_options');
}
}
16 changes: 16 additions & 0 deletions classes/BlueChip/Security/Modules/Deactivateable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
/**
* @package BC_Security
*/
namespace BlueChip\Security\Modules;

/**
* @internal Surely the ugliest English "word" that I came up with in a long time...
*/
interface Deactivateable
{
/**
* Deactivate module (clean caches, URL redirects etc.)
*/
public function deactivate();
}
16 changes: 16 additions & 0 deletions classes/BlueChip/Security/Modules/Log/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,20 @@ public function getEventIds()

return is_array($result) ? wp_list_pluck($result, 'event') : [];
}


/**
* Return list of distinct IP addresses from which a successful login has
* been made.
*
* @return array
*/
public function getKnownIps()
{
$result = $this->wpdb->get_results(
$this->wpdb->prepare("SELECT DISTINCT(ip_address) FROM {$this->log_table} WHERE event = %s", Event::LOGIN_SUCCESSFUL)
);

return is_array($result) ? wp_list_pluck($result, 'ip_address') : [];
}
}
2 changes: 1 addition & 1 deletion classes/BlueChip/Security/Modules/Login/AdminPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function __construct($settings)


/**
* Render admin page
* Render admin page.
*/
public function render()
{
Expand Down
8 changes: 4 additions & 4 deletions classes/BlueChip/Security/Modules/Login/Gatekeeper.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
*/
class Gatekeeper implements \BlueChip\Security\Modules\Initializable, \BlueChip\Security\Modules\Loadable
{
/** @var \BlueChip\Security\Modules\Login\Settings */
private $settings;

/** @var string */
private $remote_address;

/** @var \BlueChip\Security\Modules\Login\Settings */
private $settings;

/** @var \BlueChip\Security\Modules\Login\Bookkeeper */
private $bookkeeper;

Expand All @@ -33,8 +33,8 @@ class Gatekeeper implements \BlueChip\Security\Modules\Initializable, \BlueChip\
*/
public function __construct(Settings $settings, $remote_address, Bookkeeper $bookkeeper, IpBlacklist\Manager $bl_manager)
{
$this->settings = $settings;
$this->remote_address = $remote_address;
$this->settings = $settings;
$this->bookkeeper = $bookkeeper;
$this->bl_manager = $bl_manager;
}
Expand Down
113 changes: 113 additions & 0 deletions classes/BlueChip/Security/Modules/Notifications/AdminPage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php
/**
* @package BC_Security
*/

namespace BlueChip\Security\Modules\Notifications;

class AdminPage extends \BlueChip\Security\Core\AdminSettingsPage
{
/** @var string Page slug */
const SLUG = 'bc-security-notifications';


/**
* @param \BlueChip\Security\Modules\Login\Settings $settings Notifications settings
*/
function __construct($settings)
{
parent::__construct($settings);

$this->page_title = _x('Notifications Settings', 'Dashboard page title', 'bc-security');
$this->menu_title = _x('Notifications', 'Dashboard menu item name', 'bc-security');
$this->slug = self::SLUG;
}


/**
* Render admin page.
*/
public function render()
{
echo '<div class="wrap">';
echo '<h1>' . esc_html($this->page_title) . '</h1>';
echo $this->settings_api_helper->renderForm();
echo '</div>';
}


/**
* Run on `admin_init` hook.
*/
public function admin_init()
{
// Form helper is going to be useful here.
$form_helper = new \BlueChip\Security\Helpers\FormHelper();

// Shortcut
$settings_api_helper = $this->settings_api_helper;

// Register setting first.
$settings_api_helper->register();

// Set page as current.
$settings_api_helper->setSettingsPage($this->slug);

// Section: When to notify?
$settings_api_helper->addSettingsSection(
'when-to-notify',
_x('When to send notification?', 'Settings section title', 'bc-security'),
function () {
echo '<p>' . esc_html__('Immediately send email notification when:', 'bc-security') . '</p>';
}
);
$settings_api_helper->addSettingsField(
Settings::ADMIN_USER_LOGIN,
__('User with admin privileges logs in', 'bc-security'),
[$form_helper, 'renderCheckbox']
);
$settings_api_helper->addSettingsField(
Settings::KNOWN_IP_LOCKOUT,
__('Known IP address is locked out', 'bc-security'),
[$form_helper, 'renderCheckbox']
);
$settings_api_helper->addSettingsField(
Settings::CORE_UPDATE_AVAILABLE,
__('WordPress update is available', 'bc-security'),
[$form_helper, 'renderCheckbox']
);
$settings_api_helper->addSettingsField(
Settings::PLUGIN_UPDATE_AVAILABLE,
__('Plugin update is available', 'bc-security'),
[$form_helper, 'renderCheckbox']
);
$settings_api_helper->addSettingsField(
Settings::THEME_UPDATE_AVAILABLE,
__('Theme update is available', 'bc-security'),
[$form_helper, 'renderCheckbox']
);
$settings_api_helper->addSettingsField(
Settings::PLUGIN_DEACTIVATED,
__('BC Security is deactivated', 'bc-security'),
[$form_helper, 'renderCheckbox']
);

// Section: Who to notify?
$settings_api_helper->addSettingsSection(
'who-to-notify',
_x('Whom to send notification?', 'Settings section title', 'bc-security')
);
$settings_api_helper->addSettingsField(
Settings::NOTIFY_SITE_ADMIN,
__('Notify site admin', 'bc-security'),
[$form_helper, 'renderCheckbox'],
[ 'description' => sprintf(__('Currently: %s', 'bc-security'), get_option('admin_email')), ]
);
$settings_api_helper->addSettingsField(
Settings::NOTIFICATION_RECIPIENTS,
__('Send notifications to:', 'bc-security'),
[$form_helper, 'renderTextArea'],
[ 'description' => __('Enter one email per line.', 'bc-security'), ]
);
}
}
76 changes: 76 additions & 0 deletions classes/BlueChip/Security/Modules/Notifications/Mailman.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
/**
* @package BC_Security
*/

namespace BlueChip\Security\Modules\Notifications;

use BlueChip\Security\Modules\Notifications\AdminPage;


abstract class Mailman
{
/** @var string End-of-line character for email body. */
const EOL = "\r\n";

/**
* Add some boilerplate to $subject and $message and send notification via wp_mail().
*
* @see wp_mail()
*
* @param array|string $to Email address(es) of notification recipient(s).
* @param string $subject Subject of notification.
* @param array|string $message Body of notification.
* @return bool True, if notifications was sent successfully, false otherwise.
*/
public static function send($to, $subject, $message)
{
return wp_mail(
$to,
self::formatSubject($subject),
self::formatMessage(is_array($message) ? $message : [$message])
);
}


/**
* Add plugin boilerplate to $message.
*
* @param array $message Message body as list of lines.
* @return string
*/
private static function formatMessage(array $message)
{
$boilerplate_intro = [
sprintf(
__('This email was sent from your website "%1$s" by BC Security plugin on %2$s at %3$s.'),
get_option('blogname'),
date_i18n('d.m.Y'),
date_i18n('H:i:s')
),
'',
];

$boilerplate_outro = [
'',
sprintf(
__('To change your notification settings, visit: %s', 'bc-security'),
AdminPage::getPageUrl(AdminPage::SLUG)
),
];

return implode(self::EOL, array_merge($boilerplate_intro, $message, $boilerplate_outro));
}


/**
* Prepare subject for email (prepend site name and "BC Security Alert").
*
* @param string $subject
* @return string
*/
private static function formatSubject($subject)
{
return sprintf('[%s | %s] %s', get_option('blogname'), __('BC Security Alert', 'bc-security'), $subject);
}
}
Loading

0 comments on commit 833a1f5

Please sign in to comment.