Skip to content

Commit cf95031

Browse files
committed
Fixes and Tests
1 parent 3af0d0e commit cf95031

File tree

8 files changed

+320
-14
lines changed

8 files changed

+320
-14
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
},
2424
"autoload": {
2525
"psr-4": {
26-
"Moox\\Firewall\\": "src"
26+
"Moox\\Firewall\\": "src",
27+
"Moox\\Firewall\\Tests\\": "tests"
2728
}
2829
},
2930
"extra": {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!DOCTYPE html>
2+
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<meta name="csrf-token" content="{{ csrf_token() }}">
7+
<title>{{ config('firewall.message', 'Moox Firewall') }}</title>
8+
<style>
9+
* {
10+
margin: 0;
11+
padding: 0;
12+
box-sizing: border-box;
13+
}
14+
15+
body {
16+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
17+
background: black;
18+
min-height: 100vh;
19+
display: flex;
20+
align-items: center;
21+
justify-content: center;
22+
}
23+
24+
.firewall-container {
25+
background: white;
26+
border-radius: 16px;
27+
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
28+
padding: 3rem;
29+
max-width: 400px;
30+
width: 90%;
31+
text-align: center;
32+
}
33+
34+
.title {
35+
font-size: 1.5rem;
36+
font-weight: 600;
37+
color: #dc2626;
38+
margin-bottom: 0.5rem;
39+
}
40+
41+
.message {
42+
color: #718096;
43+
margin-bottom: 2rem;
44+
line-height: 1.6;
45+
}
46+
47+
.error-icon {
48+
font-size: 3rem;
49+
color: #dc2626;
50+
margin-bottom: 1rem;
51+
}
52+
</style>
53+
</head>
54+
<body>
55+
<div class="firewall-container">
56+
<div class="error-icon">🚫</div>
57+
<h1 class="title">{{ config('firewall.message', 'Moox Firewall') }}</h1>
58+
<p class="message">{{ config('firewall.denied_message', 'Access denied. Please contact the IT department.') }}</p>
59+
</div>
60+
</body>
61+
</html>

src/FirewallServiceProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public function configurePackage(Package $package): void
1717
$package
1818
->name('firewall')
1919
->hasConfigFile()
20-
->hasViews('firewall')
20+
->hasViews('access-denied')
21+
->hasViews('backdoor')
2122
->hasTranslations()
2223
->hasMigrations()
2324
->hasCommands();

tests/Feature/ExampleTest.php

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/Feature/FirewallTest.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace Moox\Firewall\Tests\Feature;
4+
5+
use Illuminate\Foundation\Testing\RefreshDatabase;
6+
use Illuminate\Foundation\Testing\TestCase;
7+
8+
class FirewallTest extends TestCase
9+
{
10+
use RefreshDatabase;
11+
12+
protected function setUp(): void
13+
{
14+
parent::setUp();
15+
16+
config(['firewall.enabled' => true]);
17+
config(['firewall.backdoor' => true]);
18+
config(['firewall.backdoor_token' => 'test-token']);
19+
}
20+
21+
public function test_firewall_blocks_access_when_enabled()
22+
{
23+
config(['firewall.enabled' => true]);
24+
config(['firewall.backdoor' => false]);
25+
26+
$response = $this->get('/');
27+
28+
$response->assertStatus(200);
29+
$response->assertSee('Access denied');
30+
}
31+
32+
public function test_firewall_allows_access_when_disabled()
33+
{
34+
config(['firewall.enabled' => false]);
35+
36+
$response = $this->get('/');
37+
38+
$response->assertStatus(200);
39+
$response->assertDontSee('Access denied');
40+
}
41+
42+
public function test_firewall_allows_whitelisted_ips()
43+
{
44+
config(['firewall.whitelist' => ['127.0.0.1']]);
45+
46+
$response = $this->get('/');
47+
48+
$response->assertStatus(200);
49+
$response->assertDontSee('Access denied');
50+
}
51+
52+
public function test_firewall_excludes_specified_routes()
53+
{
54+
config(['firewall.exclude' => ['api/*']]);
55+
56+
$response = $this->get('/api/test');
57+
58+
$response->assertStatus(200);
59+
$response->assertDontSee('Access denied');
60+
}
61+
62+
public function test_backdoor_authentication_with_valid_token()
63+
{
64+
config(['firewall.backdoor_url' => '/backdoor']);
65+
66+
$response = $this->get('/backdoor?backdoor_token=test-token');
67+
68+
$response->assertStatus(302);
69+
$response->assertRedirect('/');
70+
}
71+
72+
public function test_backdoor_authentication_with_invalid_token()
73+
{
74+
config(['firewall.backdoor_url' => '/backdoor']);
75+
76+
$response = $this->get('/backdoor?backdoor_token=wrong-token');
77+
78+
$response->assertStatus(200);
79+
$response->assertSee('Invalid token');
80+
}
81+
82+
public function test_access_denied_on_non_backdoor_url()
83+
{
84+
config(['firewall.backdoor_url' => '/backdoor']);
85+
86+
$response = $this->get('/some-other-page');
87+
88+
$response->assertStatus(200);
89+
$response->assertSee('Access denied');
90+
}
91+
}

tests/TestCase.php

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,44 @@
44

55
use Illuminate\Database\Eloquent\Factories\Factory;
66
use Moox\Firewall\FirewallServiceProvider;
7-
use Orchestra\Testbench\TestCase as Orchestra;
7+
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
8+
use Illuminate\Foundation\Application;
9+
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
10+
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
11+
use Illuminate\Foundation\Bootstrap\HandleExceptions;
12+
use Illuminate\Foundation\Bootstrap\RegisterFacades;
13+
use Illuminate\Foundation\Bootstrap\SetRequestForConsole;
14+
use Illuminate\Foundation\Bootstrap\RegisterProviders;
15+
use Illuminate\Foundation\Bootstrap\BootProviders;
816

9-
class TestCase extends Orchestra
17+
class TestCase extends BaseTestCase
1018
{
19+
public function createApplication()
20+
{
21+
$app = new Application(
22+
realpath(__DIR__.'/../../../')
23+
);
24+
25+
$app->singleton(
26+
\Illuminate\Contracts\Http\Kernel::class,
27+
\App\Http\Kernel::class
28+
);
29+
30+
$app->singleton(
31+
\Illuminate\Contracts\Console\Kernel::class,
32+
\App\Console\Kernel::class
33+
);
34+
35+
$app->singleton(
36+
\Illuminate\Contracts\Debug\ExceptionHandler::class,
37+
\App\Exceptions\Handler::class
38+
);
39+
40+
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
41+
42+
return $app;
43+
}
44+
1145
protected function setUp(): void
1246
{
1347
parent::setUp();

tests/Unit/ExampleTest.php

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
namespace Moox\Firewall\Tests\Unit;
4+
5+
use Illuminate\Foundation\Testing\TestCase;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Routing\Events\RouteMatched;
8+
use Illuminate\Support\Facades\Config;
9+
use Illuminate\Support\Facades\View;
10+
use Moox\Firewall\Listeners\FirewallListener;
11+
12+
class FirewallListenerTest extends TestCase
13+
{
14+
protected FirewallListener $listener;
15+
16+
protected function setUp(): void
17+
{
18+
parent::setUp();
19+
20+
$this->listener = new FirewallListener;
21+
22+
Config::set('firewall.enabled', true);
23+
Config::set('firewall.backdoor', true);
24+
Config::set('firewall.backdoor_token', 'test-token');
25+
}
26+
27+
public function test_firewall_disabled_returns_early()
28+
{
29+
Config::set('firewall.enabled', false);
30+
31+
$request = Request::create('/');
32+
$event = new RouteMatched($request, $request->route());
33+
34+
$this->listener->handle($event);
35+
36+
$this->assertTrue(true);
37+
}
38+
39+
public function test_whitelisted_ip_returns_early()
40+
{
41+
Config::set('firewall.whitelist', ['127.0.0.1']);
42+
43+
$request = Request::create('/');
44+
$event = new RouteMatched($request, $request->route());
45+
46+
$this->listener->handle($event);
47+
48+
$this->assertTrue(true);
49+
}
50+
51+
public function test_excluded_route_returns_early()
52+
{
53+
Config::set('firewall.exclude', ['api/*']);
54+
55+
$request = Request::create('/api/test');
56+
$event = new RouteMatched($request, $request->route());
57+
58+
$this->listener->handle($event);
59+
60+
$this->assertTrue(true);
61+
}
62+
63+
public function test_backdoor_disabled_shows_access_denied()
64+
{
65+
Config::set('firewall.backdoor', false);
66+
67+
$request = Request::create('/');
68+
$event = new RouteMatched($request, $request->route());
69+
70+
View::shouldReceive('make')
71+
->with('firewall::access-denied')
72+
->andReturnSelf();
73+
View::shouldReceive('render')
74+
->andReturn('Access denied');
75+
76+
$this->expectOutputString('Access denied');
77+
78+
$this->listener->handle($event);
79+
}
80+
81+
public function test_backdoor_url_restriction()
82+
{
83+
Config::set('firewall.backdoor_url', '/backdoor');
84+
85+
$request = Request::create('/some-other-page');
86+
$event = new RouteMatched($request, $request->route());
87+
88+
View::shouldReceive('make')
89+
->with('firewall::access-denied')
90+
->andReturnSelf();
91+
View::shouldReceive('render')
92+
->andReturn('Access denied');
93+
94+
$this->expectOutputString('Access denied');
95+
96+
$this->listener->handle($event);
97+
}
98+
99+
public function test_valid_token_authenticates_user()
100+
{
101+
Config::set('firewall.backdoor_url', '/backdoor');
102+
103+
$request = Request::create('/backdoor?backdoor_token=test-token');
104+
$event = new RouteMatched($request, $request->route());
105+
106+
$this->listener->handle($event);
107+
108+
$this->assertTrue(true);
109+
}
110+
111+
public function test_invalid_token_shows_error()
112+
{
113+
Config::set('firewall.backdoor_url', '/backdoor');
114+
115+
$request = Request::create('/backdoor?backdoor_token=wrong-token');
116+
$event = new RouteMatched($request, $request->route());
117+
118+
View::shouldReceive('make')
119+
->with('firewall::backdoor', ['firewall_error' => null])
120+
->andReturnSelf();
121+
View::shouldReceive('render')
122+
->andReturn('Backdoor form');
123+
124+
$this->expectOutputString('Backdoor form');
125+
126+
$this->listener->handle($event);
127+
}
128+
}

0 commit comments

Comments
 (0)