Merge pull request #6518 from marc1706/ticket/9687-new

[ticket/9687] Refactor banning
This commit is contained in:
Marc Alexander 2023-11-06 21:52:40 +01:00 committed by GitHub
commit 604d776dd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 3089 additions and 927 deletions

View file

@ -11,11 +11,11 @@
<script>
// <![CDATA[
var ban_length = new Array();
const ban_length = [];
ban_length[-1] = '';
var ban_reason = new Array();
const ban_reason = [];
ban_reason[-1] = '';
var ban_give_reason = new Array();
const ban_give_reason = [];
ban_give_reason[-1] = '';
<!-- BEGIN bans -->
@ -43,6 +43,19 @@
}
}
document.addEventListener("DOMContentLoaded", () => {
const $unbanSelect = document.getElementById('unban');
if ($unbanSelect) {
$unbanSelect.addEventListener('change', function () {
if (this.selectedIndex > -1) {
display_details(this.options[this.selectedIndex].value);
} else {
display_details(-1);
}
});
}
});
// ]]>
</script>
@ -60,11 +73,6 @@
<dd><label for="banlength"><select name="banlength" id="banlength" onchange="if(this.value==-1){document.getElementById('banlengthother').style.display = 'block';}else{document.getElementById('banlengthother').style.display='none';}">{S_BAN_END_OPTIONS}</select></label></dd>
<dd id="banlengthother" style="display: none;"><label><input type="text" name="banlengthother" class="inputbox" /><br /><span>{L_YEAR_MONTH_DAY}</span></label></dd>
</dl>
<dl>
<dt><label for="banexclude">{L_BAN_EXCLUDE}{L_COLON}</label><br /><span>{L_BAN_EXCLUDE_EXPLAIN}</span></dt>
<dd><label><input type="radio" name="banexclude" value="1" class="radio" /> {L_YES}</label>
<label><input type="radio" name="banexclude" id="banexclude" value="0" checked="checked" class="radio" /> {L_NO}</label></dd>
</dl>
<dl>
<dt><label for="banreason">{L_BAN_REASON}{L_COLON}</label></dt>
<dd><input name="banreason" type="text" class="text medium" maxlength="255" id="banreason" /></dd>
@ -90,44 +98,41 @@
<p>{L_UNBAN_EXPLAIN}</p>
<form id="acp_unban" method="post" action="{U_ACTION}">
<form id="acp_unban" method="post" action="{{ U_ACTION }}">
<fieldset>
<legend>{L_UNBAN_TITLE}</legend>
<legend>{{ lang('UNBAN_TITLE') }}</legend>
<!-- IF S_BANNED_OPTIONS -->
{% if BANNED_SELECT %}
<dl>
<dt><label for="unban">{L_BAN_CELL}{L_COLON}</label></dt>
<dd><select id="unban" name="unban[]" multiple="multiple" size="10" style="width: 50%" onchange="if (this.selectedIndex > -1) display_details(this.options[this.selectedIndex].value); else display_details(-1);">{BANNED_OPTIONS}</select></dd>
<dt><label for="unban">{{ lang('BAN_CELL') ~ lang('COLON') }}</label></dt>
<dd>
{{ FormsSelect(BANNED_SELECT) }}
</dd>
</dl>
<dl>
<dt><label for="unbanlength">{L_BAN_LENGTH}{L_COLON}</label></dt>
<dt><label for="unbanlength">{{ lang('BAN_LENGTH') ~ lang('COLON') }}</label></dt>
<dd><input style="border: 0;" type="text" class="text full" readonly="readonly" name="unbanlength" id="unbanlength" /></dd>
</dl>
<dl>
<dt><label for="unbanreason">{L_BAN_REASON}{L_COLON}</label></dt>
<dt><label for="unbanreason">{{ lang('BAN_REASON') ~ lang('COLON') }}</label></dt>
<dd><textarea style="border: 0;" class="text full" readonly="readonly" name="unbanreason" id="unbanreason" rows="5" cols="80">&nbsp;</textarea></dd>
</dl>
<dl>
<dt><label for="unbangivereason">{L_BAN_GIVE_REASON}{L_COLON}</label></dt>
<dt><label for="unbangivereason">{{ lang('BAN_GIVE_REASON') ~ lang('COLON') }}</label></dt>
<dd><textarea style="border: 0;" class="text full" readonly="readonly" name="unbangivereason" id="unbangivereason" rows="5" cols="80">&nbsp;</textarea></dd>
</dl>
<p class="submit-buttons">
<input class="button1" type="submit" id="unbansubmit" name="unbansubmit" value="{L_SUBMIT}" />&nbsp;
<input class="button2" type="reset" id="unbanreset" name="unbanreset" value="{L_RESET}" />
<input class="button1" type="submit" id="unbansubmit" name="unbansubmit" value="{{ lang('SUBMIT') }}" />&nbsp;
<input class="button2" type="reset" id="unbanreset" name="unbanreset" value="{{ lang('RESET') }}" />
</p>
{S_FORM_TOKEN}
{% else %}
<p>{{ lang('NO_BAN_CELL') }}</p>
{% endif %}
{{ S_FORM_TOKEN }}
</fieldset>
<!-- ELSE -->
<p>{L_NO_BAN_CELL}</p>
{S_FORM_TOKEN}
</fieldset>
<!-- ENDIF -->
</form>
<!-- INCLUDE overall_footer.html -->

View file

