117 lines
4.5 KiB
PHP
117 lines
4.5 KiB
PHP
<?php
|
|
|
|
use App\Models\User;
|
|
|
|
// operator()/admin() helpers live in tests/Pest.php.
|
|
|
|
it('serves the console on any host when ADMIN_HOSTS is empty (default)', function () {
|
|
config()->set('admin_access.hosts', []);
|
|
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://app.dev.clupilot.com/admin')
|
|
->assertOk();
|
|
});
|
|
|
|
it('404s the console on a hostname that is not allowed', function () {
|
|
config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
|
|
|
|
// A PUBLIC hostname must not even hint that a console exists here.
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://app.dev.clupilot.com/admin')
|
|
->assertNotFound();
|
|
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://www.dev.clupilot.com/admin/hosts')
|
|
->assertNotFound();
|
|
});
|
|
|
|
it('serves the console on an allowed hostname', function () {
|
|
config()->set('admin_access.hosts', ['admin.dev.clupilot.com', '10.10.90.185']);
|
|
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://admin.dev.clupilot.com/admin')
|
|
->assertOk();
|
|
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://10.10.90.185/admin')
|
|
->assertOk();
|
|
});
|
|
|
|
it('matches configured hostnames case-insensitively', function () {
|
|
// DNS is case-insensitive and getHost() lowercases, so ADMIN_HOSTS with any
|
|
// capitals must still match — otherwise a typo silently locks operators out.
|
|
config()->set('admin_access.hosts', ['Admin.Dev.CluPilot.COM']);
|
|
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://admin.dev.clupilot.com/admin')
|
|
->assertOk();
|
|
|
|
// …and the restriction still bites on everything else.
|
|
$this->actingAs(operator('Owner'), 'operator')
|
|
->get('http://www.dev.clupilot.com/admin')
|
|
->assertNotFound();
|
|
});
|
|
|
|
it('404s before revealing a login redirect to guests on a public host', function () {
|
|
config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
|
|
|
|
// Not a redirect to /login — that would confirm the console's existence.
|
|
$this->get('http://www.dev.clupilot.com/admin')->assertNotFound();
|
|
});
|
|
|
|
it('blocks admin Livewire actions posted through a public hostname', function () {
|
|
// Admin actions go to /livewire/update, which a path-based guard would skip.
|
|
// Livewire must re-apply the host restriction from the component's route.
|
|
config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
|
|
$owner = operator('Owner');
|
|
|
|
// Render the real page on an ALLOWED host so Livewire records the admin
|
|
// route's middleware on the snapshot (Livewire::test() skips HTTP routing
|
|
// and would not, which would make this test pass for the wrong reason).
|
|
$html = $this->actingAs($owner, 'operator')
|
|
->get('http://admin.dev.clupilot.com/admin/datacenters')
|
|
->assertOk()
|
|
->getContent();
|
|
|
|
expect($html)->toMatch('/wire:snapshot=/');
|
|
preg_match('/wire:snapshot="([^"]+)"/', $html, $m);
|
|
$snapshot = html_entity_decode($m[1], ENT_QUOTES);
|
|
|
|
$payload = fn () => [
|
|
'_token' => csrf_token(),
|
|
'components' => [[
|
|
'snapshot' => $snapshot,
|
|
'updates' => [],
|
|
'calls' => [['path' => '', 'method' => 'save', 'params' => []]],
|
|
]],
|
|
];
|
|
|
|
// Replayed against a PUBLIC hostname → must not execute.
|
|
$this->actingAs($owner, 'operator')
|
|
->post('http://www.dev.clupilot.com/livewire/update', $payload())
|
|
->assertNotFound();
|
|
|
|
// Positive control: the very same payload works on the allowed host, so the
|
|
// 404 above is the restriction — not a malformed request.
|
|
$this->actingAs($owner, 'operator')
|
|
->post('http://admin.dev.clupilot.com/livewire/update', $payload())
|
|
->assertOk();
|
|
});
|
|
|
|
it('registers the host restriction as Livewire-persistent middleware', function () {
|
|
// Guards the wiring above: without this, /livewire/update bypasses ADMIN_HOSTS.
|
|
$persistent = (new ReflectionClass(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class))
|
|
->getProperty('persistentMiddleware');
|
|
|
|
expect($persistent->getValue(app(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class)))
|
|
->toContain(\App\Http\Middleware\RestrictAdminHost::class);
|
|
});
|
|
|
|
it('keeps the customer portal reachable on public hosts', function () {
|
|
config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
|
|
$user = User::factory()->create();
|
|
|
|
$this->actingAs($user)->get('http://app.dev.clupilot.com/dashboard')->assertOk();
|
|
$this->get('http://www.dev.clupilot.com/')->assertOk();
|
|
});
|