Added a UI for managing the IP blacklist.
This commit is contained in:
parent
3f12ff7d8d
commit
38cb13aefe
9 changed files with 191 additions and 17 deletions
31
assets/less/classes/manage/blacklist.less
Normal file
31
assets/less/classes/manage/blacklist.less
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,4 +17,11 @@
|
||||||
&__content {
|
&__content {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
font-size: .9em;
|
||||||
|
margin: 1px 2px;
|
||||||
|
border-bottom: 1px solid var(--accent-colour);
|
||||||
|
padding: 2px 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ html {
|
||||||
// Manage
|
// Manage
|
||||||
@import "classes/manage/manage";
|
@import "classes/manage/manage";
|
||||||
@import "classes/manage/navigation";
|
@import "classes/manage/navigation";
|
||||||
|
@import "classes/manage/blacklist";
|
||||||
|
|
||||||
// Profile
|
// Profile
|
||||||
@import "classes/profile/profile";
|
@import "classes/profile/profile";
|
||||||
|
|
|
@ -92,4 +92,52 @@ switch ($_GET['v'] ?? null) {
|
||||||
|
|
||||||
echo tpl_render('manage.general.settings');
|
echo tpl_render('manage.general.settings');
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ function ip_match_cidr(string $address, string $cidr): bool
|
||||||
return ip_match_cidr_raw($address, $subnet, $mask);
|
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) {
|
if (strpos($cidr, '/') !== false) {
|
||||||
[$subnet, $mask] = explode('/', $cidr, 2);
|
[$subnet, $mask] = explode('/', $cidr, 2);
|
||||||
|
@ -101,8 +101,13 @@ function ip_cidr_to_raw(string $cidr): array
|
||||||
$subnet = $cidr;
|
$subnet = $cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$subnet = inet_pton($subnet);
|
$subnet = inet_pton($subnet);
|
||||||
$mask = empty($mask) ? null : $mask;
|
} catch (Exception $ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mask = empty($mask) ? null : (int)$mask;
|
||||||
|
|
||||||
return compact('subnet', 'mask');
|
return compact('subnet', 'mask');
|
||||||
}
|
}
|
||||||
|
@ -138,7 +143,7 @@ function ip_blacklist_add_raw(string $subnet, ?int $mask = null): bool
|
||||||
}
|
}
|
||||||
|
|
||||||
$addBlacklist = db_prepare('
|
$addBlacklist = db_prepare('
|
||||||
INSERT INTO `msz_ip_blacklist`
|
REPLACE INTO `msz_ip_blacklist`
|
||||||
(`ip_subnet`, `ip_mask`)
|
(`ip_subnet`, `ip_mask`)
|
||||||
VALUES
|
VALUES
|
||||||
(:subnet, :mask)
|
(:subnet, :mask)
|
||||||
|
@ -150,7 +155,48 @@ function ip_blacklist_add_raw(string $subnet, ?int $mask = null): bool
|
||||||
|
|
||||||
function ip_blacklist_add(string $cidr): bool
|
function ip_blacklist_add(string $cidr): bool
|
||||||
{
|
{
|
||||||
[$subnet, $mask] = ['', 0];
|
$raw = ip_cidr_to_raw($cidr);
|
||||||
extract(ip_cidr_to_raw($cidr));
|
|
||||||
return ip_blacklist_add_raw($subnet, $mask);
|
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 : [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_PERMS', 1 << 22);
|
||||||
define('MSZ_PERM_USER_MANAGE_REPORTS', 1 << 23);
|
define('MSZ_PERM_USER_MANAGE_REPORTS', 1 << 23);
|
||||||
define('MSZ_PERM_USER_MANAGE_RESTRICTIONS', 1 << 24);
|
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(
|
define(
|
||||||
'MSZ_USERS_PASSWORD_HASH_ALGO',
|
'MSZ_USERS_PASSWORD_HASH_ALGO',
|
||||||
|
|
|
@ -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_EMOTICONS', 1 << 2);
|
||||||
define('MSZ_PERM_GENERAL_MANAGE_SETTINGS', 1 << 3);
|
define('MSZ_PERM_GENERAL_MANAGE_SETTINGS', 1 << 3);
|
||||||
define('MSZ_PERM_GENERAL_TESTER', 1 << 4);
|
define('MSZ_PERM_GENERAL_TESTER', 1 << 4);
|
||||||
|
define('MSZ_PERM_GENERAL_MANAGE_BLACKLIST', 1 << 5);
|
||||||
|
|
|
@ -27,6 +27,10 @@ function manage_get_menu(int $userId): array
|
||||||
$menu['General']['Settings'] = '/manage/index.php?v=settings';
|
$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)) {
|
if (perms_check($perms['user'], MSZ_PERM_USER_MANAGE_USERS | MSZ_PERM_USER_MANAGE_PERMS)) {
|
||||||
$menu['Users']['Listing'] = '/manage/users.php?v=listing';
|
$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';
|
$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)) {
|
if (perms_check($perms['news'], MSZ_PERM_NEWS_MANAGE_POSTS)) {
|
||||||
$menu['News']['Posts'] = '/manage/news.php?v=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.',
|
'title' => 'Can use experimental features.',
|
||||||
'perm' => MSZ_PERM_GENERAL_TESTER,
|
'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.',
|
'title' => 'Can manage restrictions.',
|
||||||
'perm' => MSZ_PERM_USER_MANAGE_RESTRICTIONS,
|
'perm' => MSZ_PERM_USER_MANAGE_RESTRICTIONS,
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'section' => 'manage-blacklistings',
|
|
||||||
'title' => 'Can manage blacklistings.',
|
|
||||||
'perm' => MSZ_PERM_USER_MANAGE_BLACKLISTS,
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
40
templates/manage/general/blacklist.twig
Normal file
40
templates/manage/general/blacklist.twig
Normal 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 %}
|
Loading…
Add table
Reference in a new issue