@ -288,6 +288,10 @@ li {
padding-right: 10px;
}
.w-50 {
width: 50%;
}
@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) {
#wrap,
#page-body,

View file

@ -2,6 +2,7 @@ imports:
- { resource: services_attachment.yml }
- { resource: services_auth.yml }
- { resource: services_avatar.yml }
- { resource: services_ban.yml }
- { resource: services_captcha.yml }
- { resource: services_console.yml }
- { resource: services_content.yml }

View file

@ -0,0 +1,54 @@
services:
# ----- Ban management -----
ban.manager:
class: \phpbb\ban\manager
arguments:
- '@ban.type_collection'
- '@cache.driver'
- '@dbal.conn'
- '@language'
- '@log'
- '@user'
- '%tables.bans%'
- '%tables.users%'
# ----- Ban types -----
ban.type_collection:
class: \phpbb\di\service_collection
arguments:
- '@service_container'
tags:
- { name: service_collection, tag: ban.type }
ban.type.email:
class: \phpbb\ban\type\email
arguments:
- '@dbal.conn'
- '%tables.bans%'
- '%tables.users%'
- '%tables.sessions%'
- '%tables.sessions_keys%'
tags:
- { name: ban.type }
ban.type.ip:
class: \phpbb\ban\type\ip
arguments:
- '@dbal.conn'
- '%tables.bans%'
- '%tables.users%'
- '%tables.sessions%'
- '%tables.sessions_keys%'
tags:
- { name: ban.type }
ban.type.user:
class: \phpbb\ban\type\user
arguments:
- '@dbal.conn'
- '%tables.bans%'
- '%tables.users%'
- '%tables.sessions%'
- '%tables.sessions_keys%'
tags:
- { name: ban.type }

View file

@ -9,7 +9,7 @@ parameters:
tables.auth_provider_oauth_states: '%core.table_prefix%oauth_states'
tables.auth_provider_oauth_account_assoc: '%core.table_prefix%oauth_accounts'
tables.backups: '%core.table_prefix%backups'
tables.banlist: '%core.table_prefix%banlist'
tables.bans: '%core.table_prefix%bans'
tables.bbcodes: '%core.table_prefix%bbcodes'
tables.bookmarks: '%core.table_prefix%bookmarks'
tables.bots: '%core.table_prefix%bots'

View file

@ -14,6 +14,11 @@
/**
* @ignore
*/
use phpbb\ban\exception\type_not_found_exception;
use phpbb\ban\manager;
use phpbb\language\language;
if (!defined('IN_PHPBB'))
{
exit;
@ -25,9 +30,12 @@ class acp_ban
function main($id, $mode)
{
global $user, $template, $request, $phpbb_dispatcher;
global $language, $template, $request, $phpbb_dispatcher, $phpbb_container;
global $phpbb_root_path, $phpEx;
/** @var manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
if (!function_exists('user_ban'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
@ -36,14 +44,15 @@ class acp_ban
$bansubmit = $request->is_set_post('bansubmit');
$unbansubmit = $request->is_set_post('unbansubmit');
$user->add_lang(array('acp/ban', 'acp/users'));
/** @var language $language */
$language->add_lang(['acp/ban', 'acp/users']);
$this->tpl_name = 'acp_ban';
$form_key = 'acp_ban';
add_form_key($form_key);
if (($bansubmit || $unbansubmit) && !check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Ban submitted?
@ -53,7 +62,6 @@ class acp_ban
$ban = $request->variable('ban', '', true);
$ban_length = $request->variable('banlength', 0);
$ban_length_other = $request->variable('banlengthother', '');
$ban_exclude = $request->variable('banexclude', 0);
$ban_reason = $request->variable('banreason', '', true);
$ban_give_reason = $request->variable('bangivereason', '', true);
@ -68,7 +76,6 @@ class acp_ban
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @var mixed abort_ban Either false, or an error message that is displayed to the user.
@ -80,7 +87,6 @@ class acp_ban
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
'abort_ban',
@ -91,7 +97,20 @@ class acp_ban
{
trigger_error($abort_ban . adm_back_link($this->u_action));
}
user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason);
$ban_start = new \DateTime();
$ban_start->setTimestamp(time());
$ban_end = $ban_manager->get_ban_end($ban_start, $ban_length, $ban_length_other);
$ban = explode("\n", $ban);
try
{
$ban_manager->ban($mode, $ban, $ban_start, $ban_end, $ban_reason, $ban_give_reason);
}
catch (\phpbb\exception\exception_interface $exception)
{
trigger_error($language->lang_array($exception->getMessage(), $exception->get_parameters()), E_USER_WARNING);
}
/**
* Use this event to perform actions after the ban has been performed
@ -101,7 +120,6 @@ class acp_ban
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @since 3.1.0-RC5
@ -111,49 +129,50 @@ class acp_ban
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
);
extract($phpbb_dispatcher->trigger_event('core.acp_ban_after', compact($vars)));
trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . adm_back_link($this->u_action));
trigger_error($language->lang('BAN_UPDATE_SUCCESSFUL') . adm_back_link($this->u_action));
}
}
else if ($unbansubmit)
{
$ban = $request->variable('unban', array(''));
$ban = $request->variable('unban', ['']);
if ($ban)
{
user_unban($mode, $ban);
$ban_manager->unban($mode, $ban);
trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . adm_back_link($this->u_action));
trigger_error($language->lang('BAN_UPDATE_SUCCESSFUL') . adm_back_link($this->u_action));
}
}
// Define language vars
$this->page_title = $user->lang[strtoupper($mode) . '_BAN'];
$this->page_title = $language->lang(strtoupper($mode) . '_BAN');
$l_ban_explain = $user->lang[strtoupper($mode) . '_BAN_EXPLAIN'];
$l_ban_exclude_explain = $user->lang[strtoupper($mode) . '_BAN_EXCLUDE_EXPLAIN'];
$l_unban_title = $user->lang[strtoupper($mode) . '_UNBAN'];
$l_unban_explain = $user->lang[strtoupper($mode) . '_UNBAN_EXPLAIN'];
$l_no_ban_cell = $user->lang[strtoupper($mode) . '_NO_BANNED'];
$l_ban_explain = $language->lang(strtoupper($mode) . '_BAN_EXPLAIN');
$l_unban_title = $language->lang(strtoupper($mode) . '_UNBAN');
$l_unban_explain = $language->lang(strtoupper($mode) . '_UNBAN_EXPLAIN');
$l_no_ban_cell = $language->lang(strtoupper($mode) . '_NO_BANNED');
switch ($mode)
{
case 'user':
$l_ban_cell = $user->lang['USERNAME'];
$l_ban_cell = $language->lang('USERNAME');
break;
case 'ip':
$l_ban_cell = $user->lang['IP_HOSTNAME'];
$l_ban_cell = $language->lang('IP_HOSTNAME');
break;
case 'email':
$l_ban_cell = $user->lang['EMAIL_ADDRESS'];
$l_ban_cell = $language->lang('EMAIL_ADDRESS');
break;
default:
throw new type_not_found_exception();
}
display_ban_end_options();
@ -165,10 +184,9 @@ class acp_ban
'L_UNBAN_TITLE' => $l_unban_title,
'L_UNBAN_EXPLAIN' => $l_unban_explain,
'L_BAN_CELL' => $l_ban_cell,
'L_BAN_EXCLUDE_EXPLAIN' => $l_ban_exclude_explain,
'L_NO_BAN_CELL' => $l_no_ban_cell,
'S_USERNAME_BAN' => ($mode == 'user') ? true : false,
'S_USERNAME_BAN' => $mode == 'user' ? true : false,
'U_ACTION' => $this->u_action,
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=acp_ban&amp;field=ban'),

View file

@ -26,7 +26,7 @@ class acp_email
function main($id, $mode)
{
global $config, $db, $user, $template, $phpbb_log, $request;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_dispatcher;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
$user->add_lang('acp/email');
$this->tpl_name = 'acp_email';
@ -74,7 +74,7 @@ class acp_email
{
// If giving usernames the admin is able to email inactive users too...
$sql_ary = array(
'SELECT' => 'username, user_email, user_jabber, user_notify_type, user_lang',
'SELECT' => 'user_id, username, user_email, user_jabber, user_notify_type, user_lang',
'FROM' => array(
USERS_TABLE => '',
),
@ -88,7 +88,7 @@ class acp_email
if ($group_id)
{
$sql_ary = array(
'SELECT' => 'u.user_email, u.username, u.username_clean, u.user_lang, u.user_jabber, u.user_notify_type',
'SELECT' => 'u.user_id, u.user_email, u.username, u.username_clean, u.user_lang, u.user_jabber, u.user_notify_type',
'FROM' => array(
USERS_TABLE => 'u',
USER_GROUP_TABLE => 'ug',
@ -104,7 +104,7 @@ class acp_email
else
{
$sql_ary = array(
'SELECT' => 'u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type',
'SELECT' => 'u.user_id, u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type',
'FROM' => array(
USERS_TABLE => 'u',
),
@ -113,21 +113,6 @@ class acp_email
'ORDER_BY' => 'u.user_lang, u.user_notify_type',
);
}
// Mail banned or not
if (!isset($_REQUEST['mail_banned_flag']))
{
$sql_ary['WHERE'] .= ' AND (b.ban_id IS NULL
OR b.ban_exclude = 1)';
$sql_ary['LEFT_JOIN'] = array(
array(
'FROM' => array(
BANLIST_TABLE => 'b',
),
'ON' => 'u.user_id = b.ban_userid',
),
);
}
}
/**
* Modify sql query to change the list of users the email is sent to
@ -141,11 +126,22 @@ class acp_email
$sql = $db->sql_build_query('SELECT', $sql_ary);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
if (!$row)
{
$rows = $db->sql_fetchrowset($result);
$db->sql_freeresult($result);
if (!empty($rows) && !$request->is_set('mail_banned_flag'))
{
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$banned_users = $ban_manager->get_banned_users();
$rows = array_filter($rows, function ($row) use ($banned_users) {
return !isset($banned_users[(int) $row['user_id']]);
});
}
if (empty($rows))
{
trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@ -155,10 +151,10 @@ class acp_email
// Maximum number of bcc recipients
$max_chunk_size = (int) $config['email_max_chunk_size'];
$email_list = array();
$old_lang = $row['user_lang'];
$old_notify_type = $row['user_notify_type'];
$old_lang = $rows[0]['user_lang'];
$old_notify_type = $rows[0]['user_notify_type'];
do
foreach ($rows as $row)
{
if (($row['user_notify_type'] == NOTIFY_EMAIL && $row['user_email']) ||
($row['user_notify_type'] == NOTIFY_IM && $row['user_jabber']) ||
@ -185,8 +181,6 @@ class acp_email
$i++;
}
}
while ($row = $db->sql_fetchrow($result));
$db->sql_freeresult($result);
// Send the messages
if (!class_exists('messenger'))

View file

@ -239,7 +239,7 @@ define('ACL_ROLES_TABLE', $table_prefix . 'acl_roles');
define('ACL_USERS_TABLE', $table_prefix . 'acl_users');
define('ATTACHMENTS_TABLE', $table_prefix . 'attachments');
define('BACKUPS_TABLE', $table_prefix . 'backups');
define('BANLIST_TABLE', $table_prefix . 'banlist');
define('BANS_TABLE', $table_prefix . 'bans');
define('BBCODES_TABLE', $table_prefix . 'bbcodes');
define('BOOKMARKS_TABLE', $table_prefix . 'bookmarks');
define('BOTS_TABLE', $table_prefix . 'bots');

View file

@ -3156,109 +3156,68 @@ function display_ban_end_options()
*/
function display_ban_options($mode)
{
global $user, $db, $template;
global $language, $user, $template, $phpbb_container;
switch ($mode)
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$ban_rows = $ban_manager->get_bans($mode);
$banned_options = [];
foreach ($ban_rows as $ban_row)
{
case 'user':
$banned_options[] = [
'value' => $ban_row['ban_id'],
'label' => $ban_row['label'] ?? $ban_row['ban_item'],
];
$field = 'username';
$sql = 'SELECT b.*, u.user_id, u.username, u.username_clean
FROM ' . BANLIST_TABLE . ' b, ' . USERS_TABLE . ' u
WHERE (b.ban_end >= ' . time() . '
OR b.ban_end = 0)
AND u.user_id = b.ban_userid
ORDER BY u.username_clean ASC';
break;
case 'ip':
$field = 'ban_ip';
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
WHERE (ban_end >= ' . time() . "
OR ban_end = 0)
AND ban_ip <> ''
ORDER BY ban_ip";
break;
case 'email':
$field = 'ban_email';
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
WHERE (ban_end >= ' . time() . "
OR ban_end = 0)
AND ban_email <> ''
ORDER BY ban_email";
break;
}
$result = $db->sql_query($sql);
$banned_options = $excluded_options = array();
while ($row = $db->sql_fetchrow($result))
{
$option = '<option value="' . $row['ban_id'] . '">' . $row[$field] . '</option>';
if ($row['ban_exclude'])
{
$excluded_options[] = $option;
}
else
{
$banned_options[] = $option;
}
$time_length = ($row['ban_end']) ? ($row['ban_end'] - $row['ban_start']) / 60 : 0;
$time_length = ($ban_row['ban_end']) ? ($ban_row['ban_end'] - $ban_row['ban_start']) / 60 : 0;
if ($time_length == 0)
{
// Banned permanently
$ban_length = $user->lang['PERMANENT'];
$ban_length = $language->lang('PERMANENT');
}
else if (isset($ban_end_text[$time_length]))
{
// Banned for a given duration
$ban_length = $user->lang('BANNED_UNTIL_DURATION', $ban_end_text[$time_length], $user->format_date($row['ban_end'], false, true));
$ban_length = $language->lang('BANNED_UNTIL_DURATION', $ban_end_text[$time_length], $user->format_date($ban_row['ban_end'], false, true));
}
else
{
// Banned until given date
$ban_length = $user->lang('BANNED_UNTIL_DATE', $user->format_date($row['ban_end'], false, true));
$ban_length = $language->lang('BANNED_UNTIL_DATE', $user->format_date($ban_row['ban_end'], false, true));
}
$template->assign_block_vars('bans', array(
'BAN_ID' => (int) $row['ban_id'],
'BAN_ID' => (int) $ban_row['ban_id'],
'LENGTH' => $ban_length,
'A_LENGTH' => addslashes($ban_length),
'REASON' => $row['ban_reason'],
'A_REASON' => addslashes($row['ban_reason']),
'GIVE_REASON' => $row['ban_give_reason'],
'A_GIVE_REASON' => addslashes($row['ban_give_reason']),
'REASON' => $ban_row['ban_reason'],
'A_REASON' => addslashes($ban_row['ban_reason']),
'GIVE_REASON' => $ban_row['ban_reason_display'],
'A_GIVE_REASON' => addslashes($ban_row['ban_reason_display']),
));
}
$db->sql_freeresult($result);
$options = '';
if ($excluded_options)
if (count($banned_options))
{
$options .= '<optgroup label="' . $user->lang['OPTIONS_EXCLUDED'] . '">';
$options .= implode('', $excluded_options);
$options .= '</optgroup>';
}
$banned_select = [
'tag' => 'select',
'name' => 'unban[]',
'id' => 'unban',
'class' => 'w-50',
'multiple' => true,
'size' => 10,
'data' => [
'onchange' => 'display_details',
],
'options' => [[
'label' => $language->lang('OPTIONS_BANNED'),
'options' => $banned_options,
]],
];
if ($banned_options)
{
$options .= '<optgroup label="' . $user->lang['OPTIONS_BANNED'] . '">';
$options .= implode('', $banned_options);
$options .= '</optgroup>';
$template->assign_vars(['BANNED_SELECT' => $banned_select]);
}
$template->assign_vars(array(
'S_BANNED_OPTIONS' => ($banned_options || $excluded_options) ? true : false,
'BANNED_OPTIONS' => $options,
));
}

View file

@ -1632,6 +1632,10 @@ function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabl
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$user_banned = $ban_manager->check($data);
// Can this user receive a Private Message?
$can_receive_pm = $check_can_receive_pm && (
// They must be a "normal" user
@ -1644,7 +1648,7 @@ function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabl
count($auth->acl_get_list($user_id, 'u_readpm')) &&
// They must not be permanently banned
!count(phpbb_get_banned_user_ids($user_id, false)) &&
(empty($user_banned) || $user_banned['end'] > 0) &&
// They must allow users to contact via PM
(($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $data['user_allow_pm'])

View file

@ -749,8 +749,9 @@ function user_delete($mode, $user_ids, $retain_username = true)
$db->sql_query($sql);
// Delete the user_id from the banlist
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
WHERE ' . $db->sql_in_set('ban_userid', $user_ids);
$sql = 'DELETE FROM ' . BANS_TABLE . "
WHERE ban_mode = 'user'
AND " . $db->sql_in_set('ban_userid', $user_ids);
$db->sql_query($sql);
// Delete the user_id from the session table
@ -915,30 +916,26 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
/**
* Add a ban or ban exclusion to the banlist. Bans either a user, an IP or an email address
*
* @deprecated 4.0.0-a1 (To be removed: 4.1.0)
*
* @param string $mode Type of ban. One of the following: user, ip, email
* @param mixed $ban Banned entity. Either string or array with usernames, ips or email addresses
* @param int $ban_len Ban length in minutes
* @param string $ban_len_other Ban length as a date (YYYY-MM-DD)
* @param boolean $ban_exclude Exclude these entities from banning?
* @param string $ban_reason String describing the reason for this ban
* @param string $ban_give_reason
* @return boolean
*/
function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '')
function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_reason, $ban_give_reason = '')
{
global $db, $user, $cache, $phpbb_log;
global $phpbb_container, $user;
// Delete stale bans
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
WHERE ban_end < ' . time() . '
AND ban_end <> 0';
$db->sql_query($sql);
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$ban_list = (!is_array($ban)) ? array_unique(explode("\n", $ban)) : $ban;
$ban_list_log = implode(', ', $ban_list);
$items = is_array($ban) ? $ban : [$ban];
$current_time = time();
// Set $ban_end to the unix time when the ban should end. 0 is a permanent ban.
if ($ban_len)
{
@ -968,482 +965,28 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
$ban_end = 0;
}
$founder = $founder_names = array();
$start = new \DateTime();
$start->setTimestamp($current_time);
$end = new \DateTime();
$end->setTimestamp($ban_end);
if (!$ban_exclude)
{
// Create a list of founder...
$sql = 'SELECT user_id, user_email, username_clean
FROM ' . USERS_TABLE . '
WHERE user_type = ' . USER_FOUNDER;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$founder[$row['user_id']] = $row['user_email'];
$founder_names[$row['user_id']] = $row['username_clean'];
}
$db->sql_freeresult($result);
}
$banlist_ary = array();
switch ($mode)
{
case 'user':
$type = 'ban_userid';
// At the moment we do not support wildcard username banning
// Select the relevant user_ids.
$sql_usernames = array();
foreach ($ban_list as $username)
{
$username = trim($username);
if ($username != '')
{
$clean_name = utf8_clean_string($username);
if ($clean_name == $user->data['username_clean'])
{
trigger_error('CANNOT_BAN_YOURSELF', E_USER_WARNING);
}
if (in_array($clean_name, $founder_names))
{
trigger_error('CANNOT_BAN_FOUNDER', E_USER_WARNING);
}
$sql_usernames[] = $clean_name;
}
}
// Make sure we have been given someone to ban
if (!count($sql_usernames))
{
trigger_error('NO_USER_SPECIFIED', E_USER_WARNING);
}
$sql = 'SELECT user_id
FROM ' . USERS_TABLE . '
WHERE ' . $db->sql_in_set('username_clean', $sql_usernames);
// Do not allow banning yourself, the guest account, or founders.
$non_bannable = array($user->data['user_id'], ANONYMOUS);
if (count($founder))
{
$sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), $non_bannable), true);
}
else
{
$sql .= ' AND ' . $db->sql_in_set('user_id', $non_bannable, true);
}
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
do
{
$banlist_ary[] = (int) $row['user_id'];
}
while ($row = $db->sql_fetchrow($result));
$db->sql_freeresult($result);
}
else
{
$db->sql_freeresult($result);
trigger_error('NO_USERS', E_USER_WARNING);
}
break;
case 'ip':
$type = 'ban_ip';
foreach ($ban_list as $ban_item)
{
if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($ban_item), $ip_range_explode))
{
// This is an IP range
// Don't ask about all this, just don't ask ... !
$ip_1_counter = $ip_range_explode[1];
$ip_1_end = $ip_range_explode[5];
while ($ip_1_counter <= $ip_1_end)
{
$ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0;
$ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6];
if ($ip_2_counter == 0 && $ip_2_end == 254)
{
$ip_2_counter = 256;
$banlist_ary[] = "$ip_1_counter.*";
}
while ($ip_2_counter <= $ip_2_end)
{
$ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0;
$ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7];
if ($ip_3_counter == 0 && $ip_3_end == 254)
{
$ip_3_counter = 256;
$banlist_ary[] = "$ip_1_counter.$ip_2_counter.*";
}
while ($ip_3_counter <= $ip_3_end)
{
$ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0;
$ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8];
if ($ip_4_counter == 0 && $ip_4_end == 254)
{
$ip_4_counter = 256;
$banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*";
}
while ($ip_4_counter <= $ip_4_end)
{
$banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter";
$ip_4_counter++;
}
$ip_3_counter++;
}
$ip_2_counter++;
}
$ip_1_counter++;
}
}
else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($ban_item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($ban_item)))
{
// Normal IP address
$banlist_ary[] = trim($ban_item);
}
else if (preg_match('#^\*$#', trim($ban_item)))
{
// Ban all IPs
$banlist_ary[] = '*';
}
else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($ban_item)))
{
// hostname
$ip_ary = gethostbynamel(trim($ban_item));
if (!empty($ip_ary))
{
foreach ($ip_ary as $ip)
{
if ($ip)
{
if (strlen($ip) > 40)
{
continue;
}
$banlist_ary[] = $ip;
}
}
}
}
if (empty($banlist_ary))
{
trigger_error('NO_IPS_DEFINED', E_USER_WARNING);
}
}
break;
case 'email':
$type = 'ban_email';
foreach ($ban_list as $ban_item)
{
$ban_item = trim($ban_item);
if (preg_match('#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i', $ban_item))
{
if (strlen($ban_item) > 100)
{
continue;
}
if (!count($founder) || !in_array($ban_item, $founder))
{
$banlist_ary[] = $ban_item;
}
}
}
if (count($ban_list) == 0)
{
trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING);
}
break;
default:
trigger_error('NO_MODE', E_USER_WARNING);
break;
}
// Fetch currently set bans of the specified type and exclude state. Prevent duplicate bans.
$sql_where = ($type == 'ban_userid') ? 'ban_userid <> 0' : "$type <> ''";
$sql = "SELECT $type
FROM " . BANLIST_TABLE . "
WHERE $sql_where
AND ban_exclude = " . (int) $ban_exclude;
$result = $db->sql_query($sql);
// Reset $sql_where, because we use it later...
$sql_where = '';
if ($row = $db->sql_fetchrow($result))
{
$banlist_ary_tmp = array();
do
{
switch ($mode)
{
case 'user':
$banlist_ary_tmp[] = $row['ban_userid'];
break;
case 'ip':
$banlist_ary_tmp[] = $row['ban_ip'];
break;
case 'email':
$banlist_ary_tmp[] = $row['ban_email'];
break;
}
}
while ($row = $db->sql_fetchrow($result));
$banlist_ary_tmp = array_intersect($banlist_ary, $banlist_ary_tmp);
if (count($banlist_ary_tmp))
{
// One or more entities are already banned/excluded, delete the existing bans, so they can be re-inserted with the given new length
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
WHERE ' . $db->sql_in_set($type, $banlist_ary_tmp) . '
AND ban_exclude = ' . (int) $ban_exclude;
$db->sql_query($sql);
}
unset($banlist_ary_tmp);
}
$db->sql_freeresult($result);
// We have some entities to ban
if (count($banlist_ary))
{
$sql_ary = array();
foreach ($banlist_ary as $ban_entry)
{
$sql_ary[] = array(
$type => $ban_entry,
'ban_start' => (int) $current_time,
'ban_end' => (int) $ban_end,
'ban_exclude' => (int) $ban_exclude,
'ban_reason' => (string) $ban_reason,
'ban_give_reason' => (string) $ban_give_reason,
);
}
$db->sql_multi_insert(BANLIST_TABLE, $sql_ary);
// If we are banning we want to logout anyone matching the ban
if (!$ban_exclude)
{
switch ($mode)
{
case 'user':
$sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $banlist_ary);
break;
case 'ip':
$sql_where = 'WHERE ' . $db->sql_in_set('session_ip', $banlist_ary);
break;
case 'email':
$banlist_ary_sql = array();
foreach ($banlist_ary as $ban_entry)
{
$banlist_ary_sql[] = (string) str_replace('*', '%', $ban_entry);
}
$sql = 'SELECT user_id
FROM ' . USERS_TABLE . '
WHERE ' . $db->sql_in_set('user_email', $banlist_ary_sql);
$result = $db->sql_query($sql);
$sql_in = array();
if ($row = $db->sql_fetchrow($result))
{
do
{
$sql_in[] = $row['user_id'];
}
while ($row = $db->sql_fetchrow($result));
$sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $sql_in);
}
$db->sql_freeresult($result);
break;
}
if (isset($sql_where) && $sql_where)
{
$sql = 'DELETE FROM ' . SESSIONS_TABLE . "
$sql_where";
$db->sql_query($sql);
if ($mode == 'user')
{
$sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' ' . ((in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('user_id', $banlist_ary));
$db->sql_query($sql);
}
}
}
// Update log
$log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_';
// Add to admin log, moderator log and user notes
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array($ban_reason, $ban_list_log));
$phpbb_log->add('mod', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array(
'forum_id' => 0,
'topic_id' => 0,
$ban_reason,
$ban_list_log
));
if ($mode == 'user')
{
foreach ($banlist_ary as $user_id)
{
$phpbb_log->add('user', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array(
'reportee_id' => $user_id,
$ban_reason,
$ban_list_log
));
}
}
$cache->destroy('sql', BANLIST_TABLE);
return true;
}
// There was nothing to ban/exclude. But destroying the cache because of the removal of stale bans.
$cache->destroy('sql', BANLIST_TABLE);
return false;
return $ban_manager->ban($mode, $items, $start, $end, $ban_reason, $ban_give_reason);
}
/**
* Unban User
*
* @deprecated 4.0.0-a1 (To be removed: 4.1.0)
*/
function user_unban($mode, $ban)
{
global $db, $user, $cache, $phpbb_log, $phpbb_dispatcher;
global $phpbb_container;
// Delete stale bans
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
WHERE ban_end < ' . time() . '
AND ban_end <> 0';
$db->sql_query($sql);
$items = is_array($ban) ? $ban : [$ban];
if (!is_array($ban))
{
$ban = array($ban);
}
$unban_sql = array_map('intval', $ban);
if (count($unban_sql))
{
// Grab details of bans for logging information later
switch ($mode)
{
case 'user':
$sql = 'SELECT u.username AS unban_info, u.user_id
FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b
WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . '
AND u.user_id = b.ban_userid';
break;
case 'email':
$sql = 'SELECT ban_email AS unban_info
FROM ' . BANLIST_TABLE . '
WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
break;
case 'ip':
$sql = 'SELECT ban_ip AS unban_info
FROM ' . BANLIST_TABLE . '
WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
break;
}
$result = $db->sql_query($sql);
$l_unban_list = '';
$user_ids_ary = array();
while ($row = $db->sql_fetchrow($result))
{
$l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info'];
if ($mode == 'user')
{
$user_ids_ary[] = $row['user_id'];
}
}
$db->sql_freeresult($result);
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
WHERE ' . $db->sql_in_set('ban_id', $unban_sql);
$db->sql_query($sql);
// Add to moderator log, admin log and user notes
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array($l_unban_list));
$phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array(
'forum_id' => 0,
'topic_id' => 0,
$l_unban_list
));
if ($mode == 'user')
{
foreach ($user_ids_ary as $user_id)
{
$phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array(
'reportee_id' => $user_id,
$l_unban_list
));
}
}
/**
* Use this event to perform actions after the unban has been performed
*
* @event core.user_unban
* @var string mode One of the following: user, ip, email
* @var array user_ids_ary Array with user_ids
* @since 3.1.11-RC1
*/
$vars = array(
'mode',
'user_ids_ary',
);
extract($phpbb_dispatcher->trigger_event('core.user_unban', compact($vars)));
}
$cache->destroy('sql', BANLIST_TABLE);
return false;
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$ban_manager->unban($mode, $items);
}
/**
@ -1948,7 +1491,7 @@ function validate_user_email($email, $allowed_email = false)
$ban = $user->check_ban(false, false, $email, true);
if (!empty($ban))
{
return !empty($ban['ban_give_reason']) ? $ban['ban_give_reason'] : 'EMAIL_BANNED';
return !empty($ban['reason']) ? $ban['reason'] : 'EMAIL_BANNED';
}
if (!$config['allow_emailreuse'])
@ -3719,45 +3262,43 @@ function remove_newly_registered($user_id, $user_data = false)
*/
function phpbb_get_banned_user_ids($user_ids = array(), $ban_end = true)
{
global $db;
global $phpbb_container;
$sql_user_ids = (!empty($user_ids)) ? $db->sql_in_set('ban_userid', $user_ids) : 'ban_userid <> 0';
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$banned_users = $ban_manager->get_banned_users();
// Get banned User ID's
// Ignore stale bans which were not wiped yet
$banned_ids_list = array();
$sql = 'SELECT ban_userid
FROM ' . BANLIST_TABLE . "
WHERE $sql_user_ids
AND ban_exclude <> 1";
if ($ban_end === true)
if ($ban_end === false)
{
// Banned currently
$sql .= " AND (ban_end > " . time() . '
OR ban_end = 0)';
$banned_users = array_filter($banned_users, function ($end) {
return $end <= 0;
});
}
else if ($ban_end === false)
else if ($ban_end !== true)
{
// Permanently banned
$sql .= " AND ban_end = 0";
$banned_users = array_filter($banned_users, function ($end) use ($ban_end) {
return $end <= 0 || $end > (int) $ban_end;
});
}
else
{
// Banned until a specified time
$sql .= " AND (ban_end > " . (int) $ban_end . '
OR ban_end = 0)';
$banned_users = array_filter($banned_users, function ($end) {
return $end <= 0 || $end > time();
});
}
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
$result_array = [];
foreach ($banned_users as $user_id => $_)
{
$user_id = (int) $row['ban_userid'];
$banned_ids_list[$user_id] = $user_id;
if (count($user_ids) && !in_array($user_id, $user_ids))
{
continue;
}
$db->sql_freeresult($result);
return $banned_ids_list;
$result_array[$user_id] = $user_id;
}
return $result_array;
}
/**

View file

@ -68,7 +68,6 @@ class mcp_ban
$ban = $request->variable('ban', '', $mode === 'user');
$ban_length = $request->variable('banlength', 0);
$ban_length_other = $request->variable('banlengthother', '');
$ban_exclude = $request->variable('banexclude', 0);
$ban_reason = $request->variable('banreason', '', true);
$ban_give_reason = $request->variable('bangivereason', '', true);
@ -85,7 +84,6 @@ class mcp_ban
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @var mixed abort_ban Either false, or an error message that is displayed to the user.
@ -97,7 +95,6 @@ class mcp_ban
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
'abort_ban',
@ -108,7 +105,7 @@ class mcp_ban
{
trigger_error($abort_ban);
}
user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason);
user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_reason, $ban_give_reason);
/**
* Use this event to perform actions after the ban has been performed
@ -118,7 +115,6 @@ class mcp_ban
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @since 3.1.0-RC5
@ -128,7 +124,6 @@ class mcp_ban
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
);
@ -144,7 +139,6 @@ class mcp_ban
'bansubmit' => true,
'banlength' => $ban_length,
'banlengthother' => $ban_length_other,
'banexclude' => $ban_exclude,
'banreason' => $ban_reason,
'bangivereason' => $ban_give_reason,
);
@ -189,7 +183,6 @@ class mcp_ban
$this->page_title = $user->lang[strtoupper($mode) . '_BAN'];
$l_ban_explain = $user->lang[strtoupper($mode) . '_BAN_EXPLAIN'];
$l_ban_exclude_explain = $user->lang[strtoupper($mode) . '_BAN_EXCLUDE_EXPLAIN'];
$l_unban_title = $user->lang[strtoupper($mode) . '_UNBAN'];
$l_unban_explain = $user->lang[strtoupper($mode) . '_UNBAN_EXPLAIN'];
$l_no_ban_cell = $user->lang[strtoupper($mode) . '_NO_BANNED'];
@ -218,7 +211,6 @@ class mcp_ban
'L_UNBAN_TITLE' => $l_unban_title,
'L_UNBAN_EXPLAIN' => $l_unban_explain,
'L_BAN_CELL' => $l_ban_cell,
'L_BAN_EXCLUDE_EXPLAIN' => $l_ban_exclude_explain,
'L_NO_BAN_CELL' => $l_no_ban_cell,
'S_USERNAME_BAN' => ($mode == 'user') ? true : false,

View file

@ -114,13 +114,13 @@ if ($show_birthdays)
),
'LEFT_JOIN' => array(
array(
'FROM' => array(BANLIST_TABLE => 'b'),
'FROM' => array(BANS_TABLE => 'b'),
'ON' => 'u.user_id = b.ban_userid',
),
),
'WHERE' => "(b.ban_id IS NULL OR b.ban_exclude = 1)
AND (u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' $leap_year_birthdays)
AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')',
'WHERE' => 'b.ban_id IS NULL
AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
AND (u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' $leap_year_birthdays)",
);
/**

View file

@ -755,7 +755,7 @@ class convertor
{
if (!$db->sql_query($insert_query . $waiting_sql))
{
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
}
}
@ -774,7 +774,7 @@ class convertor
if (!$db->sql_query($insert_sql))
{
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
}
$db->sql_return_on_error(false);
@ -809,7 +809,7 @@ class convertor
foreach ($waiting_rows as $waiting_sql)
{
$db->sql_query($insert_query . $waiting_sql);
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
$this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql, ENT_COMPAT) . '<br /><br />' . htmlspecialchars(print_r($db->sql_error(), true), ENT_COMPAT), __LINE__, __FILE__, true);
}
$db->sql_return_on_error(false);

View file

@ -445,29 +445,42 @@ if (!$get_info)
),
array(
'target' => BANLIST_TABLE,
'target' => BANS_TABLE,
'execute_first' => 'phpbb_check_username_collisions();',
'query_first' => array('target', $convert->truncate_statement . BANLIST_TABLE),
'query_first' => array('target', $convert->truncate_statement . BANS_TABLE),
array('ban_ip', 'banlist.ban_ip', 'decode_ban_ip'),
array('ban_mode', 'user', ''),
array('ban_item', 'banlist.ban_userid', 'phpbb_user_id'),
array('ban_userid', 'banlist.ban_userid', 'phpbb_user_id'),
array('ban_email', 'banlist.ban_email', ''),
array('ban_reason', '', ''),
array('ban_give_reason', '', ''),
array('ban_reason_display', '', ''),
'where' => "banlist.ban_ip NOT LIKE '%.%'",
'where' => "banlist.ban_ip NOT LIKE '%.%'
AND banlist.ban_userid <> 0",
),
array(
'target' => BANLIST_TABLE,
'target' => BANS_TABLE,
array('ban_ip', 'banlist.ban_ip', ''),
array('ban_userid', 0, ''),
array('ban_email', '', ''),
array('ban_mode', 'email', ''),
array('ban_item', 'banlist.ban_email', ''),
array('ban_reason', '', ''),
array('ban_give_reason', '', ''),
array('ban_reason_display', '', ''),
'where' => "banlist.ban_ip LIKE '%.%'",
'where' => "banlist.ban_ip NOT LIKE '%.%'
AND banlist.ban_email <> ''",
),
array(
'target' => BANS_TABLE,
array('ban_mode', 'ip', ''),
array('ban_item', 'banlist.ban_ip', 'decode_ban_ip'),
array('ban_reason', '', ''),
array('ban_reason_display', '', ''),
'where' => "banlist.ban_userid = 0
AND banlist.ban_ip <> ''",
),
array(

View file

@ -44,7 +44,6 @@ $lang = array_merge($lang, array(
'ACP_BAN_EXPLAIN' => 'Here you can control the banning of users by name, IP or email address. These methods prevent a user reaching any part of the board. You can give a short (maximum 3000 characters) reason for the ban if you wish. This will be displayed in the admin log. The duration of a ban can also be specified. If you want the ban to end on a specific date rather than after a set time period select <span style="text-decoration: underline;">Until -&gt;</span> for the ban length and enter a date in <kbd>YYYY-MM-DD</kbd> format.',
'BAN_EXCLUDE' => 'Exclude from banning',
'BAN_LENGTH' => 'Length of ban',
'BAN_REASON' => 'Reason for ban',
'BAN_GIVE_REASON' => 'Reason shown to the banned',
@ -53,32 +52,28 @@ $lang = array_merge($lang, array(
'BANNED_UNTIL_DURATION' => '%1$s (until %2$s)', // Example: "7 days (until Tue 14.Jul.2009, 14:44)"
'EMAIL_BAN' => 'Ban one or more email addresses',
'EMAIL_BAN_EXCLUDE_EXPLAIN' => 'Enable this to exclude the entered email address from all current bans.',
'EMAIL_BAN_EXPLAIN' => 'To specify more than one email address enter each on a new line. To match partial addresses use * as the wildcard, e.g. <samp>*@hotmail.com</samp>, <samp>*@*.domain.tld</samp>, etc.',
'EMAIL_NO_BANNED' => 'No banned email addresses',
'EMAIL_UNBAN' => 'Un-ban or un-exclude emails',
'EMAIL_UNBAN_EXPLAIN' => 'You can unban (or un-exclude) multiple email addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded email addresses are emphasised.',
'EMAIL_UNBAN' => 'Un-ban emails',
'EMAIL_UNBAN_EXPLAIN' => 'You can unban multiple email addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser.',
'IP_BAN' => 'Ban one or more IPs',
'IP_BAN_EXCLUDE_EXPLAIN' => 'Enable this to exclude the entered IP from all current bans.',
'IP_BAN_EXPLAIN' => 'To specify several different IPs or hostnames enter each on a new line. To specify a range of IP addresses separate the start and end with a hyphen (-), to specify a wildcard use “*”.',
'IP_HOSTNAME' => 'IP addresses or hostnames',
'IP_NO_BANNED' => 'No banned IP addresses',
'IP_UNBAN' => 'Un-ban or un-exclude IPs',
'IP_UNBAN_EXPLAIN' => 'You can unban (or un-exclude) multiple IP addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded IPs are emphasised.',
'IP_UNBAN' => 'Un-ban IPs',
'IP_UNBAN_EXPLAIN' => 'You can unban multiple IP addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser.',
'LENGTH_BAN_INVALID' => 'The date has to be formatted <kbd>YYYY-MM-DD</kbd>.',
'OPTIONS_BANNED' => 'Banned',
'OPTIONS_EXCLUDED' => 'Excluded',
'PERMANENT' => 'Permanent',
'UNTIL' => 'Until',
'USER_BAN' => 'Ban one or more users by username',
'USER_BAN_EXCLUDE_EXPLAIN' => 'Enable this to exclude the entered users from all current bans.',
'USER_BAN_EXPLAIN' => 'You can ban multiple users in one go by entering each name on a new line. Use the <span style="text-decoration: underline;">Find a member</span> facility to look up and add one or more users automatically.',
'USER_NO_BANNED' => 'No banned usernames',
'USER_UNBAN' => 'Un-ban or un-exclude users by username',
'USER_UNBAN_EXPLAIN' => 'You can unban (or un-exclude) multiple users in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded users are emphasised.',
'USER_UNBAN' => 'Un-ban users by username',
'USER_UNBAN_EXPLAIN' => 'You can unban multiple users in one go using the appropriate combination of mouse and keyboard for your computer and browser.',
));

View file

@ -553,9 +553,6 @@ $lang = array_merge($lang, array(
'LOG_ATTACH_FILEUPLOAD' => '<strong>Orphan File uploaded to Post</strong><br />» ID %1$d - %2$s',
'LOG_ATTACH_ORPHAN_DEL' => '<strong>Orphan Files deleted</strong><br />» %s',
'LOG_BAN_EXCLUDE_USER' => '<strong>Excluded user from ban</strong> for reason “<em>%1$s</em>”<br />» %2$s',
'LOG_BAN_EXCLUDE_IP' => '<strong>Excluded IP from ban</strong> for reason “<em>%1$s</em>”<br />» %2$s',
'LOG_BAN_EXCLUDE_EMAIL' => '<strong>Excluded email from ban</strong> for reason “<em>%1$s</em>”<br />» %2$s',
'LOG_BAN_USER' => '<strong>Banned user</strong> for reason “<em>%1$s</em>”<br />» %2$s',
'LOG_BAN_IP' => '<strong>Banned IP</strong> for reason “<em>%1$s</em>”<br />» %2$s',
'LOG_BAN_EMAIL' => '<strong>Banned email</strong> for reason “<em>%1$s</em>”<br />» %2$s',

View file

@ -120,9 +120,9 @@ $lang = array_merge($lang, array(
'BBCODE_GUIDE' => 'BBCode guide',
'BCC' => 'BCC',
'BIRTHDAYS' => 'Birthdays',
'BOARD_BAN_PERM' => 'You have been <strong>permanently</strong> banned from this board.<br /><br />Please contact the %2$sBoard Administrator%3$s for more information.',
'BOARD_BAN_PERM' => 'You have been <strong>permanently</strong> banned from this board.<br><br>Please contact the %2$sBoard Administrator%3$s for more information.',
'BOARD_BAN_REASON' => 'Reason given for ban: <strong>%s</strong>',
'BOARD_BAN_TIME' => 'You have been banned from this board until <strong>%1$s</strong>.<br /><br />Please contact the %2$sBoard Administrator%3$s for more information.',
'BOARD_BAN_TIME' => 'You have been banned from this board until <strong>%1$s</strong>.<br><br>Please contact the %2$sBoard Administrator%3$s for more information.',
'BOARD_DISABLE' => 'Sorry but this board is currently unavailable.',
'BOARD_DISABLED' => 'This board is currently disabled.',
'BOARD_UNAVAILABLE' => 'Sorry but the board is temporarily unavailable, please try again in a few minutes.',

View file

@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\exception;
use phpbb\exception\runtime_exception;
class invalid_length_exception extends runtime_exception
{
}

View file

@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\exception;
use phpbb\exception\runtime_exception;
class no_valid_emails_exception extends runtime_exception
{
}

View file

@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\exception;
use phpbb\exception\runtime_exception;
class no_valid_ips_exception extends runtime_exception
{
}

View file

@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\exception;
use phpbb\exception\runtime_exception;
class no_valid_users_exception extends runtime_exception
{
}

View file

@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\exception;
use phpbb\exception\runtime_exception;
class type_not_found_exception extends runtime_exception
{
}

573
phpBB/phpbb/ban/manager.php Normal file
View file

@ -0,0 +1,573 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban;
use phpbb\ban\exception\invalid_length_exception;
use phpbb\ban\exception\type_not_found_exception;
use phpbb\ban\type\type_interface;
use phpbb\cache\driver\driver_interface as cache_driver;
use phpbb\db\driver\driver_interface;
use phpbb\di\service_collection;
use phpbb\language\language;
use phpbb\log\log_interface;
use phpbb\user;
class manager
{
const CACHE_KEY_INFO = '_ban_info';
const CACHE_KEY_USERS = '_banned_users';
const CACHE_TTL = 3600;
/** @var string */
protected $bans_table;
/** @var cache_driver */
protected $cache;
/** @var driver_interface */
protected $db;
/** @var service_collection */
protected $types;
/** @var language */
protected $language;
/** @var log_interface */
protected $log;
/** @var user */
protected $user;
/** @var string */
protected $users_table;
/**
* Creates a service which manages all bans. Developers can
* create their own ban types which will be handled in this.
*
* @param service_collection $types A service collection containing all ban types
* @param cache_driver $cache A cache object
* @param driver_interface $db A phpBB DBAL object
* @param language $language Language object
* @param log_interface $log Log object
* @param user $user User object
* @param string $bans_table The bans table
* @param string $users_table The users table
*/
public function __construct(service_collection $types, cache_driver $cache, driver_interface $db, language $language,
log_interface $log, user $user, string $bans_table, string $users_table = '')
{
$this->bans_table = $bans_table;
$this->cache = $cache;
$this->db = $db;
$this->types = $types;
$this->language = $language;
$this->log = $log;
$this->user = $user;
$this->users_table = $users_table;
}
/**
* Creates ban entries for the given $items. Returns true if successful
* and false if no entries were added to the database
*
* @param string $mode A string which identifies a ban type
* @param array $items An array of items which should be banned
* @param \DateTimeInterface $start A DateTimeInterface object which is the start of the ban
* @param \DateTimeInterface $end A DateTimeInterface object which is the end of the ban (or 0 if permanent)
* @param string $reason An (internal) reason for the ban
* @param string $display_reason An optional reason which should be displayed to the banned
*
* @return bool
*/
public function ban(string $mode, array $items, \DateTimeInterface $start, \DateTimeInterface $end, string $reason, string $display_reason = ''): bool
{
if ($start > $end && $end->getTimestamp() !== 0)
{
throw new invalid_length_exception('LENGTH_BAN_INVALID');
}
/** @var type_interface $ban_mode */
$ban_mode = $this->find_type($mode);
if ($ban_mode === false)
{
throw new type_not_found_exception();
}
if (!empty($this->user))
{
$ban_mode->set_user($this->user);
}
$this->tidy();
$ban_items = $ban_mode->prepare_for_storage($items);
// Prevent duplicate bans
$sql = 'DELETE FROM ' . $this->bans_table . "
WHERE ban_mode = '" . $this->db->sql_escape($mode) . "'
AND " . $this->db->sql_in_set('ban_item', $ban_items, false, true);
$this->db->sql_query($sql);
$insert_array = [];
foreach ($ban_items as $ban_item)
{
$insert_array[] = [
'ban_mode' => $mode,
'ban_item' => $ban_item,
'ban_userid' => $mode === 'user' ? $ban_item : 0,
'ban_start' => $start->getTimestamp(),
'ban_end' => $end->getTimestamp(),
'ban_reason' => $reason,
'ban_reason_display' => $display_reason,
];
}
if (empty($insert_array))
{
return false;
}
$this->db->sql_multi_insert($this->bans_table, $insert_array);
$ban_data = [
'items' => $ban_items,
'start' => $start,
'end' => $end,
'reason' => $reason,
'display_reason' => $display_reason,
];
// Add to admin log, moderator log and user notes
$ban_list_log = implode(', ', $items);
$log_operation = 'LOG_BAN_' . strtoupper($mode);
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [$reason, $ban_list_log]);
$this->log->add('mod', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [
'forum_id' => 0,
'topic_id' => 0,
$reason,
$ban_list_log
]);
if ($banlist_ary = $ban_mode->after_ban($ban_data))
{
foreach ($banlist_ary as $user_id)
{
$this->log->add('user', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [
'reportee_id' => $user_id,
$reason,
$ban_list_log
]);
}
}
$this->cache->destroy(self::CACHE_KEY_INFO);
$this->cache->destroy(self::CACHE_KEY_USERS);
return true;
}
/**
* Removes ban entries from the database with the given IDs
*
* @param string $mode The ban type in which the ban IDs were created
* @param array $items An array of ban IDs which should be removed
*/
public function unban(string $mode, array $items)
{
/** @var type_interface $ban_mode */
$ban_mode = $this->find_type($mode);
if ($ban_mode === false)
{
throw new type_not_found_exception();
}
$this->tidy();
$sql_ids = array_map('intval', $items);
if (count($sql_ids))
{
$sql = 'SELECT ban_item
FROM ' . $this->bans_table . '
WHERE ' . $this->db->sql_in_set('ban_id', $sql_ids);
$result = $this->db->sql_query($sql);
$unbanned_items = [];
while ($row = $this->db->sql_fetchrow($result))
{
$unbanned_items[] = $row['ban_item'];
}
$this->db->sql_freeresult($result);
$sql = 'DELETE FROM ' . $this->bans_table . '
WHERE ' . $this->db->sql_in_set('ban_id', $sql_ids);
$this->db->sql_query($sql);
$unban_data = [
'items' => $unbanned_items,
];
$unbanned_users = $ban_mode->after_unban($unban_data);
// Add to moderator log, admin log and user notes
$log_operation = 'LOG_UNBAN_' . strtoupper($mode);
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [$unbanned_users]);
$this->log->add('mod', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [
'forum_id' => 0,
'topic_id' => 0,
$unbanned_users
]);
if (count($unbanned_users))
{
foreach ($unbanned_users as $user_id)
{
$this->log->add('user', $this->user->data['user_id'], $this->user->ip, $log_operation, false, array(
'reportee_id' => $user_id,
$unbanned_users
));
}
}
}
$this->cache->destroy(self::CACHE_KEY_INFO);
$this->cache->destroy(self::CACHE_KEY_USERS);
}
/**
* Checks for the given user data whether the user is banned.
* Returns false if nothing was found and an array containing
* 'mode', 'end', 'reason' and 'item' otherwise.
*
* @param array $user_data The array containing the user data
*
* @return array|bool
*/
public function check(array $user_data = [])
{
if (empty($user_data))
{
$user_data = $this->user->data;
}
$ban_info = $this->get_info_cache();
foreach ($ban_info as $mode => $ban_rows)
{
/** @var type_interface $ban_mode */
$ban_mode = $this->find_type($mode);
if ($ban_mode === false)
{
continue;
}
if ($ban_mode->get_user_column() === null)
{
$ban_result = $ban_mode->check($ban_rows, $user_data);
if ($ban_result !== false)
{
return $ban_result + ['mode' => $mode];
}
}
else
{
$user_column = $ban_mode->get_user_column();
if (!isset($user_data[$user_column]))
{
continue;
}
foreach ($ban_rows as $ban_row)
{
if (!$ban_row['end'] || $ban_row['end'] > time())
{
if (stripos($ban_row['item'], '*') === false)
{
if ($ban_row['item'] == $user_data[$user_column])
{
return $ban_row + ['mode' => $mode];
}
}
else
{
$regex = '#^' . str_replace('\*', '.*?', preg_quote($ban_row['item'], '#')) . '$#i';
if (preg_match($regex, $user_data[$user_column]))
{
return $ban_row + ['mode' => $mode];
}
}
}
}
}
}
return false;
}
/**
* Returns all bans for a given ban type. False, if none were found
*
* @param string $mode The ban type for which the entries should be retrieved
*
* @return array|bool
*/
public function get_bans(string $mode)
{
/** @var type_interface $ban_type */
$ban_type = $this->find_type($mode);
if ($ban_type === false)
{
throw new type_not_found_exception();
}
$this->tidy();
return $ban_type->get_ban_options();
}
/**
* Returns an array of banned users with 'id' => 'end' values.
* The result is cached for performance reasons and is not as
* accurate as the check() method. (Wildcards aren't considered e.g.)
*
* @return array
*/
public function get_banned_users(): array
{
$banned_users = $this->cache->get(self::CACHE_KEY_USERS);
if ($banned_users === false)
{
$manual_modes = [];
$where_array = [];
/** @var type_interface $ban_mode */
foreach ($this->types as $ban_mode)
{
$user_column = $ban_mode->get_user_column();
if (empty($user_column))
{
$manual_modes[] = $ban_mode;
continue;
}
$where_column = $user_column == 'user_id' ? 'b.ban_userid' : 'b.ban_item';
$where_array[] = ['AND',
[
[$where_column, '=', 'u.' . $user_column],
['b.ban_mode', '=', "'{$ban_mode->get_type()}'"],
],
];
}
$sql_array = [
'SELECT' => 'u.user_id, b.ban_end',
'FROM' => [
$this->bans_table => 'b',
$this->users_table => 'u',
],
'WHERE' => ['AND',
[
['OR',
$where_array,
],
['u.user_type', '<>', USER_FOUNDER],
],
],
];
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query($sql);
$banned_users = [];
while ($row = $this->db->sql_fetchrow($result))
{
$user_id = (int) $row['user_id'];
$end = (int) $row['ban_end'];
if (!isset($banned_users[$user_id]) || ($banned_users[$user_id] > 0 && $banned_users[$user_id] < $end))
{
$banned_users[$user_id] = $end;
}
}
$this->db->sql_freeresult($result);
/** @var type_interface $manual_mode */
foreach ($manual_modes as $manual_mode)
{
$mode_banned_users = $manual_mode->get_banned_users();
foreach ($mode_banned_users as $user_id => $end)
{
$user_id = (int) $user_id;
$end = (int) $end;
if (!isset($banned_users[$user_id]) || ($banned_users[$user_id] > 0 && $banned_users[$user_id] < $end))
{
$banned_users[$user_id] = $end;
}
}
}
$this->cache->put(self::CACHE_KEY_USERS, $banned_users, self::CACHE_TTL);
}
return $banned_users;
}
/**
* Get ban end
*
* @param \DateTimeInterface $ban_start Ban start time
* @param int $length Ban length in minutes
* @param string $end_date Ban end date as YYYY-MM-DD string
* @return \DateTimeInterface Ban end as DateTimeInterface instance
*/
public function get_ban_end(\DateTimeInterface $ban_start, int $length, string $end_date): \DateTimeInterface
{
$current_time = $ban_start->getTimestamp();
$end_time = 0;
if ($length)
{
if ($length != -1 || !$end_date)
{
$end_time = max($current_time, $current_time + ($length) * 60);
}
else
{
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $end_date))
{
$end_time = max(
$current_time,
\DateTime::createFromFormat('Y-m-d', $end_date, $this->user->timezone)->getTimestamp()
);
}
else
{
throw new invalid_length_exception('LENGTH_BAN_INVALID');
}
}
}
$ban_end = new \DateTime();
$ban_end->setTimestamp($end_time);
return $ban_end;
}
/**
* Cleans up the database of e.g. stale bans
*/
public function tidy()
{
// Delete stale bans
$sql = 'DELETE FROM ' . $this->bans_table . '
WHERE ban_end > 0
AND ban_end < ' . (int) time();
$this->db->sql_query($sql);
/** @var type_interface $type */
foreach ($this->types as $type)
{
$type->tidy();
}
}
/**
* Finds the ban type for the given mode string.
* Returns false if none was found
*
* @param string $mode The mode string
*
* @return bool|type\type_interface
*/
protected function find_type(string $mode)
{
/** @var type_interface $type */
foreach ($this->types as $type)
{
if ($type->get_type() === $mode)
{
return $type;
}
}
return false;
}
/**
* Returns the ban_info from the cache.
* If they're not in the cache, bans are retrieved from the database
* and then put into the cache.
* The array contains an array for each mode with respectively
* three values for 'item', 'end' and 'reason' only.
*
* @return array
*/
protected function get_info_cache(): array
{
$ban_info = $this->cache->get(self::CACHE_KEY_INFO);
if ($ban_info === false)
{
$sql = 'SELECT ban_mode, ban_item, ban_end, ban_reason_display
FROM ' . $this->bans_table;
$result = $this->db->sql_query($sql);
$ban_info = [];
while ($row = $this->db->sql_fetchrow($result))
{
if (!isset($ban_info[$row['ban_mode']]))
{
$ban_info[$row['ban_mode']] = [];
}
$ban_info[$row['ban_mode']][] = [
'item' => $row['ban_item'],
'end' => $row['ban_end'],
'reason' => $row['ban_reason_display'],
];
}
$this->db->sql_freeresult($result);
$this->cache->put(self::CACHE_KEY_INFO, $ban_info, self::CACHE_TTL);
}
return $ban_info;
}
/**
* Get ban info message
*
* @param array $ban_row Ban data row from database
* @param string $ban_triggered_by Ban triggered by; allowed 'user', 'ip', 'email
* @param string $contact_link Contact link URL
*
* @return string Ban message
*/
public function get_ban_message(array $ban_row, string $ban_triggered_by, string $contact_link): string
{
if ($ban_row['end'] > 0)
{
$till_date = $this->user->format_date($ban_row['end']);
$ban_type = 'BOARD_BAN_TIME';
}
else
{
$till_date = '';
$ban_type = 'BOARD_BAN_PERM';
}
$message = $this->language->lang($ban_type, $till_date, '<a href="' . $contact_link . '">', '</a>');
$message .= !empty($ban_row['reason']) ? '<br><br>' . $this->language->lang('BOARD_BAN_REASON', $ban_row['reason']) : '';
$message .= '<br><br><em>' . $this->language->lang('BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)) . '</em>';
return $message;
}
}

