190 lines
6.4 KiB
PHP
190 lines
6.4 KiB
PHP
<?php
|
|
namespace Seria\Torrents;
|
|
|
|
use RuntimeException;
|
|
use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler};
|
|
use Index\Security\CSRFP;
|
|
use Sasae\SasaeEnvironment;
|
|
use Syokuhou\IConfig;
|
|
use Seria\Auth\AuthInfo;
|
|
use Seria\Users\UsersContext;
|
|
|
|
class TorrentInfoRouting extends RouteHandler {
|
|
private ?TorrentInfo $torrentInfo = null;
|
|
|
|
public function __construct(
|
|
private IConfig $config,
|
|
private AuthInfo $authInfo,
|
|
private TorrentsContext $torrentsCtx,
|
|
private UsersContext $usersCtx,
|
|
private CSRFP $csrfp,
|
|
private ?SasaeEnvironment $templating
|
|
) {}
|
|
|
|
#[HttpGet('/download/([0-9]+)')]
|
|
public function getDownload($response, $request, string $torrentId) {
|
|
try {
|
|
$torrentInfo = $this->torrentsCtx->getTorrents()->getTorrent($torrentId);
|
|
} catch(RuntimeException $ex) {
|
|
$response->setStatusCode(404);
|
|
return 'Download not found.';
|
|
}
|
|
|
|
$canDownload = $this->torrentsCtx->canDownloadTorrent($torrentInfo, $this->authInfo->getUserInfo());
|
|
if($canDownload !== '') {
|
|
$response->setStatusCode(403);
|
|
|
|
return match($canDownload) {
|
|
'inactive' => 'This download is inactive.',
|
|
'private' => 'You must be logged in for this download.',
|
|
'pending' => 'This download is pending approval.',
|
|
default => $canDownload,
|
|
};
|
|
}
|
|
|
|
$trackerUrl = '';
|
|
if($this->authInfo->isLoggedIn()) {
|
|
$userInfo = $this->authInfo->getUserInfo();
|
|
$passKey = $userInfo->hasPassKey()
|
|
? $userInfo->getPassKey()
|
|
: $this->usersCtx->getUsers()->updatePassKey($userInfo);
|
|
|
|
$trackerUrl = sprintf($this->config->getString('url:user'), $passKey);
|
|
} else
|
|
$trackerUrl = $this->config->getString('url:anon');
|
|
|
|
$response->setContentType('application/x-bittorrent');
|
|
$response->setFileName(htmlspecialchars($torrentInfo->getName()) . '.torrent');
|
|
|
|
return $this->torrentsCtx->encodeTorrent($torrentInfo, $trackerUrl);
|
|
}
|
|
|
|
private function getTorrentInfo(string $torrentId): int {
|
|
if($this->torrentInfo?->getId() === $torrentId)
|
|
return 0;
|
|
|
|
try {
|
|
$this->torrentInfo = $this->torrentsCtx->getTorrents()->getTorrent($torrentId);
|
|
} catch(RuntimeException $ex) {
|
|
return 404;
|
|
}
|
|
|
|
$canDownload = $this->torrentsCtx->canDownloadTorrent($this->torrentInfo, $this->authInfo->getUserInfo());
|
|
if($canDownload !== '')
|
|
return 403;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#[HttpGet('/info/([0-9]+)')]
|
|
public function getInfo($response, $request, string $torrentId) {
|
|
$error = $this->getTorrentInfo($torrentId);
|
|
if($error > 0) return $error;
|
|
|
|
if($this->torrentInfo->hasUser()) {
|
|
$users = $this->usersCtx->getUsers();
|
|
$userInfo = $users->getUser($this->torrentInfo->getUserId(), 'id');
|
|
} else $userInfo = null;
|
|
|
|
$peers = $this->torrentsCtx->getPeers();
|
|
$completePeers = $peers->countCompletePeers($this->torrentInfo);
|
|
$incompletePeers = $peers->countIncompletePeers($this->torrentInfo);
|
|
|
|
$files = $this->torrentsCtx->getFiles();
|
|
$totalFileSize = $files->countTotalSize($this->torrentInfo);
|
|
$fileList = $files->getFiles($this->torrentInfo);
|
|
|
|
return $this->templating->render('info', [
|
|
'torrent_info' => $this->torrentInfo,
|
|
'torrent_user' => $userInfo,
|
|
'torrent_total_size' => $totalFileSize,
|
|
'torrent_complete_peers' => $completePeers,
|
|
'torrent_incomplete_peers' => $incompletePeers,
|
|
'torrent_files' => $fileList,
|
|
]);
|
|
}
|
|
|
|
#[HttpMiddleware('/info/([0-9]+)/rehash')]
|
|
#[HttpMiddleware('/info/([0-9]+)/approve')]
|
|
#[HttpMiddleware('/info/([0-9]+)/deny')]
|
|
public function verifyRequest($response, $request, string $torrentId) {
|
|
if(!$this->authInfo->isLoggedIn())
|
|
return 401;
|
|
|
|
if(!$request->isFormContent())
|
|
return 400;
|
|
|
|
$content = $request->getContent();
|
|
if(!$this->csrfp->verifyToken((string)$content->getParam('_csrfp')))
|
|
return 403;
|
|
|
|
$error = $this->getTorrentInfo($torrentId);
|
|
if($error > 0) return $error;
|
|
}
|
|
|
|
#[HttpPost('/info/([0-9]+)/rehash')]
|
|
public function postRehash($response, $request, string $torrentId) {
|
|
$error = $this->getTorrentInfo($torrentId);
|
|
if($error > 0) return $error;
|
|
|
|
if(!$this->authInfo->getUserInfo()->canRecalculateInfoHash())
|
|
return 403;
|
|
|
|
$builder = TorrentBuilder::import(
|
|
$this->torrentInfo,
|
|
$this->torrentsCtx->getPieces()->getPieces($this->torrentInfo),
|
|
$this->torrentsCtx->getFiles()->getFiles($this->torrentInfo)
|
|
);
|
|
$infoHash = $builder->calculateInfoHash();
|
|
$this->torrentsCtx->getTorrents()->updateTorrentInfoHash($this->torrentInfo, $infoHash);
|
|
|
|
return [
|
|
'hash' => base64_encode($infoHash),
|
|
];
|
|
}
|
|
|
|
#[HttpPost('/info/([0-9]+)/approve')]
|
|
public function postApprove($response, $request, string $torrentId) {
|
|
$error = $this->getTorrentInfo($torrentId);
|
|
if($error > 0) return $error;
|
|
|
|
if(!$this->authInfo->getUserInfo()->canApproveTorrents())
|
|
return 403;
|
|
|
|
$this->torrentsCtx->getTorrents()->approveTorrent($this->torrentInfo);
|
|
|
|
return 204;
|
|
}
|
|
|
|
#[HttpPost('/info/([0-9]+)/deny')]
|
|
public function postDeny($response, $request, string $torrentId) {
|
|
$error = $this->getTorrentInfo($torrentId);
|
|
if($error > 0) return $error;
|
|
|
|
if(!$this->authInfo->getUserInfo()->canApproveTorrents())
|
|
return 403;
|
|
|
|
$this->torrentsCtx->getTorrents()->deleteTorrent($this->torrentInfo);
|
|
|
|
return 204;
|
|
}
|
|
|
|
#[HttpGet('/info.php')]
|
|
public function getInfoPHP($response, $request) {
|
|
$torrentId = (int)$request->getParam('id', FILTER_SANITIZE_NUMBER_INT);
|
|
if($torrentId < 1)
|
|
return 404;
|
|
|
|
$response->redirect(sprintf('/info/%d', $torrentId), true);
|
|
}
|
|
|
|
#[HttpGet('/download.php')]
|
|
public function getDownloadPHP($response, $request) {
|
|
$torrentId = (int)$request->getParam('id', FILTER_SANITIZE_NUMBER_INT);
|
|
if($torrentId < 1)
|
|
return 404;
|
|
|
|
$response->redirect(sprintf('/download/%d', $torrentId), true);
|
|
}
|
|
}
|