From 33faad23557469f06b2757454a6d59f26943b275 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B8nstantine=20Kovalensky?=
<45331093+kovalensky@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:55:46 +0400
Subject: [PATCH] Tracker client stats cache, more robust file list functions,
permissions for file list access (#1069)
---
admin/stats/tracker.php | 42 ++++++++++++++++++-----------
library/includes/file_list_v2.php | 44 ++++++++++++++++++++-----------
library/language/source/main.php | 3 +++
src/Legacy/TorrentFileList.php | 25 +++++++-----------
4 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/admin/stats/tracker.php b/admin/stats/tracker.php
index d7f5b9529..2e32f2661 100644
--- a/admin/stats/tracker.php
+++ b/admin/stats/tracker.php
@@ -82,29 +82,40 @@ $clients_percentage = [];
$numwant = !empty($_GET['client_numwant']) ? (int)$_GET['client_numwant'] : 100;
$client_full = !empty($_GET['client_length']) ? (int)$_GET['client_length'] : false;
-$rowset = DB()->fetch_rowset('SELECT peer_id AS client FROM ' . TMP_TRACKER_TABLE);
+if ($client_full || !$stats_cache = CACHE('tr_cache')->get('tracker_clients_stats')) {
-if (!empty($rowset)) {
+ $rowset = DB()->fetch_rowset('SELECT peer_id AS client FROM ' . TMP_TRACKER_TABLE);
- $client_count = 0;
+ if (!empty($rowset)) {
- foreach ($rowset as $cnt => $row) {
- $clientString = $client_full ? substr($row['client'], 0, $client_full) : substr($row['client'], 0, 3);
- if (!isset($clients[$clientString])) {
- $clients[$clientString] = 1;
+ $client_count = 0;
+
+ foreach ($rowset as $cnt => $row) {
+ $clientString = $client_full ? substr($row['client'], 0, $client_full) : substr($row['client'], 0, 3);
+ if (!isset($clients[$clientString])) {
+ $clients[$clientString] = 1;
+ }
+ else {
+ $clients[$clientString]++;
+ }
+ $client_count++;
}
- else {
- $clients[$clientString]++;
+
+ foreach ($clients as $client => $count) {
+ $percentage = number_format(($count / $client_count) * 100, 2);
+ $clients_percentage[$client] = "[$count] => $percentage%";
}
- $client_count++;
- }
- foreach ($clients as $client => $count) {
- $percentage = number_format(($count / $client_count) * 100, 2);
- $clients_percentage[] = ($client_full ? $client : get_user_torrent_client($client)) . " [$count] => $percentage%";
+ if (!$client_full) {
+ CACHE('tr_cache')->set('tracker_clients_stats', $clients_percentage, 3600);
+ }
}
+} else {
+ $clients_percentage = $stats_cache;
+}
- $client_list = implode('
', array_slice($clients_percentage, 0, $numwant));
+foreach (array_slice($clients_percentage, 0, $numwant) as $client => $value) {
+ $client_list .= ($client_full) ? ("$client => $value
") : get_user_torrent_client($client) . " => $value
";
}
function commify_callback($matches)
@@ -157,6 +168,7 @@ echo (count($clients_percentage) > $numwant) ? ('Peer_ids with more length (version debugging)': '');
echo '';
echo '';
+echo !$client_full ? '
Simple stats for clients are being cached for one hour.
' : ''; echo ''; if ($l = sys('la')) { diff --git a/library/includes/file_list_v2.php b/library/includes/file_list_v2.php index 23ec87eb7..32d87fdf8 100644 --- a/library/includes/file_list_v2.php +++ b/library/includes/file_list_v2.php @@ -6,7 +6,12 @@ if (!defined('BB_ROOT')) { $user->session_start(); -$topic_id = (int)$_GET['t']; +if ($bb_cfg['bt_disable_dht'] && IS_GUEST) { + http_response_code(403); + die($lang['BT_PRIVATE_TRACKER']); +} + +$topic_id = !empty($_GET['t']) ? (int)$_GET['t'] : (http_response_code(404) && die($lang['INVALID_TOPIC_ID'])); $sql = 'SELECT t.attach_id, t.info_hash_v2, ad.physical_filename FROM ' . BB_BT_TORRENTS . ' t @@ -24,13 +29,13 @@ if (empty($row) || empty($row['physical_filename'])) { if (empty($row['info_hash_v2'])) { http_response_code(404); - die('Currently torrents with BitTorrent v2 support are enabled for file listing'); + die($lang['BT_V2_FILE_LIST_ONLY']); } $file_path = get_attachments_dir() . '/' . $row['physical_filename']; if(!is_file($file_path)){ - die($lang['INVALID_ATTACH_ID']); + die($lang['TOR_NOT_FOUND']); } $file_contents = file_get_contents($file_path); @@ -39,29 +44,35 @@ if (!$tor = \Arokettu\Bencode\Bencode::decode($file_contents, dictType: \Arokett die($lang['TORFILE_INVALID']); } +if (isset($tor['info']['private']) && IS_GUEST) { + die($lang['BT_PRIVATE_TORRENT']); +} + $torrent = new TorrentPier\Legacy\TorrentFileList($tor); -$file_list = $torrent->fileTreeTable($tor['info']['file tree']); +$files = $torrent->fileTreeTable($tor['info']['file tree']); $data = [ 'date' => '', 'name' => htmlCHR($tor['info']['name'] ?? ''), 'client' => htmlCHR(substr($tor['created by'] ?? 'unknown client', 0, 20)), - 'size' => humn_size($file_list['size']) + 'size' => humn_size($files['size']), + 'hash' => bin2hex($row['info_hash_v2']) ]; if (isset($tor['creation date']) && is_numeric($tor['creation date'])) { $data['date'] = date("d M Y | G:i:s T", $tor['creation date']); } -echo " +echo <<- - - + + + - File list — {$data['name']} ({$data['size']}) +File information listing | {$data['name']} ({$data['size']}) | {$data['hash']} - +- Document name: {$data['name']} | Date: ({$data['date']}) | Size: {$data['size']} +
Document name: {$data['name']} | Date: ({$data['date']}) | Size: {$data['size']}
Created by: {$data['client']}
-
"; + Path Size Hash ? -
+EOF; -echo implode('', $file_list['list']); +echo $files['list']; echo ' Path Size Hash ? Generated by TorrentPier
+Generated by TorrentPier
'; diff --git a/library/language/source/main.php b/library/language/source/main.php index fce63b4b1..eefdc08ae 100644 --- a/library/language/source/main.php +++ b/library/language/source/main.php @@ -1060,6 +1060,7 @@ $lang['BT_REG_ON_TRACKER'] = 'Register on tracker'; $lang['BT_REG_FAIL'] = 'Could not register torrent on tracker'; $lang['BT_REG_FAIL_SAME_HASH'] = 'Another torrent with same info_hash already registered'; $lang['BT_V2_ONLY_DISALLOWED'] = 'v2-only torrents have been disabled by the administrator at the moment, allowed: v1 and hybrids'; +$lang['BT_V2_FILE_LIST_ONLY'] = 'Currently, only torrents with BitTorrent version 2 support are enabled for separate file listing'; $lang['BT_UNREG_FROM_TRACKER'] = 'Remove from tracker'; $lang['BT_UNREGISTERED'] = 'Torrent unregistered'; $lang['BT_UNREGISTERED_ALREADY'] = 'Torrent already unregistered'; @@ -2321,6 +2322,8 @@ $lang['BT_ANNOUNCE_URL'] = 'Announce url'; $lang['BT_ANNOUNCE_URL_EXPL'] = 'you can define additional allowed urls in "includes/torrent_announce_urls.php"'; $lang['BT_DISABLE_DHT'] = 'Disable DHT network'; $lang['BT_DISABLE_DHT_EXPL'] = 'Disable Peer Exchange and DHT (recommended for private networks, only url announce)'; +$lang['BT_PRIVATE_TRACKER'] = 'This tracker is private: file listing (for guests), DHT | PEX are disabled'; +$lang['BT_PRIVATE_TORRENT'] = 'The creator of this torrent made it private'; $lang['BT_CHECK_ANNOUNCE_URL'] = 'Verify announce url'; $lang['BT_CHECK_ANNOUNCE_URL_EXPL'] = 'register on tracker only allowed urls'; $lang['BT_REPLACE_ANN_URL'] = 'Replace announce url'; diff --git a/src/Legacy/TorrentFileList.php b/src/Legacy/TorrentFileList.php index fcb58a5f8..ed411df9d 100644 --- a/src/Legacy/TorrentFileList.php +++ b/src/Legacy/TorrentFileList.php @@ -44,7 +44,7 @@ class TorrentFileList 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']); //v2 + return $this->fileTreeList($this->tor_decoded['info']['file tree'], $this->tor_decoded['info']['name'] ?? ''); //v2 } } @@ -139,24 +139,21 @@ class TorrentFileList */ public function fileTreeList(array $array, string $name = ''): string { - $folders = []; - $rootFiles = []; + $allItems = ''; foreach ($array as $key => $value) { $key = htmlCHR($key); if (!isset($value[''])) { $html_v2 = $this->fileTreeList($value); - $folders[] = "$key "; + $allItems .= "$html_v2
$key "; } else { $length = (int)$value['']['length']; $root = bin2hex($value['']['pieces root'] ?? ''); - $rootFiles[] = "$html_v2
$key$length "; + $allItems .= "$root
$key$length "; } } - $allFiles = implode('', [...$folders, ...$rootFiles]); - - return '$root
' . (empty($folders) ? '' : htmlCHR($name)) . '' . $allFiles . '
'; + return '' . (empty($allItems) ? '' : htmlCHR($name)) . '' . $allItems . '
'; } /** @@ -168,8 +165,7 @@ class TorrentFileList */ public function fileTreeTable(array $array, string $parent = ''): array { - $filesList = []; - $size = 0; + static $filesList = ['list' => '', 'size' => 0]; foreach ($array as $key => $value) { $key = htmlCHR($key); $current = "$parent/$key"; @@ -178,14 +174,11 @@ class TorrentFileList } else { $length = (int)$value['']['length']; $root = bin2hex($value['']['pieces root'] ?? ''); - $size += $length; - $filesList[] = '' . $current . ' ' . humn_size($length, 2) . ' ' . $root . ' '; + $filesList['size'] += $length; + $filesList['list'] .= ' ' . $current . ' ' . humn_size($length, 2) . ' ' . $root . ' '; } } - return [ - 'list' => $filesList, - 'size' => $size - ]; + return $filesList; } }