Added a UI for managing the IP blacklist.

This commit is contained in:
flash 2018-12-26 17:03:26 +01:00
parent 3f12ff7d8d
commit 38cb13aefe
9 changed files with 191 additions and 17 deletions

View file

@ -0,0 +1,31 @@
.manage__blacklist {
display: flex;
justify-content: space-evenly;
@media (max-width: @site-mobile-width) {
flex-direction: column;
}
&__form {
margin: 2px;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
&__select,
&__textarea {
margin: 0;
padding: 5px 10px;
font-family: monospace;
width: 100%;
min-width: 100%;
max-width: 100%;
min-height: 400px;
}
&__button {
margin-top: 1px;
}
}

View file

@ -17,4 +17,11 @@
&__content {
flex: 1 1 auto;
}
&__description {
font-size: .9em;
margin: 1px 2px;
border-bottom: 1px solid var(--accent-colour);
padding: 2px 5px;
}
}

View file

@ -114,6 +114,7 @@ html {
// Manage
@import "classes/manage/manage";
@import "classes/manage/navigation";
@import "classes/manage/blacklist";
// Profile
@import "classes/profile/profile";

View file

@ -92,4 +92,52 @@ switch ($_GET['v'] ?? null) {
echo tpl_render('manage.general.settings');
break;
case 'blacklist':
if (!perms_check($generalPerms, MSZ_PERM_GENERAL_MANAGE_BLACKLIST)) {
echo render_error(403);
break;
}
$notices = [];
while (!empty($_POST)) {
if (!csrf_verify('ip_blacklist', $_POST['csrf'] ?? '')) {
$notices[] = 'Verification failed.';
break;
}
header(csrf_http_header('ip_blacklist'));
if (!empty($_POST['blacklist']['remove']) && is_array($_POST['blacklist']['remove'])) {
foreach ($_POST['blacklist']['remove'] as $cidr) {
if (!ip_blacklist_remove($cidr)) {
$notices[] = sprintf('Failed to remove "%s" from the blacklist.', $cidr);
}
}
}
if (!empty($_POST['blacklist']['add']) && is_string($_POST['blacklist']['add'])) {
$cidrs = explode("\n", $_POST['blacklist']['add']);
foreach ($cidrs as $cidr) {
$cidr = trim($cidr);
if (empty($cidr)) {
continue;
}
if (!ip_blacklist_add($cidr)) {
$notices[] = sprintf('Failed to add "%s" to the blacklist.', $cidr);
}
}
}
break;
}
echo tpl_render('manage.general.blacklist', [
'notices' => $notices,
'blacklist' => ip_blacklist_list(),
]);
break;
}

View file

@ -93,7 +93,7 @@ function ip_match_cidr(string $address, string $cidr): bool
return ip_match_cidr_raw($address, $subnet, $mask);
}
function ip_cidr_to_raw(string $cidr): array
function ip_cidr_to_raw(string $cidr): ?array
{
if (strpos($cidr, '/') !== false) {
[$subnet, $mask] = explode('/', $cidr, 2);
@ -101,8 +101,13 @@ function ip_cidr_to_raw(string $cidr): array
$subnet = $cidr;
}
$subnet = inet_pton($subnet);
$mask = empty($mask) ? null : $mask;
try {
$subnet = inet_pton($subnet);
} catch (Exception $ex) {
return null;
}
$mask = empty($mask) ? null : (int)$mask;
return compact('subnet', 'mask');
}
@ -138,7 +143,7 @@ function ip_blacklist_add_raw(string $subnet, ?int $mask = null): bool
}
$addBlacklist = db_prepare('
INSERT INTO `msz_ip_blacklist`
REPLACE INTO `msz_ip_blacklist`
(`ip_subnet`, `ip_mask`)
VALUES
(:subnet, :mask)
@ -150,7 +155,48 @@ function ip_blacklist_add_raw(string $subnet, ?int $mask = null): bool
function ip_blacklist_add(string $cidr): bool
{
[$subnet, $mask] = ['', 0];
extract(ip_cidr_to_raw($cidr));
return ip_blacklist_add_raw($subnet, $mask);
$raw = ip_cidr_to_raw($cidr);
if (empty($raw)) {
return false;
}
return ip_blacklist_add_raw($raw['subnet'], $raw['mask']);
}
function ip_blacklist_remove_raw(string $subnet, ?int $mask = null): bool
{
$removeBlacklist = db_prepare('
DELETE FROM `msz_ip_blacklist`
WHERE `ip_subnet` = :subnet
AND `ip_mask` = :mask
');
$removeBlacklist->bindValue('subnet', $subnet);
$removeBlacklist->bindValue('mask', $mask);
return $removeBlacklist->execute();
}
function ip_blacklist_remove(string $cidr): bool
{
$raw = ip_cidr_to_raw($cidr);
if (empty($raw)) {
return false;
}
return ip_blacklist_remove_raw($raw['subnet'], $raw['mask']);
}
function ip_blacklist_list(): array
{
$getBlacklist = db_query("
SELECT
INET6_NTOA(`ip_subnet`) AS `ip_subnet`,
`ip_mask`,
LENGTH(`ip_subnet`) AS `ip_bytes`,
CONCAT(INET6_NTOA(`ip_subnet`), '/', `ip_mask`) as `ip_cidr`
FROM `msz_ip_blacklist`
");
$blacklist = $getBlacklist->execute() ? $getBlacklist->fetchAll(PDO::FETCH_ASSOC) : false;
return $blacklist ? $blacklist : [];
}

View file

@ -13,7 +13,7 @@ define('MSZ_PERM_USER_MANAGE_ROLES', 1 << 21);
define('MSZ_PERM_USER_MANAGE_PERMS', 1 << 22);
define('MSZ_PERM_USER_MANAGE_REPORTS', 1 << 23);
define('MSZ_PERM_USER_MANAGE_RESTRICTIONS', 1 << 24);
define('MSZ_PERM_USER_MANAGE_BLACKLISTS', 1 << 25);
//define('MSZ_PERM_USER_MANAGE_BLACKLISTS', 1 << 25); // Replaced with MSZ_PERM_GENERAL_MANAGE_BLACKLIST
define(
'MSZ_USERS_PASSWORD_HASH_ALGO',

View file

@ -4,3 +4,4 @@ define('MSZ_PERM_GENERAL_VIEW_LOGS', 1 << 1);
define('MSZ_PERM_GENERAL_MANAGE_EMOTICONS', 1 << 2);
define('MSZ_PERM_GENERAL_MANAGE_SETTINGS', 1 << 3);
define('MSZ_PERM_GENERAL_TESTER', 1 << 4);
define('MSZ_PERM_GENERAL_MANAGE_BLACKLIST', 1 << 5);

View file

@ -27,6 +27,10 @@ function manage_get_menu(int $userId): array
$menu['General']['Settings'] = '/manage/index.php?v=settings';
}
if (perms_check($perms['general'], MSZ_PERM_GENERAL_MANAGE_BLACKLIST)) {
$menu['General']['IP Blacklist'] = '/manage/index.php?v=blacklist';
}
if (perms_check($perms['user'], MSZ_PERM_USER_MANAGE_USERS | MSZ_PERM_USER_MANAGE_PERMS)) {
$menu['Users']['Listing'] = '/manage/users.php?v=listing';
}
@ -43,10 +47,6 @@ function manage_get_menu(int $userId): array
$menu['Users']['Restrictions'] = '/manage/users.php?v=restrictions';
}
if (perms_check($perms['user'], MSZ_PERM_USER_MANAGE_BLACKLISTS)) {
$menu['Users']['Blacklisting'] = '/manage/users.php?v=blacklisting';
}
if (perms_check($perms['news'], MSZ_PERM_NEWS_MANAGE_POSTS)) {
$menu['News']['Posts'] = '/manage/news.php?v=posts';
}
@ -199,6 +199,11 @@ function manage_perms_list(array $rawPerms): array
'title' => 'Can use experimental features.',
'perm' => MSZ_PERM_GENERAL_TESTER,
],
[
'section' => 'manage-blacklist',
'title' => 'Can manage blacklistings.',
'perm' => MSZ_PERM_GENERAL_MANAGE_BLACKLIST,
],
],
],
[
@ -250,11 +255,6 @@ function manage_perms_list(array $rawPerms): array
'title' => 'Can manage restrictions.',
'perm' => MSZ_PERM_USER_MANAGE_RESTRICTIONS,
],
[
'section' => 'manage-blacklistings',
'title' => 'Can manage blacklistings.',
'perm' => MSZ_PERM_USER_MANAGE_BLACKLISTS,
],
],
],
[

View file

@ -0,0 +1,40 @@
{% extends 'manage/general/master.twig' %}
{% from 'macros.twig' import container_title, pagination %}
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select %}
{% block manage_content %}
<div class="container">
{{ container_title('<i class="fas fa-shield-alt"></i> IP Blacklist', '', true) }}
<div class="manage__description">
Here you can add or remove CIDR ranges to the IP Blacklist, these ranges are allowed to log into the site but cannot create accounts.
</div>
{% if notices|length > 0 %}
<div class="warning">
<div class="warning__content">
{% for notice in notices %}
{{ notice }}
{% endfor %}
</div>
</div>
{% endif %}
<div class="manage__blacklist">
<form action="" method="post" class="manage__blacklist__form">
{{ input_csrf('ip_blacklist') }}
<textarea name="blacklist[add]" class="input__textarea manage__blacklist__textarea" placeholder="Enter CIDR (subnet/mask), each line will be processed. Addresses without a mask will just be blacklisted alone."></textarea>
<button class="input__button input__button--save manage__blacklist__button">Add</button>
</form>
<form action="" method="post" class="manage__blacklist__form">
{{ input_csrf('ip_blacklist') }}
{{ input_select('blacklist[remove][]', blacklist, null, 'ip_cidr', null, true, 'manage__blacklist__select', {
'multiple': true,
'size': 10,
}) }}
<button class="input__button input__button--destroy manage__blacklist__button">Remove</button>
</form>
</div>
</div>
{% endblock %}