Some security improvements 🔑 (#1503)

* Some security improvements 🔑

* Update .env.example

* Update Dev.php

* Update CHANGELOG.md

* Update Dev.php

* Update Ajax.php

* Update SqlDb.php

* Updated

* Updated

* Update Dev.php

* Update page_header.tpl

* Updated

* Updated

* Update CHANGELOG.md
This commit is contained in:
Roman Kelesidis 2024-06-10 16:55:55 +07:00 committed by GitHub
commit 0663f55e54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 117 additions and 83 deletions

View file

@ -1,5 +1,5 @@
# Common params
APP_ENV=local
APP_ENV=production
APP_CRON_ENABLED=true
APP_DEMO_MODE=false

View file

@ -6,8 +6,10 @@
**Merged pull requests:**
- Release 2.4.4 🦩 ([belomaxorka](https://github.com/belomaxorka))
- Some security improvements 🔑 [\#1503](https://github.com/torrentpier/torrentpier/pull/1503) ([belomaxorka](https://github.com/belomaxorka))
- Some improvements for integrity checker [\#1501](https://github.com/torrentpier/torrentpier/pull/1501) ([belomaxorka](https://github.com/belomaxorka))
- Minor improvements [\#1502](https://github.com/torrentpier/torrentpier/pull/1502) ([belomaxorka](https://github.com/belomaxorka))
- New Crowdin updates [\#1504](https://github.com/torrentpier/torrentpier/pull/1504) ([Exileum](https://github.com/Exileum))
## [v2.4.3](https://github.com/torrentpier/torrentpier/tree/v2.4.3) (2024-06-09)
[Full Changelog](https://github.com/torrentpier/torrentpier/compare/v2.4.2...v2.4.3)

View file

@ -65,7 +65,6 @@ define('XS_TAG_ENDIF', 8);
define('XS_TAG_BEGINELSE', 11);
// Debug
define('APP_DEBUG', true); // enable application debug
define('SQL_DEBUG', true); // enable forum sql & cache debug
define('SQL_LOG_ERRORS', true); // all SQL_xxx options enabled only if SQL_DEBUG == TRUE
define('SQL_BB_LOG_NAME', 'sql_error_bb'); // mysql log filename (Board)

View file

@ -11,7 +11,7 @@ if (!defined('BB_ROOT')) {
die(basename(__FILE__));
}
global $bb_cfg, $userdata, $template, $DBS, $lang;
global $bb_cfg, $debug, $userdata, $template, $DBS, $lang;
if (!empty($template)) {
$template->assign_vars([
@ -25,7 +25,7 @@ if (!empty($template)) {
$template->pparse('page_footer');
}
$show_dbg_info = (APP_DEBUG && !(isset($_GET['pane']) && $_GET['pane'] == 'left'));
$show_dbg_info = (!$debug->isProduction && !(isset($_GET['pane']) && $_GET['pane'] == 'left'));
if (!$bb_cfg['gzip_compress']) {
flush();

View file

@ -71,7 +71,7 @@ if (!empty($_COOKIE['explain'])) {
}
}
$sql_log = !empty($_COOKIE['sql_log']) ? \TorrentPier\Dev::get_sql_log() : false;
$sql_log = !empty($_COOKIE['sql_log']) ? $debug->getSqlLog() : false;
if ($sql_log) {
echo '<div class="sqlLog" id="sqlLog">' . $sql_log . '</div><!-- / sqlLog --><br clear="all" />';

View file

@ -170,14 +170,16 @@ class Ajax
/**
* Send data
*
* @return void
* @throws Exception
*/
public function send()
public function send(): void
{
global $debug;
$this->response['action'] = $this->action;
if (Dev::sql_dbg_enabled()) {
$this->response['sql_log'] = Dev::get_sql_log();
if ($debug->sqlDebugAllowed()) {
$this->response['sql_log'] = $debug->getSqlLog();
}
// sending output will be handled by $this->ob_handler()
@ -193,7 +195,9 @@ class Ajax
*/
public function ob_handler($contents): string
{
if (APP_DEBUG) {
global $debug;
if (!$debug->isProduction) {
if ($contents) {
$this->response['raw_output'] = $contents;
}

View file

@ -37,7 +37,14 @@ class Dev
*
* @var string
*/
public string $envType = 'local';
private string $envType;
/**
* In production mode
*
* @var bool
*/
public bool $isProduction = false;
/**
* Whoops instance
@ -51,16 +58,20 @@ class Dev
*/
public function __construct()
{
$this->envType = env('APP_ENV', 'local');
$this->envType = env('APP_ENV', 'production');
$this->whoops = new Run;
switch ($this->envType) {
case 'prod':
case 'production':
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
$this->getWhoopsProduction();
$this->isProduction = true;
break;
case 'dev':
case 'local':
case 'development':
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
$this->getWhoops();
@ -128,10 +139,6 @@ class Dev
*/
private function getWhoops(): void
{
if (!APP_DEBUG) {
return;
}
/**
* Show errors on page
*/
@ -170,28 +177,28 @@ class Dev
* @return string
* @throws Exception
*/
public static function get_sql_log(): string
public function getSqlLog(): string
{
global $DBS, $CACHES, $datastore;
$log = '';
foreach ($DBS->srv as $srv_name => $db_obj) {
$log .= !empty($db_obj->dbg) ? self::get_sql_log_html($db_obj, "database: $srv_name [{$db_obj->engine}]") : '';
$log .= !empty($db_obj->dbg) ? $this->getSqlLogHtml($db_obj, "database: $srv_name [{$db_obj->engine}]") : '';
}
foreach ($CACHES->obj as $cache_name => $cache_obj) {
if (!empty($cache_obj->db->dbg)) {
$log .= self::get_sql_log_html($cache_obj->db, "cache: $cache_name [{$cache_obj->db->engine}]");
$log .= $this->getSqlLogHtml($cache_obj->db, "cache: $cache_name [{$cache_obj->db->engine}]");
} elseif (!empty($cache_obj->dbg)) {
$log .= self::get_sql_log_html($cache_obj, "cache: $cache_name [{$cache_obj->engine}]");
$log .= $this->getSqlLogHtml($cache_obj, "cache: $cache_name [{$cache_obj->engine}]");
}
}
if (!empty($datastore->db->dbg)) {
$log .= self::get_sql_log_html($datastore->db, "cache: datastore [{$datastore->db->engine}]");
$log .= $this->getSqlLogHtml($datastore->db, "cache: datastore [{$datastore->db->engine}]");
} elseif (!empty($datastore->dbg)) {
$log .= self::get_sql_log_html($datastore, "cache: datastore [{$datastore->engine}]");
$log .= $this->getSqlLogHtml($datastore, "cache: datastore [{$datastore->engine}]");
}
return $log;
@ -202,9 +209,40 @@ class Dev
*
* @return bool
*/
public static function sql_dbg_enabled(): bool
public function sqlDebugAllowed(): bool
{
return (SQL_DEBUG && APP_DEBUG && !empty($_COOKIE['sql_log']));
return (SQL_DEBUG && !$this->isProduction && !empty($_COOKIE['sql_log']));
}
/**
* Get SQL query html log
*
* @param object $db_obj
* @param string $log_name
*
* @return string
* @throws Exception
*/
private function getSqlLogHtml(object $db_obj, string $log_name): string
{
$log = '';
foreach ($db_obj->dbg as $i => $dbg) {
$id = "sql_{$i}_" . random_int(0, mt_getrandmax());
$sql = $this->shortQuery($dbg['sql'], true);
$time = sprintf('%.4f', $dbg['time']);
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
$log .= '<div onmouseout="$(this).removeClass(\'sqlHover\');" onmouseover="$(this).addClass(\'sqlHover\');" onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . $info . '">'
. '<span style="letter-spacing: -1px;">' . $time . ' </span>'
. '<span class="copyElement" data-clipboard-target="#' . $id . '" title="Copy to clipboard" style="color: rgb(128,128,128); letter-spacing: -1px;">' . $perc . '</span>&nbsp;'
. '<span style="letter-spacing: 0;" id="' . $id . '">' . $sql . '</span>'
. '<span style="color: rgb(128,128,128);"> # ' . $info . ' </span>'
. '</div>';
}
return '<div class="sqlLogTitle">' . $log_name . '</div>' . $log;
}
/**
@ -214,7 +252,7 @@ class Dev
* @param bool $esc_html
* @return string
*/
public static function short_query(string $sql, bool $esc_html = false): string
public function shortQuery(string $sql, bool $esc_html = false): string
{
$max_len = 100;
$sql = str_compact($sql);
@ -227,40 +265,4 @@ class Dev
return $esc_html ? htmlCHR($sql, true) : $sql;
}
/**
* Get SQL query html log
*
* @param object $db_obj
* @param string $log_name
*
* @return string
* @throws Exception
*/
private static function get_sql_log_html(object $db_obj, string $log_name): string
{
$log = '';
foreach ($db_obj->dbg as $i => $dbg) {
$id = "sql_{$i}_" . random_int(0, mt_getrandmax());
$sql = self::short_query($dbg['sql'], true);
$time = sprintf('%.4f', $dbg['time']);
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
$log .= ''
. '<div onmouseout="$(this).removeClass(\'sqlHover\');" onmouseover="$(this).addClass(\'sqlHover\');" onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . $info . '">'
. '<span style="letter-spacing: -1px;">' . $time . ' </span>'
. '<span class="copyElement" data-clipboard-target="#' . $id . '" title="Copy to clipboard" style="color: gray; letter-spacing: -1px;">' . $perc . '</span>'
. ' '
. '<span style="letter-spacing: 0;" id="' . $id . '">' . $sql . '</span>'
. '<span style="color: gray"> # ' . $info . ' </span>'
. '</div>'
. "\n";
}
return '
<div class="sqlLogTitle">' . $log_name . '</div>
' . $log . '
';
}
}

View file

@ -23,12 +23,14 @@ class APCu extends Common
public function __construct($prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->prefix = $prefix;
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)

View file

@ -59,6 +59,8 @@ class Common
public function debug($mode, $cur_query = null)
{
global $debug;
if (!$this->dbg_enabled) {
return;
}
@ -69,7 +71,7 @@ class Common
switch ($mode) {
case 'start':
$this->sql_starttime = utime();
$dbg['sql'] = Dev::short_query($cur_query ?? $this->cur_query);
$dbg['sql'] = $debug->shortQuery($cur_query ?? $this->cur_query);
$dbg['src'] = $this->debug_find_source();
$dbg['file'] = $this->debug_find_source('file');
$dbg['line'] = $this->debug_find_source('line');

View file

@ -24,9 +24,11 @@ class File extends Common
public function __construct($dir, $prefix = null)
{
global $debug;
$this->dir = $dir;
$this->prefix = $prefix;
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function get($name, $get_miss_key_callback = '', $ttl = 0)

View file

@ -26,6 +26,8 @@ class Memcache extends Common
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
@ -33,7 +35,7 @@ class Memcache extends Common
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()

View file

@ -26,6 +26,8 @@ class Redis extends Common
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
@ -33,7 +35,7 @@ class Redis extends Common
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->redis = new \Redis();
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()

View file

@ -37,8 +37,10 @@ class SqliteCommon extends Common
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()

View file

@ -17,17 +17,19 @@ use TorrentPier\Dev;
*/
class APCu extends Common
{
public $prefix;
public $engine = 'APCu';
public string $prefix;
public string $engine = 'APCu';
public function __construct($prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function store($title, $var)

View file

@ -139,6 +139,8 @@ class Common
public function debug($mode, $cur_query = null)
{
global $debug;
if (!$this->dbg_enabled) {
return;
}
@ -149,7 +151,7 @@ class Common
switch ($mode) {
case 'start':
$this->sql_starttime = utime();
$dbg['sql'] = Dev::short_query($cur_query ?? $this->cur_query);
$dbg['sql'] = $debug->shortQuery($cur_query ?? $this->cur_query);
$dbg['src'] = $this->debug_find_source();
$dbg['file'] = $this->debug_find_source('file');
$dbg['line'] = $this->debug_find_source('line');

View file

@ -23,9 +23,11 @@ class File extends Common
public function __construct($dir, $prefix = null)
{
global $debug;
$this->prefix = $prefix;
$this->dir = $dir;
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function store($title, $var)

View file

@ -25,6 +25,8 @@ class Memcache extends Common
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
@ -32,7 +34,7 @@ class Memcache extends Common
$this->cfg = $cfg;
$this->prefix = $prefix;
$this->memcache = new \Memcache();
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()

View file

@ -25,13 +25,15 @@ class Redis extends Common
public function __construct($cfg, $prefix = null)
{
global $debug;
if (!$this->is_installed()) {
die("Error: $this->engine extension not installed");
}
$this->cfg = $cfg;
$this->redis = new \Redis();
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
$this->prefix = $prefix;
}

View file

@ -37,8 +37,10 @@ class SqliteCommon extends Common
public function __construct($cfg)
{
global $debug;
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->dbg_enabled = $debug->sqlDebugAllowed();
}
public function connect()

View file

@ -57,10 +57,10 @@ class SqlDb
*/
public function __construct($cfg_values)
{
global $DBS;
global $DBS, $debug;
$this->cfg = array_combine($this->cfg_keys, $cfg_values);
$this->dbg_enabled = (Dev::sql_dbg_enabled() || !empty($_COOKIE['explain']));
$this->dbg_enabled = ($debug->sqlDebugAllowed() || !empty($_COOKIE['explain']));
$this->do_explain = ($this->dbg_enabled && !empty($_COOKIE['explain']));
$this->slow_time = SQL_SLOW_QUERY_TIME;
@ -886,6 +886,8 @@ class SqlDb
*/
public function log_query($log_file = 'sql_queries')
{
global $debug;
$q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.4f', $this->cur_query_time);
$msg = [];
$msg[] = round($this->sql_starttime);
@ -893,7 +895,7 @@ class SqlDb
$msg[] = sprintf('%-6s', $q_time);
$msg[] = sprintf('%05d', getmypid());
$msg[] = $this->db_server;
$msg[] = Dev::short_query($this->cur_query);
$msg[] = $debug->shortQuery($this->cur_query);
$msg = implode(LOG_SEPR, $msg);
$msg .= ($info = $this->query_info()) ? ' # ' . $info : '';
$msg .= ' # ' . $this->debug_find_source() . ' ';
@ -951,12 +953,14 @@ class SqlDb
*
* @param $mode
* @param string $html_table
* @param string $row
* @param array $row
*
* @return bool|string
*/
public function explain($mode, $html_table = '', $row = '')
public function explain($mode, $html_table = '', array $row = [])
{
global $debug;
$query = str_compact($this->cur_query);
// remove comments
$query = preg_replace('#(\s*)(/\*)(.*)(\*/)(\s*)#', '', $query);
@ -975,7 +979,7 @@ class SqlDb
$html_table = false;
if ($result = mysqli_query($this->link, "EXPLAIN $query")) {
while ($row = mysqli_fetch_assoc($result)) {
while ($row = $this->sql_fetchrow($result)) {
$html_table = $this->explain('add_explain_row', $html_table, $row);
}
}
@ -1002,7 +1006,7 @@ class SqlDb
</tr>
<tr><td colspan="2">' . $this->explain_hold . '</td></tr>
</table>
<div class="sqlLog"><div id="' . $htid . '" class="sqlLogRow sqlExplain" style="padding: 0;">' . Dev::short_query($dbg['sql'], true) . '&nbsp;&nbsp;</div></div>
<div class="sqlLog"><div id="' . $htid . '" class="sqlLogRow sqlExplain" style="padding: 0;">' . $debug->shortQuery($dbg['sql'], true) . '&nbsp;&nbsp;</div></div>
<br />';
break;
@ -1024,8 +1028,6 @@ class SqlDb
return $html_table;
break;
case 'display':
echo '<a name="explain"></a><div class="med">' . $this->explain_out . '</div>';
break;

View file

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="initial-scale=1.0">
<title><!-- IF HAVE_NEW_PM -->({HAVE_NEW_PM}) <!-- ENDIF --><!-- IF PAGE_TITLE -->{PAGE_TITLE} :: {SITENAME}<!-- ELSE -->{SITENAME}<!-- ENDIF --></title>
<meta name="application-name" content="{SITENAME}"/>
<meta property="og:site_name" content="{SITENAME}">