Limit execution time for forum file-listing (#1211)

* Limit execution time for forum file-listing

* Prevent multiple ajax calling
---------

Co-authored-by: Roman Kelesidis <roman25052006.kelesh@gmail.com>
This commit is contained in:
Cønstantine Kovalensky 2023-12-18 09:03:00 +04:00 committed by GitHub
commit 0b499dc137
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 42 deletions

View file

@ -302,8 +302,18 @@ function make_rand_str(int $length = 10): string
return $randomString;
}
function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false)
function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false, $timeout = false)
{
if ($timeout) {
static $recursions = 0;
if (time() > (TIMENOW + $timeout)) {
return [
'timeout' => true,
'recs' => $recursions
];
}
$recursions++;
}
if (is_array($var)) {
foreach ($var as $k => $v) {
if (is_array($v)) {
@ -312,7 +322,7 @@ function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false)
} elseif ($array_only) {
$var[$k] = $fn($v);
} else {
array_deep($var[$k], $fn);
array_deep($var[$k], $fn, timeout: $timeout);
}
} elseif (!$array_only) {
$var[$k] = $fn($v);

View file

@ -27,7 +27,6 @@ if ($mode === 'get_feed_url' && ($type === 'f' || $type === 'u') && $id >= 0) {
if ($type == 'f') {
// Check if the user has actually sent a forum ID
$sql = "SELECT allow_reg_tracker, forum_name FROM " . BB_FORUMS . " WHERE forum_id = $id LIMIT 1";
//DIE($sql);
if (!$forum_data = DB()->fetch_row($sql)) {
if ($id == 0) {
$forum_data = [];

View file

@ -540,7 +540,7 @@ $bb_cfg['mem_on_start'] = memory_get_usage();
$bb_cfg['translate_dates'] = true; // in displaying time
$bb_cfg['use_word_censor'] = true;
$bb_cfg['show_jumpbox'] = true; // Whether to show jumpbox (on viewtopic.php and viewforum.php)
$bb_cfg['flist_time_limit'] = 15; // Max number of seconds to process file lists before throwing an error
$bb_cfg['last_visit_date_format'] = 'd-M H:i';
$bb_cfg['last_post_date_format'] = 'd-M-y H:i';
$bb_cfg['poll_max_days'] = 180; // How many days will the poll be active

View file

@ -41,10 +41,12 @@ class TorrentFileList
*/
public function get_filelist()
{
global $html;
if (($this->tor_decoded['info']['meta version'] ?? 1) === 2) {
if (is_array($this->tor_decoded['info']['file tree'] ?? null)) {
return $this->fileTreeList($this->tor_decoded['info']['file tree'], $this->tor_decoded['info']['name'] ?? ''); //v2
global $bb_cfg, $html;
$info = &$this->tor_decoded['info'];
if (isset($info['meta version'], $info['file tree'])) { //v2
if (($info['meta version']) === 2 && is_array($info['file tree'])) {
return $this->fileTreeList($info['file tree'], $info['name'] ?? '', $bb_cfg['flist_time_limit']);
}
}
@ -69,7 +71,9 @@ class TorrentFileList
*/
private function build_filelist_array()
{
$info = $this->tor_decoded['info'];
global $bb_cfg;
$info = &$this->tor_decoded['info'];
if (isset($info['name.utf-8'])) {
$info['name'] =& $info['name.utf-8'];
@ -90,7 +94,11 @@ class TorrentFileList
if (isset($f['attr']) && $f['attr'] === 'p') {
continue;
}
array_deep($f['path'], 'clean_tor_dirname');
$structure = array_deep($f['path'], 'clean_tor_dirname', timeout: $bb_cfg['flist_time_limit']);
if (isset($structure['timeout'])) {
bb_die("Timeout, too many nested files/directories for file listing, aborting after \n{$structure['recs']} recursive calls.\nNesting level: " . count($info['files'], COUNT_RECURSIVE));
}
$length = isset($f['length']) ? (float)$f['length'] : 0;
$subdir_count = \count($f['path']) - 1;
@ -137,14 +145,22 @@ class TorrentFileList
* @param string $name
* @return string
*/
public function fileTreeList(array $array, string $name = ''): string
public function fileTreeList(array $array, string $name = '', int $timeout = 0, bool $child = false): string
{
$allItems = '';
if ($timeout) {
static $recursions = 0;
if (time() > (TIMENOW + $timeout)) {
bb_die("Timeout, too many nested files/directories for file listing, aborting after \n$recursions recursive calls.\nNesting level: " . count($this->tor_decoded['info']['file tree'], COUNT_RECURSIVE));
}
$recursions++;
}
foreach ($array as $key => $value) {
$key = htmlCHR($key);
$key = clean_tor_dirname($key);
if (!isset($value[''])) {
$html_v2 = $this->fileTreeList($value);
$html_v2 = $this->fileTreeList($value, timeout: $timeout, child: true);
$allItems .= "<li><span class=\"b\">$key</span><ul>$html_v2</ul></li>";
} else {
$length = $value['']['length'];
@ -152,7 +168,11 @@ class TorrentFileList
}
}
return '<div class="tor-root-dir">' . (empty($allItems) ? '' : htmlCHR($name)) . '</div><ul class="tree-root">' . $allItems . '</ul>';
if (!$child) {
return '<div class="tor-root-dir">' . (empty($allItems) ? '' : htmlCHR($name)) . '</div><ul class="tree-root">' . $allItems . '</ul>';
}
return $allItems;
}
/**
@ -166,7 +186,7 @@ class TorrentFileList
{
static $filesList = ['list' => '', 'count' => 0];
foreach ($array as $key => $value) {
$key = htmlCHR($key);
$key = clean_tor_dirname($key);
$current = "$parent/$key";
if (!isset($value[''])) {
$this->fileTreeTable($value, $current);

View file

@ -46,4 +46,5 @@ var.ajax-params {
.loading-1 {
background: transparent url(../images/loading.gif) no-repeat left center;
padding-left: 22px;
padding-block: inherit;
}

View file

@ -297,34 +297,44 @@ function humn_size (size) {
}
ajax.tor_filelist_loaded = false;
$('#tor-filelist-btn').click(function(){
if (ajax.tor_filelist_loaded) {
$('#tor-fl-wrap').toggle();
return false;
}
$('#tor-fl-wrap').show();
$('#tor-filelist-btn').click(function () {
if (ajax.tor_filelist_loaded) {
$('#tor-fl-wrap').toggle();
return false;
} else {
$("#tor-filelist-btn").attr('disabled', true);
}
$('#tor-fl-wrap').show();
ajax.exec({action: 'view_torrent', attach_id: {postrow.attach.tor_reged.ATTACH_ID} });
ajax.callback.view_torrent = function(data) {
$('#tor-filelist').html(data.html);
$('#tor-filelist > ul.tree-root').treeview({
control: "#tor-fl-treecontrol"
});
$('#tor-filelist li.collapsable').each(function(){
var $li = $(this);
var dir_size = 0;
$('i', $li).each(function(){ dir_size += parseInt(this.innerHTML) });
$('span.b:first', $li).append(' &middot; <s>' + humn_size(dir_size) + '</s>');
});
$('#tor-filelist i').each(function(){
var size_bytes = this.innerHTML;
this.innerHTML = '('+ size_bytes +')';
$(this).prepend('<s>'+ humn_size(size_bytes) +'</s> ');
});
ajax.tor_filelist_loaded = true;
};
$('#tor-fl-treecontrol a').click(function(){ this.blur(); });
return false;
ajax.exec({
action: 'view_torrent',
attach_id: {postrow.attach.tor_reged.ATTACH_ID}
});
ajax.callback.view_torrent = function (data) {
$('#tor-filelist').html(data.html);
$('#tor-filelist > ul.tree-root').treeview({
control: "#tor-fl-treecontrol"
});
$('#tor-filelist li.collapsable').each(function () {
var $li = $(this);
var dir_size = 0;
$('i', $li).each(function () {
dir_size += parseInt(this.innerHTML)
});
$('span.b:first', $li).append(' &middot; <s>' + humn_size(dir_size) + '</s>');
});
$('#tor-filelist i').each(function () {
var size_bytes = this.innerHTML;
this.innerHTML = '(' + size_bytes + ')';
$(this).prepend('<s>' + humn_size(size_bytes) + '</s> ');
});
ajax.tor_filelist_loaded = true;
$("#tor-filelist-btn").attr('disabled', false);
};
$('#tor-fl-treecontrol a').click(function () {
this.blur();
});
return false;
});
</script>