mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 18:01:27 +00:00
382 lines
12 KiB
PHP
382 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Http\Middleware;
|
|
|
|
use App\Http\Middleware\BlockAbusiveServices;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Tests\TestCase;
|
|
|
|
final class BlockAbusiveServicesTest extends TestCase
|
|
{
|
|
private BlockAbusiveServices $middleware;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->middleware = app(BlockAbusiveServices::class);
|
|
Cache::flush();
|
|
}
|
|
|
|
/**
|
|
* Test that normal requests pass through.
|
|
*/
|
|
public function test_allows_normal_requests(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS15169 Google LLC',
|
|
'org' => 'Google LLC',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$this->assertEquals('OK', $response->getContent());
|
|
}
|
|
|
|
/**
|
|
* Test that AIOStreams User-Agent is blocked.
|
|
*/
|
|
public function test_blocks_aiostreams_user_agent(): void
|
|
{
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'AIOStreams/1.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
$this->assertStringContainsString('Streaming services are not allowed', $response->getContent());
|
|
}
|
|
|
|
/**
|
|
* Test that UsenetStreamer User-Agent is blocked.
|
|
*/
|
|
public function test_blocks_usenetstreamer_user_agent(): void
|
|
{
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'UsenetStreamer/2.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
$this->assertStringContainsString('Streaming services are not allowed', $response->getContent());
|
|
}
|
|
|
|
/**
|
|
* Test that Stremio User-Agent is blocked.
|
|
*/
|
|
public function test_blocks_stremio_user_agent(): void
|
|
{
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Stremio/4.5.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
$this->assertStringContainsString('Streaming services are not allowed', $response->getContent());
|
|
}
|
|
|
|
/**
|
|
* Test that User-Agent check is case-insensitive.
|
|
*/
|
|
public function test_blocks_user_agent_case_insensitive(): void
|
|
{
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'AIOSTREAMS/1.0 (uppercase)');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* Test that Oracle Cloud ASN is blocked.
|
|
*/
|
|
public function test_blocks_oracle_cloud_asn(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS31898 Oracle Corporation',
|
|
'org' => 'Oracle Corporation',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '129.146.10.50');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
$json = json_decode($response->getContent(), true);
|
|
$this->assertStringContainsString('Oracle Cloud Infrastructure', $json['message']);
|
|
}
|
|
|
|
/**
|
|
* Test that Cloudflare WARP ASN is blocked.
|
|
*/
|
|
public function test_blocks_cloudflare_warp_asn(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS13335 Cloudflare Inc',
|
|
'org' => 'Cloudflare Inc',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '104.16.50.100');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(403, $response->getStatusCode());
|
|
$json = json_decode($response->getContent(), true);
|
|
$this->assertStringContainsString('Cloudflare WARP', $json['message']);
|
|
}
|
|
|
|
/**
|
|
* Test that non-blocked ASNs pass through.
|
|
*/
|
|
public function test_allows_non_blocked_asn(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS15169 Google LLC',
|
|
'org' => 'Google LLC',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* Test that private IPs are allowed (skip ASN lookup).
|
|
*/
|
|
public function test_allows_private_ips(): void
|
|
{
|
|
Http::fake(); // Should not be called
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '192.168.1.100');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
Http::assertNothingSent();
|
|
}
|
|
|
|
/**
|
|
* Test that localhost is allowed.
|
|
*/
|
|
public function test_allows_localhost(): void
|
|
{
|
|
Http::fake(); // Should not be called
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.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());
|
|
Http::assertNothingSent();
|
|
}
|
|
|
|
/**
|
|
* Test that API failures allow request to pass through.
|
|
*/
|
|
public function test_allows_request_on_api_failure(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response(null, 500),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* Test that ASN lookups are cached.
|
|
*/
|
|
public function test_caches_asn_lookups(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS15169 Google LLC',
|
|
'org' => 'Google LLC',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'Mozilla/5.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
// First request
|
|
$this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
// Second request (should use cache)
|
|
$this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
// API should only be called once
|
|
Http::assertSentCount(1);
|
|
}
|
|
|
|
/**
|
|
* Test that empty User-Agent is allowed.
|
|
*/
|
|
public function test_allows_empty_user_agent(): void
|
|
{
|
|
Http::fake([
|
|
'ip-api.com/*' => Http::response([
|
|
'status' => 'success',
|
|
'as' => 'AS15169 Google LLC',
|
|
'org' => 'Google LLC',
|
|
], 200),
|
|
]);
|
|
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* Test response is JSON format.
|
|
*/
|
|
public function test_blocked_response_is_json(): void
|
|
{
|
|
$request = Request::create('/api/test', 'GET');
|
|
$request->headers->set('User-Agent', 'AIOStreams/1.0');
|
|
$request->server->set('REMOTE_ADDR', '8.8.8.8');
|
|
|
|
$response = $this->middleware->handle($request, function ($req) {
|
|
return new Response('OK', 200);
|
|
});
|
|
|
|
$json = json_decode($response->getContent(), true);
|
|
|
|
$this->assertIsArray($json);
|
|
$this->assertArrayHasKey('error', $json);
|
|
$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());
|
|
}
|
|
}
|