View file

@ -0,0 +1,240 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\type;
use phpbb\db\driver\driver_interface;
abstract class base implements type_interface
{
/** @var driver_interface */
protected $db;
/** @var array */
protected $excluded;
/** @var string */
protected $bans_table;
/** @var string */
protected $sessions_keys_table;
/** @var string */
protected $sessions_table;
/** @var \phpbb\user */
protected $user;
/** @var string */
protected $users_table;
/**
* Creates a ban type.
*
* @param driver_interface $db A phpBB DBAL object
* @param string $bans_table The bans table
* @param string $users_table The users table
* @param string $sessions_table The sessions table
* @param string $sessions_keys_table The sessions keys table
*/
public function __construct(driver_interface $db, string $bans_table, string $users_table, string $sessions_table, string $sessions_keys_table)
{
$this->db = $db;
$this->bans_table = $bans_table;
$this->users_table = $users_table;
$this->sessions_table = $sessions_table;
$this->sessions_keys_table = $sessions_keys_table;
}
/**
* {@inheritDoc}
*/
public function set_user(\phpbb\user $user): void
{
$this->user = $user;
}
/**
* {@inheritDoc}
*/
public function after_ban(array $data): array
{
return $this->logout_affected_users($data['items']);
}
/**
* {@inheritDoc}
*/
public function after_unban(array $data): array
{
return [];
}
/**
* {@inheritDoc}
*/
public function check(array $ban_rows, array $user_data)
{
return false;
}
/**
* {@inheritDoc}
*/
public function tidy(): void
{
}
/**
* {@inheritDoc}
*/
public function get_banned_users(): array
{
return [];
}
/**
* {@inheritDoc}
*/
public function get_ban_options(): array
{
$sql = 'SELECT *
FROM ' . $this->bans_table . '
WHERE (ban_end >= ' . time() . "
OR ban_end = 0)
AND ban_mode = '{$this->db->sql_escape($this->get_type())}'
ORDER BY ban_item";
$result = $this->db->sql_query($sql);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return $rowset;
}
/**
* Queries users that are excluded from banning (like founders)
* from the database and saves them in $this->excluded array.
* Returns true on success and false on failure
*
* @return bool
*/
protected function get_excluded(): bool
{
$user_column = $this->get_user_column();
if (empty($user_column))
{
return false;
}
$this->excluded = [];
if (!empty($this->user))
{
$this->excluded[$this->user->id()] = $this->user->data[$user_column];
}
$sql = "SELECT user_id, {$this->db->sql_escape($user_column)}
FROM {$this->users_table}
WHERE user_type = " . USER_FOUNDER;
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$this->excluded[(int) $row['user_id']] = $row[$user_column];
}
$this->db->sql_freeresult($result);
return true;
}
/**
* Logs out all affected users in the given array. The values
* have to match the values of the column returned by get_user_column().
* Returns all banned users.
*
* @param array $ban_items
*
* @return array Logged out users
*/
protected function logout_affected_users(array $ban_items): array
{
$user_column = $this->get_user_column();
if (empty($user_column))
{
return [];
}
if ($user_column !== 'user_id')
{
$ban_items_sql = [];
$ban_like_items = [];
foreach ($ban_items as $ban_item)
{
if (stripos($ban_item, '*') === false)
{
$ban_items_sql[] = $ban_item;
}
else
{
$ban_like_items[] = [$user_column, 'LIKE', str_replace('*', $this->db->get_any_char(), $ban_item)];
}
}
$sql_array = [
'SELECT' => 'user_id',
'FROM' => [
$this->users_table => '',
],
'WHERE' => ['AND',
[
['OR',
array_merge([
[$user_column, 'IN', $ban_items_sql]
], $ban_like_items),
],
['user_id', 'NOT_IN', array_map('intval', array_keys($this->excluded))],
],
],
];
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query($sql);
$user_ids = [];
while ($row = $this->db->sql_fetchrow($result))
{
$user_ids[] = (int) $row['user_id'];
}
$this->db->sql_freeresult($result);
}
else
{
$user_ids = array_map('intval', $ban_items);
}
if (!empty($user_ids) && !empty($this->sessions_table))
{
$sql = 'DELETE FROM ' . $this->sessions_table . '
WHERE ' . $this->db->sql_in_set('session_user_id', $user_ids);
$this->db->sql_query($sql);
}
if (!empty($user_ids) && !empty($this->sessions_keys_table))
{
$sql = 'DELETE FROM ' . $this->sessions_keys_table . '
WHERE ' . $this->db->sql_in_set('user_id', $user_ids);
$this->db->sql_query($sql);
}
return $user_ids;
}
}

