mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 00:01:21 +00:00
Fix blocking issue
This commit is contained in:
@@ -17,7 +17,11 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
* Blocks:
|
||||
* - AIOStreams (User-Agent based)
|
||||
* - UsenetStreamer (User-Agent based)
|
||||
* - Configured indexer apps on public indexer API/RSS endpoints (User-Agent based, opt-in)
|
||||
* - Configured indexer apps proxying NZB downloads (User-Agent based, opt-in).
|
||||
* Only NZB download/grab requests are blocked, so proxied searches and RSS
|
||||
* feeds keep working. Redirected grabs (Prowlarr/NZBHydra2 "Redirect" setting)
|
||||
* arrive directly from the download client, whose User-Agent does not match
|
||||
* the configured proxy patterns, and are therefore allowed.
|
||||
* - Oracle Cloud (ASN: AS31898)
|
||||
* - Cloudflare WARP (ASN: AS13335)
|
||||
*/
|
||||
@@ -83,13 +87,13 @@ class BlockAbusiveServices
|
||||
}
|
||||
|
||||
if ($this->shouldBlockProxyIndexerApp($request, $userAgent)) {
|
||||
Log::warning('Blocked proxy indexer app request', [
|
||||
Log::warning('Blocked proxied NZB download from indexer app', [
|
||||
'ip' => $ip,
|
||||
'user_agent' => $userAgent,
|
||||
'uri' => $this->safeRequestUri($request),
|
||||
]);
|
||||
|
||||
return $this->blockedResponse('Access denied: Proxy indexer app access is not allowed.');
|
||||
return $this->blockedResponse('Access denied: Proxying NZB downloads through indexer apps is not allowed.');
|
||||
}
|
||||
|
||||
// Check for blocked ASNs
|
||||
@@ -137,7 +141,7 @@ class BlockAbusiveServices
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->isPublicIndexerEndpoint($request)) {
|
||||
if (! $this->isNzbDownloadRequest($request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -148,15 +152,25 @@ class BlockAbusiveServices
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect public indexer API/RSS endpoints while leaving unrelated requests alone.
|
||||
* Detect NZB download/grab requests so only proxied downloads are blocked.
|
||||
*
|
||||
* Searches, caps and RSS feeds are intentionally out of scope so proxied
|
||||
* searches keep working. Redirected grabs arrive directly from the download
|
||||
* client, whose User-Agent does not match the configured proxy patterns.
|
||||
*/
|
||||
protected function isPublicIndexerEndpoint(Request $request): bool
|
||||
protected function isNzbDownloadRequest(Request $request): bool
|
||||
{
|
||||
if ($request->is('api/v1/api') || $request->is('api/v2/*')) {
|
||||
if ($request->is('api/v2/getnzb')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $request->is('rss/*') && ! $request->is('rss/health');
|
||||
if (! $request->is('api/v1/api')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = strtolower(trim((string) $request->input('t', '')));
|
||||
|
||||
return in_array($type, ['get', 'g'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -320,4 +320,62 @@ final class BlockAbusiveServicesTest extends TestCase
|
||||
$this->assertArrayHasKey('message', $json);
|
||||
$this->assertTrue($json['error']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a proxied NZB download is blocked when the block is enabled.
|
||||
*/
|
||||
public function test_blocks_proxied_download_from_indexer_app(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
$request = Request::create('/api/v1/api?t=get&id=release-guid', 'GET');
|
||||
$request->headers->set('User-Agent', 'Prowlarr/2.0.0');
|
||||
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||
|
||||
$response = $this->middleware->handle($request, function ($req) {
|
||||
return new Response('OK', 200);
|
||||
});
|
||||
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
$this->assertStringContainsString('Proxying NZB downloads through indexer apps is not allowed', $response->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a proxied search is allowed even when the block is enabled.
|
||||
*/
|
||||
public function test_allows_proxied_search_from_indexer_app(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
$request = Request::create('/api/v1/api?t=search&q=linux', 'GET');
|
||||
$request->headers->set('User-Agent', 'Prowlarr/2.0.0');
|
||||
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||
|
||||
$response = $this->middleware->handle($request, function ($req) {
|
||||
return new Response('OK', 200);
|
||||
});
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a redirected download (download-client UA) is allowed.
|
||||
*/
|
||||
public function test_allows_redirected_download_from_download_client(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
$request = Request::create('/api/v1/api?t=get&id=release-guid', 'GET');
|
||||
$request->headers->set('User-Agent', 'SABnzbd/4.3.3');
|
||||
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||
|
||||
$response = $this->middleware->handle($request, function ($req) {
|
||||
return new Response('OK', 200);
|
||||
});
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,40 +76,42 @@ class BlockAbusiveServicesTest extends TestCase
|
||||
$this->assertSame(Response::HTTP_OK, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function test_enabled_proxy_indexer_app_block_denies_configured_user_agent_on_newznab_endpoints(): void
|
||||
public function test_enabled_proxy_indexer_app_block_denies_proxied_downloads(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
foreach ([
|
||||
'/api/v1/api?t=caps',
|
||||
'/api/v1/api?t=search&q=linux',
|
||||
'/api/v1/api?t=get&id=release-guid',
|
||||
] as $uri) {
|
||||
$response = $this->handleRequest($uri, 'Prowlarr/2.0.0');
|
||||
'/api/v1/api?t=get&id=release-guid' => 'Prowlarr/2.0.0',
|
||||
'/api/v1/api?t=g&id=release-guid' => 'Prowlarr/2.0.0',
|
||||
'/api/v2/getnzb?id=release-guid' => 'NZBHydra2 8.3.0',
|
||||
] as $uri => $userAgent) {
|
||||
$response = $this->handleRequest($uri, $userAgent);
|
||||
|
||||
$this->assertSame(Response::HTTP_FORBIDDEN, $response->getStatusCode(), $uri);
|
||||
$this->assertStringContainsString('Proxy indexer app access is not allowed', (string) $response->getContent());
|
||||
$this->assertStringContainsString('Proxying NZB downloads through indexer apps is not allowed', (string) $response->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
public function test_enabled_proxy_indexer_app_block_denies_configured_user_agent_on_v2_endpoints(): void
|
||||
public function test_enabled_proxy_indexer_app_block_allows_proxied_searches(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
foreach ([
|
||||
'/api/v2/capabilities',
|
||||
'/api/v2/search?q=linux',
|
||||
'/api/v2/getnzb?id=release-guid',
|
||||
] as $uri) {
|
||||
$response = $this->handleRequest($uri, 'NZBHydra2 8.3.0');
|
||||
'/api/v1/api?t=caps' => 'Prowlarr/2.0.0',
|
||||
'/api/v1/api?t=search&q=linux' => 'Prowlarr/2.0.0',
|
||||
'/api/v1/api?t=tvsearch&q=linux' => 'Prowlarr/2.0.0',
|
||||
'/api/v2/capabilities' => 'NZBHydra2 8.3.0',
|
||||
'/api/v2/search?q=linux' => 'NZBHydra2 8.3.0',
|
||||
] as $uri => $userAgent) {
|
||||
$response = $this->handleRequest($uri, $userAgent);
|
||||
|
||||
$this->assertSame(Response::HTTP_FORBIDDEN, $response->getStatusCode(), $uri);
|
||||
$this->assertSame(Response::HTTP_OK, $response->getStatusCode(), $uri);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_enabled_proxy_indexer_app_block_denies_configured_user_agent_on_rss_feed_endpoints(): void
|
||||
public function test_enabled_proxy_indexer_app_block_allows_proxied_rss_feeds(): void
|
||||
{
|
||||
config()->set('nntmux.block_proxy_indexer_apps', true);
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
@@ -120,7 +122,7 @@ class BlockAbusiveServicesTest extends TestCase
|
||||
] as $uri) {
|
||||
$response = $this->handleRequest($uri, 'Prowlarr/2.0.0');
|
||||
|
||||
$this->assertSame(Response::HTTP_FORBIDDEN, $response->getStatusCode(), $uri);
|
||||
$this->assertSame(Response::HTTP_OK, $response->getStatusCode(), $uri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,13 +169,13 @@ class BlockAbusiveServicesTest extends TestCase
|
||||
config()->set('nntmux.block_proxy_indexer_app_user_agents', 'Prowlarr/,NZBHydra2');
|
||||
|
||||
$response = $this->handleRequest(
|
||||
'/api/v1/api?t=search&apikey=secret-api-key&api_token=secret-token&passkey=secret-passkey&q=linux',
|
||||
'/api/v1/api?t=get&id=release-guid&apikey=secret-api-key&api_token=secret-token&passkey=secret-passkey',
|
||||
'Prowlarr/2.0.0'
|
||||
);
|
||||
|
||||
$this->assertSame(Response::HTTP_FORBIDDEN, $response->getStatusCode());
|
||||
Log::shouldHaveReceived('warning')
|
||||
->with('Blocked proxy indexer app request', \Mockery::on(function (mixed $context): bool {
|
||||
->with('Blocked proxied NZB download from indexer app', \Mockery::on(function (mixed $context): bool {
|
||||
if (! is_array($context)) {
|
||||
return false;
|
||||
}
|
||||
@@ -183,7 +185,7 @@ class BlockAbusiveServicesTest extends TestCase
|
||||
return str_contains($uri, 'apikey=%5Bredacted%5D')
|
||||
&& str_contains($uri, 'api_token=%5Bredacted%5D')
|
||||
&& str_contains($uri, 'passkey=%5Bredacted%5D')
|
||||
&& str_contains($uri, 'q=linux')
|
||||
&& str_contains($uri, 'id=release-guid')
|
||||
&& ! str_contains($uri, 'secret-api-key')
|
||||
&& ! str_contains($uri, 'secret-token')
|
||||
&& ! str_contains($uri, 'secret-passkey');
|
||||
|
||||
Reference in New Issue
Block a user