View file

@ -0,0 +1,63 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\type;
use phpbb\ban\exception\no_valid_emails_exception;
class email extends base
{
/**
* {@inheritDoc}
*/
public function get_type(): string
{
return 'email';
}
/**
* {@inheritDoc}
*/
public function get_user_column(): ?string
{
return 'user_email';
}
/**
* {@inheritDoc}
*/
public function prepare_for_storage(array $items): array
{
$this->get_excluded();
$regex = '#^.*?@.*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i';
$ban_items = [];
foreach ($items as $item)
{
$item = trim($item);
if (strlen($item) > 100 || !preg_match($regex, $item) || in_array($item, $this->excluded))
{
continue;
}
$ban_items[] = $item;
}
if (empty($ban_items))
{
throw new no_valid_emails_exception('NO_EMAILS_DEFINED');
}
return $ban_items;
}
}

View file

@ -0,0 +1,93 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\type;
use phpbb\ban\exception\no_valid_ips_exception;
use Symfony\Component\HttpFoundation\IpUtils;
class ip extends base
{
private const USER_IP = 'user_ip';
/**
* @inheritDoc
*/
public function get_type(): string
{
return 'ip';
}
/**
* @inheritDoc
*/
public function get_user_column(): ?string
{
return null;
}
/**
* {@inheritDoc}
*/
public function check(array $ban_rows, array $user_data)
{
if (!isset($user_data[self::USER_IP]))
{
return false;
}
foreach ($ban_rows as $ip_ban)
{
if (IpUtils::checkIp($user_data[self::USER_IP], $ip_ban['item']))
{
return $ip_ban;
}
}
return false;
}
/**
* @inheritDoc
*/
public function prepare_for_storage(array $items): array
{
$ban_items = [];
foreach ($items as $ip)
{
try
{
// Misuse checkIp for checking validity of IP. Should return true if defined IP is valid.
if (!IpUtils::checkIp($ip, $ip))
{
continue;
}
$ban_items[] = $ip;
}
// @codeCoverageIgnoreStart
catch (\RuntimeException $exception)
{
// IPv6 not supported, therefore IPv6 address will not be added
}
// @codeCoverageIgnoreEnd
}
if (empty($ban_items))
{
throw new no_valid_ips_exception('NO_IPS_DEFINED');
}
return $ban_items;
}
}

View file

@ -0,0 +1,126 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\type;
/**
* Interface implemented by all ban types
*/
interface type_interface
{
/**
* Returns the type identifier for this ban type
*
* @return string
*/
public function get_type(): string;
/**
* Returns the column in the users table which contains
* the values that should be looked for when checking a ban.
* If it returns null, the check method will be called when
* checking for bans.
*
* @return string|null
*/
public function get_user_column(): ?string;
/**
* Sets a user object to the ban type to have it excluded
* from banning.
*
* @param \phpbb\user $user An user object
*
* @return void
*/
public function set_user(\phpbb\user $user): void;
/**
* Gives the possibility to do some clean up after banning.
* The return value of this method will be passed through
* to the caller.
*
* @param array $data An array containing information about
* the bans, like the reason or the start
* and end of the ban
*
* @return array List of banned users
*/
public function after_ban(array $data): array;
/**
* Gives the possibility to do some clean up after unbanning.
* The return value of this method will be passed through
* to the caller.
*
* @param array $data An array containing information about
* the unbans, e.g. the unbanned items.
*
* @return array List of unbanned users
*/
public function after_unban(array $data): array;
/**
* In the case that get_user_column() returns null, this method
* is called when checking the ban status.
* Please note, that this method is basically called on every page,
* so the check should perform rather fast.
*
* Returns an array with information about the ban, like the end or
* the reason. False if the user is not banned.
*
* @param array $ban_rows An array containing the ban rows retrieved
* from the database for this specific mode.
* They contain the item, reason and end of the ban.
* @param array $user_data The user data
*
* @return array|bool
*/
public function check(array $ban_rows, array $user_data);
/**
* In case get_user_column() returns no string, this method will be called
* when a list of banned users is retrieved.
* Returns a list of banned users.
* The result is cached and is not used for ban checking, so the accuracy
* of the results is not as important as when *really* checking in check()
*
* @return array An array of banned users, where the user ids are the keys
* and the value is the end of the ban (or 0 if permanent)
*/
public function get_banned_users(): array;
/**
* Get ban options mapping ban ID to an option to display to admins
*
* @return array
*/
public function get_ban_options(): array;
/**
* Prepares the given ban items before saving them in the database
*
* @param array $items
*
* @return array
*/
public function prepare_for_storage(array $items): array;
/**
* Does some cleanup work for the banning mode.
* Is called before banning and unbanning and as cron job.
*
* @return void
*/
public function tidy(): void;
}

View file

@ -0,0 +1,156 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\ban\type;
use phpbb\ban\exception\no_valid_users_exception;
class user extends base
{
/** @var array */
private $banned_users;
/**
* {@inheritDoc}
*/
public function get_type(): string
{
return 'user';
}
/**
* {@inheritDoc}
*/
public function get_user_column(): string
{
return 'user_id';
}
/**
* {@inheritDoc}
*/
public function after_ban(array $data): array
{
$this->logout_affected_users($data['items']);
return $this->banned_users;
}
/**
* {@inheritDoc}
*/
public function after_unban(array $data): array
{
$user_ids = array_map('intval', $data['items']);
$sql = 'SELECT user_id, username
FROM ' . $this->users_table . '
WHERE ' . $this->db->sql_in_set('user_id', $user_ids);
$result = $this->db->sql_query($sql);
$unbanned_users = [];
while ($row = $this->db->sql_fetchrow($result))
{
$unbanned_users[(int) $row['user_id']] = $row['username'];
}
$this->db->sql_freeresult($result);
return $unbanned_users;
}
/**
* {@inheritDoc}
*/
public function get_ban_options(): array
{
$ban_options = [];
$sql = 'SELECT b.*, u.user_id, u.username, u.username_clean
FROM ' . $this->bans_table . ' b, ' . $this->users_table . ' u
WHERE (b.ban_end >= ' . time() . "
OR b.ban_end = 0)
AND b.ban_userid = u.user_id
AND b.ban_mode = '{$this->db->sql_escape($this->get_type())}'
ORDER BY u.username_clean ASC";
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$row['label'] = $row['username'];
$ban_options[] = $row;
}
$this->db->sql_freeresult($result);
return $ban_options;
}
/**
* {@inheritDoc}
*/
public function prepare_for_storage(array $items): array
{
// Fill excluded user list
$this->get_excluded();
// Prevent banning of anonymous
$this->excluded[ANONYMOUS] = ANONYMOUS;
$sql_usernames = [];
$sql_or_like = [];
foreach ($items as $item)
{
$cleaned_username = utf8_clean_string($item);
if (stripos($cleaned_username, '*') === false)
{
$sql_usernames[] = $cleaned_username;
}
else
{
$sql_or_like[] = ['username_clean', 'LIKE', str_replace('*', $this->db->get_any_char(), $cleaned_username)];
}
}
$sql_array = [
'SELECT' => 'user_id, username',
'FROM' => [
$this->users_table => '',
],
'WHERE' => ['AND',
[
['OR',
array_merge([
['username_clean', 'IN', $sql_usernames]
], $sql_or_like),
],
['user_id', 'NOT_IN', array_map('intval', $this->excluded)],
],
],
];
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query($sql);
$ban_items = [];
$this->banned_users = [];
while ($row = $this->db->sql_fetchrow($result))
{
$ban_items[] = (string) $row['user_id'];
$this->banned_users[(int) $row['user_id']] = $row['username'];
}
$this->db->sql_freeresult($result);
if (empty($ban_items))
{
throw new no_valid_users_exception('NO_USER_SPECIFIED');
}
return $ban_items;
}
}

View file

@ -0,0 +1,179 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\db\migration\data\v400;
use phpbb\db\migration\migration;
class ban_table_p1 extends migration
{
public static function depends_on(): array
{
return ['\phpbb\db\migration\data\v320\default_data_type_ids'];
}
public function update_schema(): array
{
return [
'add_tables' => [
$this->table_prefix . 'bans' => [
'COLUMNS' => [
'ban_id' => ['ULINT', null, 'auto_increment'],
'ban_userid' => ['ULINT', 0],
'ban_mode' => ['VCHAR', ''],
'ban_item' => ['STEXT_UNI', ''],
'ban_start' => ['TIMESTAMP', 0],
'ban_end' => ['TIMESTAMP', 0],
'ban_reason' => ['VCHAR_UNI', ''],
'ban_reason_display' => ['VCHAR_UNI', ''],
],
'PRIMARY_KEY' => 'ban_id',
'KEYS' => [
'ban_userid' => ['INDEX', 'ban_userid'],
'ban_end' => ['INDEX', 'ban_end'],
],
],
],
];
}
public function revert_schema(): array
{
return [
'drop_tables' => [
$this->table_prefix . 'bans',
],
];
}
public function update_data(): array
{
return [
['custom', [[$this, 'old_to_new']]],
];
}
public function revert_data(): array
{
return [
['custom', [[$this, 'new_to_old']]],
];
}
public function old_to_new($start)
{
$start = (int) $start;
$limit = 500;
$processed_rows = 0;
$sql = 'SELECT *
FROM ' . $this->table_prefix . 'banlist';
$result = $this->db->sql_query_limit($sql, $limit, $start);
$bans = [];
while ($row = $this->db->sql_fetchrow($result))
{
$processed_rows++;
if ($row['ban_exclude'])
{
continue;
}
$row['ban_userid'] = (int) $row['ban_userid'];
$item = $mode = '';
if ($row['ban_ip'] !== '')
{
$mode = 'ip';
$item = $row['ban_ip'];
}
else if ($row['ban_email'] !== '')
{
$mode = 'email';
$item = $row['ban_email'];
}
else if ($row['ban_userid'] !== 0)
{
$mode = 'user';
$item = $row['ban_userid'];
}
if ($mode === '' || $item === '')
{
continue;
}
$bans[] = [
'ban_mode' => $mode,
'ban_userid' => $row['ban_userid'],
'ban_item' => $item,
'ban_start' => $row['ban_start'],
'ban_end' => $row['ban_end'],
'ban_reason' => $row['ban_reason'],
'ban_reason_display' => $row['ban_give_reason'],
];
}
$this->db->sql_freeresult($result);
if ($processed_rows > 0)
{
$this->db->sql_multi_insert($this->table_prefix . 'bans', $bans);
}
else if ($processed_rows < $limit)
{
return;
}
return $limit + $start;
}
public function new_to_old($start)
{
$start = (int) $start;
$limit = 500;
$processed_rows = 0;
$sql = 'SELECT *
FROM ' . $this->table_prefix . 'bans';
$result = $this->db->sql_query_limit($sql, $limit, $start);
$bans = [];
while ($row = $this->db->sql_fetchrow($result))
{
$processed_rows++;
$bans[] = [
'ban_userid' => (int) $row['ban_userid'],
'ban_ip' => ($row['ban_mode'] === 'ip') ? $row['ban_item'] : '',
'ban_email' => ($row['ban_mode'] === 'email') ? $row['ban_item'] : '',
'ban_start' => $row['ban_start'],
'ban_end' => $row['ban_end'],
'ban_exclude' => false,
'ban_reason' => $row['ban_reason'],
'ban_give_reason' => $row['ban_reason_display'],
];
}
$this->db->sql_freeresult($result);
if ($processed_rows > 0)
{
$this->db->sql_multi_insert($this->table_prefix . 'banlist', $bans);
}
else if ($processed_rows < $limit)
{
return;
}
return $limit + $start;
}
}

View file

@ -0,0 +1,59 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\db\migration\data\v400;
class ban_table_p2 extends \phpbb\db\migration\migration
{
public static function depends_on(): array
{
return ['\phpbb\db\migration\data\v400\ban_table_p1'];
}
public function update_schema(): array
{
return [
'drop_tables' => [
$this->table_prefix . 'banlist',
],
];
}
public function revert_schema(): array
{
return [
'add_tables' => [
$this->table_prefix . 'banlist' => [
'COLUMNS' => [
'ban_id' => ['ULINT', null, 'auto_increment'],
'ban_userid' => ['ULINT', 0],
'ban_ip' => ['VCHAR:40', ''],
'ban_email' => ['VCHAR_UNI:100', ''],
'ban_start' => ['TIMESTAMP', 0],
'ban_end' => ['TIMESTAMP', 0],
'ban_exclude' => ['BOOL', 0],
'ban_reason' => ['VCHAR_UNI', ''],
'ban_give_reason' => ['VCHAR_UNI', ''],
],
'PRIMARY_KEY' => 'ban_id',
'KEYS' => [
'ban_end' => ['INDEX', 'ban_end'],
'ban_user' => ['INDEX', ['ban_userid', 'ban_exclude']],
'ban_email' => ['INDEX', ['ban_email', 'ban_exclude']],
'ban_ip' => ['INDEX', ['ban_ip', 'ban_exclude']],
],
],
],
];
}
}

View file

@ -1136,119 +1136,23 @@ class session
*/
function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
{
global $db, $phpbb_dispatcher;
global $phpbb_container, $phpbb_dispatcher;
if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN'))
{
return false;
}
$banned = false;
$cache_ttl = 3600;
$where_sql = array();
$sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end
FROM ' . BANLIST_TABLE . '
WHERE ';
// Determine which entries to check, only return those
if ($user_email === false)
/** @var \phpbb\ban\manager $ban_manager */
$ban_manager = $phpbb_container->get('ban.manager');
$ban_row = $ban_manager->check(['user_id' => $user_id, 'user_email' => $user_email]);
if (empty($ban_row))
{
$where_sql[] = "ban_email = ''";
return false;
}
if ($user_ips === false)
{
$where_sql[] = "(ban_ip = '' OR ban_exclude = 1)";
}
if ($user_id === false)
{
$where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)';
}
else
{
$cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0;
$_sql = '(ban_userid = ' . $user_id;
if ($user_email !== false)
{
$_sql .= " OR ban_email <> ''";
}
if ($user_ips !== false)
{
$_sql .= " OR ban_ip <> ''";
}
$_sql .= ')';
$where_sql[] = $_sql;
}
$sql .= (count($where_sql)) ? implode(' AND ', $where_sql) : '';
$result = $db->sql_query($sql, $cache_ttl);
$ban_triggered_by = 'user';
while ($row = $db->sql_fetchrow($result))
{
if ($row['ban_end'] && $row['ban_end'] < time())
{
continue;
}
$ip_banned = false;
if (!empty($row['ban_ip']))
{
if (!is_array($user_ips))
{
$ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
}
else
{
foreach ($user_ips as $user_ip)
{
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
{
$ip_banned = true;
break;
}
}
}
}
if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) ||
$ip_banned ||
(!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
{
if (!empty($row['ban_exclude']))
{
$banned = false;
break;
}
else
{
$banned = true;
$ban_row = $row;
if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id)
{
$ban_triggered_by = 'user';
}
else if ($ip_banned)
{
$ban_triggered_by = 'ip';
}
else
{
$ban_triggered_by = 'email';
}
// Don't break. Check if there is an exclude rule for this user
}
}
}
$db->sql_freeresult($result);
$ban_triggered_by = $ban_row['mode'];
/**
* Event to set custom ban type
@ -1266,7 +1170,7 @@ class session
if ($banned && !$return)
{
global $phpEx;
global $config, $phpbb_root_path, $phpEx;
// Initiate environment ... since it won't be set at this stage
$this->setup();
@ -1300,7 +1204,8 @@ class session
}
// Determine which message to output
$message = $this->get_ban_message($ban_row, $ban_triggered_by);
$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx);
$message = $ban_manager->get_ban_message($ban_row, $ban_triggered_by, $contact_link);
// A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page
if (defined('IN_CRON'))
@ -1344,19 +1249,6 @@ class session
}
}
/**
* Get ban info message
*
* @param array $ban_row Ban data row from database
* @param string $ban_triggered_by Ban triggered by; allowed 'user', 'ip', 'email'
*
* @return string
*/
protected function get_ban_message(array $ban_row, string $ban_triggered_by): string
{
return ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
}
/**
* Check if ip is blacklisted by Spamhaus SBL
*

View file

@ -879,12 +879,12 @@ class user extends \phpbb\session
{
global $config, $phpbb_root_path, $phpEx;
$till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
$message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
$till_date = ($ban_row['end']) ? $this->format_date($ban_row['end']) : '';
$message = ($ban_row['end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx);
$message = $this->language->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>');
$message .= ($ban_row['ban_give_reason']) ? '<br><br>' . $this->language->lang('BOARD_BAN_REASON', $ban_row['ban_give_reason']) : '';
$message .= ($ban_row['reason']) ? '<br><br>' . $this->language->lang('BOARD_BAN_REASON', $ban_row['reason']) : '';
$message .= '<br><br><em>' . $this->language->lang('BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)) . '</em>';
return $message;

View file

@ -67,13 +67,6 @@
<hr />
<dl>
<dt><label for="banexclude0">{L_BAN_EXCLUDE}{L_COLON}</label><br /><span>{L_BAN_EXCLUDE_EXPLAIN}</span></dt>
<dd>
<label for="banexclude1"><input type="radio" name="banexclude" id="banexclude1" value="1" /> {L_YES}</label>
<label for="banexclude0"><input type="radio" name="banexclude" id="banexclude0" value="0" checked="checked" /> {L_NO}</label>
</dd>
</dl>
<!-- EVENT mcp_ban_fields_after -->
</fieldset>

View file

@ -0,0 +1,766 @@
<?php
namespace phpbb\tests\unit\ban;
use phpbb\ban\exception\invalid_length_exception;
use phpbb\ban\exception\no_valid_emails_exception;
use phpbb\ban\exception\no_valid_ips_exception;
use phpbb\ban\exception\no_valid_users_exception;
use phpbb\ban\exception\type_not_found_exception;
require_once __DIR__ . '/../test_framework/phpbb_session_test_case.php';
class ban_manager_test extends \phpbb_session_test_case
{
protected $ban_manager;
protected $phpbb_container;
protected function getDataSet()
{
return $this->createXMLDataSet(__DIR__ . '/fixtures/sessions_banlist.xml');
}
public function setUp(): void
{
parent::setUp();
global $config, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
$language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new \phpbb\user($language, '\phpbb\datetime');
$user->data['user_id'] = 2;
$user->data['user_email'] = 'foo@bar.com';
$user->data['user_timezone'] = 0;
$config = new \phpbb\config\config([]);
$phpbb_dispatcher = new \phpbb_mock_event_dispatcher();
$phpbb_container = new \phpbb_mock_container_builder();
$ban_type_email = new \phpbb\ban\type\email($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = new \phpbb\ban\type\ip($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$phpbb_log = new \phpbb\log\dummy();
$this->ban_manager = new \phpbb\ban\manager($collection, new \phpbb\cache\driver\dummy(), $this->db, $language, $phpbb_log, $user, 'phpbb_bans', 'phpbb_users');
$phpbb_container->set('ban.manager', $this->ban_manager);
$this->phpbb_container = $phpbb_container;
}
public function data_check_ban(): array
{
return [
[
[],
false
],
[
['user_ip' => '127.0.0.1'],
[
'item' => '127.0.0.1',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '10.0.0.1'], // first IP for 10.0.0.1/28 range
[
'item' => '10.0.0.1/28',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '10.0.0.14'], // last IP for 10.0.0.1/28 range
[
'item' => '10.0.0.1/28',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '10.0.0.15'], // first IP outside 10.0.0.1/28 range
[
'item' => '10.0.0.1/28',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '2001:4860:4860::8888'], // first IP in 2001:4860:4860::8888/12 range
[
'item' => '2001:4860:4860::8888/12',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '200F:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'], // last IP in 2001:4860:4860::8888/12 range
[
'item' => '2001:4860:4860::8888/12',
'end' => '0',
'reason' => '1',
'mode' => 'ip',
],
],
[
['user_ip' => '2010:4860:4860::1'], // IP outside the 2001:4860:4860::8888/12 range
false,
],
[
['user_id' => 2],
false,
],
[
['user_id' => 5], // there is only an expired ban
false,
],
[
['user_id' => 4],
[
'item' => '4',
'end' => '0',
'reason' => '1',
'mode' => 'user',
],
],
[
['user_email' => 'test@phpbb.com'],
false,
],
[
['user_email' => 'bar@example.org'],
[
'item' => 'bar@example.org',
'end' => '0',
'reason' => '1',
'mode' => 'email',
],
],
[
['user_email' => 'test@foo.bar'],
[
'item' => '*@foo.bar',
'end' => '0',
'reason' => '1',
'mode' => 'email',
],
],
];
}
/**
* @dataProvider data_check_ban
*/
public function test_check_ban($user_data, $expected)
{
$this->assertEquals($expected, $this->ban_manager->check($user_data));
}
public function data_get_bans(): array
{
return [
[
'foo',
'',
type_not_found_exception::class
],
[
'ip',
[
[
'ban_id' => '6',
'ban_userid' => 0,
'ban_item' => '10.0.0.1/28',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'ip',
],
[
'ban_id' => '2',
'ban_userid' => 0,
'ban_item' => '127.0.0.1',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'ip',
],
[
'ban_id' => '3',
'ban_userid' => 0,
'ban_item' => '127.1.1.1',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'ip',
],
[
'ban_id' => '7',
'ban_userid' => 0,
'ban_item' => '2001:4860:4860::8888/12',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'ip',
],
],
],
[
'email',
[
[
'ban_id' => '9',
'ban_userid' => 0,
'ban_item' => '*@foo.bar',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'email',
],
[
'ban_id' => '5',
'ban_userid' => 0,
'ban_item' => 'bar@example.org',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'email',
],
],
],
[
'user',
[
[
'ban_id' => '4',
'ban_item' => '4',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'user',
'ban_userid' => 4,
'user_id' => '4',
'username' => 'ipv6_user',
'username_clean' => 'ipv6_user',
'label' => 'ipv6_user',
],
],
],
];
}
/**
* @dataProvider data_get_bans
*/
public function test_get_bans($ban_type, $expected, $expected_exception = false)
{
if ($expected_exception !== false)
{
$this->expectException($expected_exception);
}
$actual = $this->ban_manager->get_bans($ban_type);
// Sort both arrays by ban_item to be synced
if (is_array($expected) && !empty($actual))
{
usort($expected, function($a, $b)
{
return strcmp($a['ban_item'], $b['ban_item']) <=> 0;
}
);
usort($actual, function($a, $b)
{
return strcmp($a['ban_item'], $b['ban_item']) <=> 0;
}
);
}
$this->assertEquals($expected, $actual);
}
public function data_get_ban_end(): array
{
return [
[
0,
20,
0,
],
[
80, // 1 minute plus 20 seconds
20,
1,
],
[
20,
20,
-1,
],
[
2 * 86400, // Ban end should be before this time
20,
-1,
'1970-01-02',
],
[
0,
20,
-1,
'1970-01-02-15:30', // wrong format
invalid_length_exception::class,
],
];
}
/**
* @dataProvider data_get_ban_end
*/
public function test_get_ban_end($expected, $ban_start, $length, $end_date = '', $expected_exception = false)
{
if ($expected_exception)
{
$this->expectException($expected_exception);
}
$start_time = new \DateTime();
$start_time->setTimestamp($ban_start);
$expected_end = new \DateTime();
$expected_end->setTimestamp($expected);
$ban_end = $this->ban_manager->get_ban_end($start_time, $length, $end_date);
if ($length >= 0 || !$end_date)
{
$this->assertEquals($expected_end, $ban_end);
}
else
{
$this->assertLessThan($expected_end, $ban_end);
$this->assertGreaterThan($start_time, $ban_end);
}
}
public function test_get_banned_users()
{
$banned_users = $this->ban_manager->get_banned_users();
$this->assertEquals(
[
4 => 0,
5 => 0
],
$banned_users
);
}
public function test_get_banned_users_own_method()
{
global $phpbb_root_path, $phpEx;
$phpbb_container = new \phpbb_mock_container_builder();
$ban_type_email = new \phpbb\ban\type\email($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = $this->getMockBuilder(\phpbb\ban\type\ip::class)
->setConstructorArgs([$this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys'])
->getMock();
$ban_type_ip->method('get_banned_users')
->willReturn([19 => 1234, 20 => 0]);
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new \phpbb\user($language, '\phpbb\datetime');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, new \phpbb\cache\driver\dummy(), $this->db, $language, $phpbb_log, $user, 'phpbb_bans', 'phpbb_users');
$this->assertEquals(
[
4 => 0,
5 => 0,
19 => 1234,
20 => 0,
],
$ban_manager->get_banned_users()
);
$ban_type_ip_reflection = new \ReflectionClass($ban_type_ip);
$get_excluded_reflection = $ban_type_ip_reflection->getMethod('get_excluded');
$get_excluded_reflection->setAccessible(true);
$this->assertFalse($get_excluded_reflection->invoke($ban_type_ip));
}
public function test_ban_empty_ban_items()
{
global $phpbb_root_path, $phpEx;
$phpbb_container = new \phpbb_mock_container_builder();
$ban_type_email = new \phpbb\ban\type\email($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = $this->getMockBuilder(\phpbb\ban\type\ip::class)
->setConstructorArgs([$this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys'])
->getMock();
$ban_type_ip->method('prepare_for_storage')
->willReturn([]);
$ban_type_ip->method('get_type')
->willReturn('ip');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new \phpbb\user($language, '\phpbb\datetime');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, new \phpbb\cache\driver\dummy(), $this->db, $language, $phpbb_log, $user, 'phpbb_bans', 'phpbb_users');
$start_time = new \DateTime();
$start_time->setTimestamp(1000);
$end_time = new \DateTime();
$end_time->setTimestamp(0);
$this->assertFalse($ban_manager->ban(
'ip',
['192.168.1.1'],
$start_time,
$end_time,
''
));
}
public function data_test_ban(): array
{
return [
[
'user',
['normal_user'],
1000,
500, // end before start
'',
'',
false,
invalid_length_exception::class,
],
[
'foo', // invalid ban type
['normal_user'],
1000,
0, // end before start
'',
'',
false,
type_not_found_exception::class,
],
[
'user',
[], // empty user list
1000,
0,
'',
'',
false,
no_valid_users_exception::class,
],
[
'user',
['founder'], // user same as current user
1000,
0,
'',
'',
false,
no_valid_users_exception::class,
],
[
'user',
['normal_user'],
1000,
0,
'',
'',
true,
],
[
'user',
['normal_u*'],
1000,
0,
'',
'',
true,
],
[
'ip',
[],
1000,
0,
'',
'',
false,
no_valid_ips_exception::class,
],
[
'ip',
['192.168.I.1'], // invalid IP
1000,
0,
'',
'',
false,
no_valid_ips_exception::class,
],
[
'ip',
['192.168.1.1'],
1000,
0,
'',
'',
true,
],
[
'email',
['this_is_not_an_email'],
1000,
0,
'',
'',
false,
no_valid_emails_exception::class
],
[
'email',
['test@example.com'],
1000,
0,
'',
'',
true,
],
[
'email',
['*@foo.bar'],
1000,
0,
'',
'',
true,
],
[
'email',
['test@example.com', str_repeat('a', 100) . '@example.com'], // one email too long, shouldn't cause any issues though
1000,
0,
'',
'',
true,
],
];
}
/**
* @dataProvider data_test_ban
*/
public function test_ban($mode, $items, $start, $end, $reason, $display_reason, $expected, $expected_exception = '')
{
if ($expected_exception)
{
$this->expectException($expected_exception);
}
$start_time = new \DateTime();
$start_time->setTimestamp($start);
$end_time = new \DateTime();
$end_time->setTimestamp($end);
$ban_return = $this->ban_manager->ban($mode, $items, $start_time, $end_time, $reason, $display_reason);
$this->assertEquals($expected, $ban_return);
}
public function test_ban_actual()
{
$start_time = new \DateTime();
$start_time->setTimestamp(1000);
$end_time = new \DateTime();
$end_time->setTimestamp(0);
$ban_return = $this->ban_manager->ban('ip', ['121.122.123.124'], $start_time, $end_time, '', 'because');
$this->assertTrue($ban_return);
$this->assertEquals(
[
'item' => '121.122.123.124',
'end' => 0,
'reason' => 'because',
'mode' => 'ip'
],
$this->ban_manager->check(['user_ip' => '121.122.123.124'])
);
}
public function data_test_unban(): array
{
return [
[
'does_not_exist',
[10],
[],
type_not_found_exception::class
],
[
'user',
[4],
[
[
'ban_id' => '4',
'ban_userid' => '4',
'ban_item' => '4',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'ban_mode' => 'user',
'user_id' => '4',
'username' => 'ipv6_user',
'username_clean' => 'ipv6_user',
'label' => 'ipv6_user',
],
],
],
];
}
/**
* @dataProvider data_test_unban
*/
public function test_unban($mode, $items, $expected, $expected_exception = '')
{
if ($expected_exception)
{
$this->expectException($expected_exception);
}
$before_bans = $this->ban_manager->get_bans($mode);
$this->ban_manager->unban($mode, $items);
$after_bans = $this->ban_manager->get_bans($mode);
$ban_diff = array_diff_assoc($before_bans, count($after_bans) ? $after_bans : []);
$this->assertEquals($expected, $ban_diff);
}
public function test_unban_invalid_type()
{
$this->expectException(type_not_found_exception::class);
$this->ban_manager->unban('does_not_exist', []);
}
public function test_base_type_methods()
{
$ban_type_ip = $this->phpbb_container->get('ban.type.ip');
$base_type_reflection = new \ReflectionClass(\phpbb\ban\type\base::class);
$after_unban = $base_type_reflection->getMethod('after_unban');
$this->assertEquals([], $after_unban->invoke($ban_type_ip, ['items' => ['foo']]));
$check = $base_type_reflection->getMethod('check');
$this->assertFalse($check->invoke($ban_type_ip, [], []));
}
public function data_get_ban_message(): array
{
return [
[
[
'end' => 0,
],
'foobar',
'http://foo.bar',
'You have been <strong>permanently</strong> banned from this board.<br><br>Please contact the <a href="http://foo.bar">Board Administrator</a> for more information.<br><br><em>BAN_TRIGGERED_BY_FOOBAR</em>',
],
[
[
'end' => 1,
],
'foobar',
'http://foo.bar',
'You have been banned from this board until <strong></strong>.<br><br>Please contact the <a href="http://foo.bar">Board Administrator</a> for more information.<br><br><em>BAN_TRIGGERED_BY_FOOBAR</em>',
],
[
[
'end' => 1,
'reason' => 'just because',
],
'foobar',
'http://foo.bar',
'You have been banned from this board until <strong></strong>.<br><br>Please contact the <a href="http://foo.bar">Board Administrator</a> for more information.<br><br>Reason given for ban: <strong>just because</strong><br><br><em>BAN_TRIGGERED_BY_FOOBAR</em>',
],
];
}
/**
* @dataProvider data_get_ban_message
*/
public function test_get_ban_message($ban_row, $ban_triggered_by, $contact_link, $expected)
{
$this->assertEquals($expected, $this->ban_manager->get_ban_message($ban_row, $ban_triggered_by, $contact_link));
}
public function test_get_ban_options_user()
{
$foo = $this->ban_manager->get_bans('user');
$this->assertEquals(
[
[
'ban_id' => 4,
'ban_userid' => '4',
'ban_mode' => 'user',
'ban_item' => '4',
'ban_start' => '1111',
'ban_end' => '0',
'ban_reason' => 'HAHAHA',
'ban_reason_display' => '1',
'user_id' => '4',
'username' => 'ipv6_user',
'username_clean' => 'ipv6_user',
'label' => 'ipv6_user',
],
],
$foo
);
}
}

View file

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_users">
<column>user_id</column>
<column>username</column>
<column>username_clean</column>
<column>user_permissions</column>
<column>user_sig</column>
<column>user_email</column>
<column>user_ip</column>
<column>user_type</column>
<row>
<value>1</value>
<value>anonymous</value>
<value>anonymous</value>
<value></value>
<value></value>
<value></value>
<value>127.0.0.1</value>
<value>2</value>
</row>
<row>
<value>2</value>
<value>founder</value>
<value>founder</value>
<value></value>
<value></value>
<value>admin@foo.bar</value>
<value>21.22.23.24</value>
<value>3</value>
</row>
<row>
<value>3</value>
<value>normal_user</value>
<value>normal_user</value>
<value></value>
<value></value>
<value>normal_user@foo.bar</value>
<value>21.22.23.25</value>
<value>0</value>
</row>
<row>
<value>4</value>
<value>ipv6_user</value>
<value>ipv6_user</value>
<value></value>
<value></value>
<value>normal_user@foo.bar</value>
<value>2345:0425:2CA1:0000:0000:0567:5673:23b5</value>
<value>0</value>
</row>
<row>
<value>5</value>
<value>another_user</value>
<value>another_user</value>
<value></value>
<value></value>
<value>bar@example.org</value>
<value>123.124.125.126</value>
<value>0</value>
</row>
</table>
<table name="phpbb_sessions">
<column>session_id</column>
<column>session_user_id</column>
<column>session_ip</column>
<column>session_browser</column>
<column>session_admin</column>
<row>
<value>bar_session000000000000000000000</value>
<value>4</value>
<value>127.0.0.1</value>
<value>user agent</value>
<value>1</value>
</row>
</table>
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_mode</column>
<column>ban_item</column>
<column>ban_start</column>
<column>ban_end</column>
<column>ban_reason</column>
<column>ban_reason_display</column>
<row>
<value>2</value>
<value>0</value>
<value>ip</value>
<value>127.0.0.1</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>3</value>
<value>0</value>
<value>ip</value>
<value>127.1.1.1</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>4</value>
<value>4</value>
<value>user</value>
<value>4</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>5</value>
<value>0</value>
<value>email</value>
<value>bar@example.org</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>6</value>
<value>0</value>
<value>ip</value>
<value>10.0.0.1/28</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>7</value>
<value>0</value>
<value>ip</value>
<value>2001:4860:4860::8888/12</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>8</value>
<value>0</value>
<value>invalid_mode</value>
<value>foo</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>9</value>
<value>0</value>
<value>email</value>
<value>*@foo.bar</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>10</value>
<value>10</value>
<value>user</value>
<value>3</value>
<value>1111</value>
<value>1234</value>
<value>expired</value>
<value>1</value>
</row>
</table>
</dataset>

View file

@ -34,6 +34,8 @@ $phpbb_class_loader_ext = new \phpbb\class_loader('\\', $phpbb_root_path . 'ext/
$phpbb_class_loader_ext->register();
$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', $phpbb_root_path . 'phpbb/', "php");
$phpbb_class_loader->register();
$phpbb_class_loader_tests = new \phpbb\class_loader('phpbb\\tests\\', $phpbb_root_path . '../tests/', 'php');
$phpbb_class_loader_tests->register();
require_once 'test_framework/phpbb_test_case_helpers.php';
require_once 'test_framework/phpbb_test_case.php';

View file

@ -153,9 +153,9 @@ class phpbb_boolean_processor_test extends phpbb_database_test_case
'LEFT_JOIN' => array(
array(
'FROM' => array(
'phpbb_banlist' => 'b',
'phpbb_bans' => 'b',
),
'ON' => 'u.user_id = b.ban_userid',
'ON' => 'b.ban_item = ' . $db->cast_expr_to_string('u.user_id'),
),
),
'WHERE' => array('AND',
@ -172,6 +172,7 @@ class phpbb_boolean_processor_test extends phpbb_database_test_case
array(
array('ug.group_id', '=', 1),
array('b.ban_id', 'IS_NOT', NULL),
array('b.ban_mode', '=', "'user'"),
),
),
),
@ -290,9 +291,9 @@ class phpbb_boolean_processor_test extends phpbb_database_test_case
'LEFT_JOIN' => array(
array(
'FROM' => array(
'phpbb_banlist' => 'b',
'phpbb_bans' => 'b',
),
'ON' => 'u.user_id = b.ban_userid',
'ON' => 'b.ban_item = ' . $db->cast_expr_to_string('u.user_id'),
),
),
'WHERE' => array('AND',

View file

@ -36,9 +36,9 @@ class phpbb_dbal_cross_join_test extends phpbb_database_test_case
'LEFT_JOIN' => array(
array(
'FROM' => array(
'phpbb_banlist' => 'b',
'phpbb_bans' => 'b',
),
'ON' => 'u.user_id = b.ban_userid',
'ON' => 'b.ban_item = ' . $db->cast_expr_to_string('u.user_id'),
),
),
'WHERE' => 'ug.group_id = 1

View file

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_mode</column>
<column>ban_item</column>
<row>
<value>1</value>
<value>user</value>
<value>2</value>
</row>
</table>

View file

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_mode</column>
<column>ban_item</column>
<row>
<value>1</value>
<value>user</value>
<value>2</value>
</row>
</table>

View file

@ -1,38 +1,69 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_userid</column>
<column>ban_exclude</column>
<column>ban_mode</column>
<column>ban_end</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>0</value>
<value>user</value>
<value>0</value>
</row>
<row>
<value>3</value>
<value>0</value>
<value>user</value>
<value>0</value>
</row>
<row>
<value>4</value>
<value>0</value>
<value>user</value>
<value>2</value>
</row>
<row>
<value>5</value>
<value>0</value>
<value>999999999999999999999</value>
<value>user</value>
<value>2147485547</value>
</row>
<row>
<value>6</value>
<value>0</value>
<value>user</value>
<value>3</value>
</row>
</table>
<table name="phpbb_users">
<column>user_id</column>
<column>username_clean</column>
<column>user_permissions</column>
<column>user_sig</column>
<row>
<value>2</value>
<value>admin</value>
<value></value>
<value></value>
</row>
<row>
<value>3</value>
<value>user3</value>
<value></value>
<value></value>
</row>
<row>
<value>4</value>
<value>user4</value>
<value></value>
<value></value>
</row>
<row>
<value>5</value>
<value>user5</value>
<value></value>
<value></value>
</row>
<row>
<value>6</value>
<value>user6</value>
<value></value>
<value></value>
</row>
</table>
</dataset>

View file

@ -1,26 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_exclude</column>
<column>ban_mode</column>
<column>ban_item</column>
<column>ban_start</column>
<column>ban_end</column>
<column>ban_email</column>
<column>ban_give_reason</column>
<column>ban_reason</column>
<column>ban_reason_display</column>
<row>
<value>1</value>
<value>0</value>
<value>0</value>
<value>0</value>
<value>email</value>
<value>banned@example.com</value>
<value>0</value>
<value>0</value>
<value></value>
<value></value>
</row>
<row>
<value>2</value>
<value>0</value>
<value>0</value>
<value>0</value>
<value>email</value>
<value>banned2@example.com</value>
<value>0</value>
<value>0</value>
<value>just because</value>
<value>just because</value>
</row>
</table>

View file

@ -20,6 +20,47 @@ class phpbb_get_banned_user_ids_test extends phpbb_database_test_case
return $this->createXMLDataSet(__DIR__ . '/fixtures/banned_users.xml');
}
protected function setUp(): void
{
global $db, $phpbb_container, $phpbb_root_path, $phpEx;
$db = $this->new_dbal();
parent::setUp();
$phpbb_container = new phpbb_mock_container_builder();
$config = new \phpbb\config\config([]);
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$language = new phpbb\language\language(new phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new phpbb\user($language, '\phpbb\datetime');
$user->data['user_email'] = '';
$cache = new \phpbb\cache\service(
new \phpbb\cache\driver\dummy(),
$config,
$db,
$phpbb_dispatcher,
$phpbb_root_path,
$phpEx
);
$cache->get_driver()->purge();
$ban_type_email = new \phpbb\ban\type\email($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = new \phpbb\ban\type\ip($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, $cache->get_driver(), $db, $language, $phpbb_log, $user, 'phpbb_bans', 'phpbb_users');
$phpbb_container->set('ban.manager', $ban_manager);
}
public function phpbb_get_banned_user_ids_data()
{
return array(
@ -35,6 +76,11 @@ class phpbb_get_banned_user_ids_test extends phpbb_database_test_case
array(array(1, 2, 4, 5, 6), false),
array(2 => 2),
),
array(
// True to get users currently banned, but should only return passed user IDs
array(array(5, 6, 7), true),
array(5 => 5),
),
array(
// Unix timestamp to get users banned until that time
array(array(1, 2, 4, 5, 6), 2),
@ -43,15 +89,6 @@ class phpbb_get_banned_user_ids_test extends phpbb_database_test_case
);
}
protected function setUp(): void
{
global $db;
$db = $this->new_dbal();
parent::setUp();
}
/**
* @dataProvider phpbb_get_banned_user_ids_data
*/

View file

@ -28,18 +28,43 @@ class phpbb_functions_validate_user_email_test extends phpbb_database_test_case
protected function setUp(): void
{
global $cache, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
global $cache, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
parent::setUp();
$cache = new \phpbb\cache\driver\file();
$cache->purge();
$phpbb_container = new phpbb_mock_container_builder();
$config = new \phpbb\config\config([]);
$this->db = $this->new_dbal();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$language = new phpbb\language\language(new phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$this->user = new phpbb\user($language, '\phpbb\datetime');
$this->user->data['user_email'] = '';
$this->helper = new phpbb_functions_validate_data_helper($this);
$cache = new \phpbb\cache\service(
new \phpbb\cache\driver\dummy(),
$config,
$this->db,
$phpbb_dispatcher,
$phpbb_root_path,
$phpEx
);
$cache->get_driver()->purge();
$ban_type_email = new \phpbb\ban\type\email($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = new \phpbb\ban\type\ip($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, $cache->get_driver(), $this->db, $language, $phpbb_log, $this->user, 'phpbb_bans', 'phpbb_users');
$phpbb_container->set('ban.manager', $ban_manager);
}
/**

View file

@ -369,7 +369,7 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
$this->db->sql_freeresult($result);
$sql = 'SELECT ban_id
FROM ' . BANLIST_TABLE . '
FROM ' . BANS_TABLE . '
ORDER BY ban_id ASC';
$result = $this->db->sql_query($sql);
$this->assertEquals($expected_ban, $this->db->sql_fetchrowset($result), 'Ban table content is mismatching after deleting a user.');

View file

@ -36,30 +36,42 @@
<value></value>
</row>
</table>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_email</column>
<column>ban_mode</column>
<column>ban_item</column>
<column>ban_start</column>
<column>ban_end</column>
<column>ban_reason</column>
<column>ban_give_reason</column>
<column>ban_reason_display</column>
<row>
<value>1</value>
<value>2</value>
<value></value>
<value>user</value>
<value>2</value>
<value>0</value>
<value>0</value>
<value></value>
<value></value>
</row>
<row>
<value>2</value>
<value>3</value>
<value></value>
<value>user</value>
<value>3</value>
<value>0</value>
<value>0</value>
<value></value>
<value></value>
</row>
<row>
<value>3</value>
<value>0</value>
<value></value>
<value>user</value>
<value>0</value>
<value>0</value>
<value>0</value>
<value></value>
<value></value>
</row>

View file

@ -33,8 +33,6 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case
false, false, false, false, /* should be banned? -> */ false),
array('Matching values in the database, should be banned',
4, '127.0.0.1', 'bar@example.org', true, /* should be banned? -> */ true),
array('IP Banned, should be banned',
false, '127.1.1.1', false, false, /* should be banned? -> */ true),
);
}
@ -53,7 +51,10 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case
'BAN_TRIGGERED_BY_USER' => 'BAN_TRIGGERED_BY_USER',
];
global $cache, $config, $phpbb_root_path, $phpEx, $phpbb_filesystem;
global $cache, $config, $phpbb_root_path, $phpEx, $phpbb_filesystem, $phpbb_container, $user;
$language = new phpbb\language\language(new phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new \phpbb\user($language, '\phpbb\datetime');
$phpbb_filesystem = new \phpbb\filesystem\filesystem();
@ -73,6 +74,22 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case
$phpbb_root_path,
$phpEx
);
$phpbb_container = new phpbb_mock_container_builder();
$ban_type_email = new \phpbb\ban\type\email($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = new \phpbb\ban\type\ip($this->db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, $cache->get_driver(), $this->db, $language, $phpbb_log, $user, 'phpbb_bans', 'phpbb_users');
$phpbb_container->set('ban.manager', $ban_manager);
}
protected function tearDown(): void

View file

@ -26,34 +26,46 @@
<value>1</value>
</row>
</table>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_ip</column>
<column>ban_email</column>
<column>ban_mode</column>
<column>ban_item</column>
<column>ban_start</column>
<column>ban_end</column>
<column>ban_exclude</column>
<column>ban_reason</column>
<column>ban_give_reason</column>
<column>ban_reason_display</column>
<row>
<value>2</value>
<value>4</value>
<value>ip</value>
<value>127.0.0.1</value>
<value>bar@example.org</value>
<value>1111</value>
<value>0</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>3</value>
<value>0</value>
<value>ip</value>
<value>127.1.1.1</value>
<value></value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>4</value>
<value>user</value>
<value>4</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>
</row>
<row>
<value>5</value>
<value>email</value>
<value>bar@example.org</value>
<value>1111</value>
<value>0</value>
<value>HAHAHA</value>
<value>1</value>

View file

@ -30,11 +30,13 @@
<column>session_ip</column>
<column>session_browser</column>
</table>
<table name="phpbb_banlist">
<table name="phpbb_bans">
<column>ban_id</column>
<column>ban_userid</column>
<column>ban_email</column>
<column>ban_mode</column>
<column>ban_item</column>
<column>ban_start</column>
<column>ban_end</column>
<column>ban_reason</column>
<column>ban_give_reason</column>
<column>ban_reason_display</column>
</table>
</dataset>

View file

@ -38,7 +38,7 @@ class phpbb_session_testable_factory
public function __construct()
{
// default configuration values
$this->config_data = array(
$this->config_data = [
'allow_autologin' => false,
'auth_method' => 'db',
'forwarded_for_check' => true,
@ -53,13 +53,14 @@ class phpbb_session_testable_factory
'limit_search_load' => 0,
'ip_check' => 3,
'browser_check' => 1,
);
];
$this->cache_data = array(
'_bots' => array(),
);
$this->cache_data = [
'_bots' => [],
'_ban_info' => [],
];
$this->cookies = array();
$this->cookies = [];
$this->server_data = $_SERVER;
}
@ -73,7 +74,8 @@ class phpbb_session_testable_factory
public function get_session(\phpbb\db\driver\driver_interface $dbal)
{
// set up all the global variables used by session
global $SID, $_SID, $db, $config, $cache, $request, $phpbb_container, $phpbb_root_path;
global $SID, $_SID, $db, $config, $cache, $request, $phpbb_container, $phpbb_dispatcher;
global $user, $phpbb_root_path, $phpEx;
$request = $this->request = new phpbb_mock_request(
array(),
@ -88,6 +90,8 @@ class phpbb_session_testable_factory
$cache = $this->cache = new phpbb_mock_cache($this->get_cache_data());
$SID = $_SID = null;
$language = new phpbb\language\language(new phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$user = new \phpbb\user($language, '\phpbb\datetime');
$phpbb_container = $this->container = new phpbb_mock_container_builder();
$phpbb_container->set(
@ -103,6 +107,24 @@ class phpbb_session_testable_factory
$provider_collection
);
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$ban_type_email = new \phpbb\ban\type\email($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_user = new \phpbb\ban\type\user($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$ban_type_ip = new \phpbb\ban\type\ip($db, 'phpbb_bans', 'phpbb_users', 'phpbb_sessions', 'phpbb_sessions_keys');
$phpbb_container->set('ban.type.email', $ban_type_email);
$phpbb_container->set('ban.type.user', $ban_type_user);
$phpbb_container->set('ban.type.ip', $ban_type_ip);
$collection = new \phpbb\di\service_collection($phpbb_container);
$collection->add('ban.type.email');
$collection->add('ban.type.user');
$collection->add('ban.type.ip');
$phpbb_log = new \phpbb\log\dummy();
$ban_manager = new \phpbb\ban\manager($collection, $cache, $db, $language, $phpbb_log, $user,'phpbb_bans', 'phpbb_users');
$phpbb_container->set('ban.manager', $ban_manager);
$session = new phpbb_mock_session_testable;
return $session;
}

View file

@ -29,7 +29,7 @@ abstract class phpbb_session_test_case extends phpbb_database_test_case
{
parent::setUp();
global $symfony_request, $phpbb_path_helper, $request, $phpbb_root_path, $phpEx;
global $symfony_request, $phpbb_path_helper, $phpbb_root_path, $phpEx;
$symfony_request = new \phpbb\symfony_request(
new phpbb_mock_request()
);