94 lines
2.9 KiB
PHP
94 lines
2.9 KiB
PHP
<?php
|
|
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Mattitja\BadIpBlocker\BadIpStore;
|
|
|
|
beforeEach(fn () => $this->store = app(BadIpStore::class));
|
|
|
|
afterEach(fn () => CarbonImmutable::setTestNow());
|
|
|
|
it('starts empty when no file exists', function () {
|
|
expect($this->store->all())->toBe([])
|
|
->and($this->store->isBlocked('203.0.113.10'))->toBeFalse();
|
|
});
|
|
|
|
it('blocks and unblocks an ip', function () {
|
|
$this->store->block('203.0.113.10', 'test');
|
|
|
|
expect($this->store->isBlocked('203.0.113.10'))->toBeTrue()
|
|
->and($this->store->all()['203.0.113.10']['reason'])->toBe('test');
|
|
|
|
expect($this->store->unblock('203.0.113.10'))->toBeTrue()
|
|
->and($this->store->unblock('203.0.113.10'))->toBeFalse()
|
|
->and($this->store->isBlocked('203.0.113.10'))->toBeFalse();
|
|
});
|
|
|
|
it('supports ipv6', function () {
|
|
$this->store->block('2001:db8::1');
|
|
|
|
expect($this->store->isBlocked('2001:db8::1'))->toBeTrue();
|
|
});
|
|
|
|
it('rejects invalid ips', function () {
|
|
$this->store->block('not-an-ip');
|
|
})->throws(InvalidArgumentException::class);
|
|
|
|
it('persists to the json file and is visible to other instances', function () {
|
|
$this->store->block('198.51.100.20');
|
|
|
|
$other = new BadIpStore($this->store->path());
|
|
|
|
expect($other->isBlocked('198.51.100.20'))->toBeTrue()
|
|
->and(json_decode(file_get_contents($this->store->path()), true)['ips'])->toHaveKey('198.51.100.20');
|
|
});
|
|
|
|
it('picks up changes made by another process', function () {
|
|
expect($this->store->isBlocked('192.0.2.30'))->toBeFalse();
|
|
|
|
(new BadIpStore($this->store->path()))->block('192.0.2.30');
|
|
|
|
expect($this->store->isBlocked('192.0.2.30'))->toBeTrue();
|
|
});
|
|
|
|
it('expires blocks with a ttl', function () {
|
|
CarbonImmutable::setTestNow('2026-11-11 20:00:00');
|
|
$this->store->block('203.0.113.10', null, 60);
|
|
|
|
expect($this->store->isBlocked('203.0.113.10'))->toBeTrue();
|
|
|
|
CarbonImmutable::setTestNow('2026-11-11 20:01:01');
|
|
|
|
expect($this->store->isBlocked('203.0.113.10'))->toBeFalse()
|
|
->and($this->store->all())->toBe([]);
|
|
});
|
|
|
|
it('prunes expired entries', function () {
|
|
CarbonImmutable::setTestNow('2026-11-11 20:00:00');
|
|
$this->store->block('203.0.113.10', null, 60);
|
|
$this->store->block('198.51.100.20');
|
|
|
|
CarbonImmutable::setTestNow('2026-11-11 21:00:00');
|
|
|
|
expect($this->store->prune())->toBe(1)
|
|
->and(array_keys($this->store->all()))->toBe(['198.51.100.20']);
|
|
});
|
|
|
|
it('clears all entries', function () {
|
|
$this->store->block('203.0.113.10');
|
|
$this->store->clear();
|
|
|
|
expect($this->store->all())->toBe([]);
|
|
});
|
|
|
|
it('treats a corrupt file as empty and logs a warning', function () {
|
|
Log::spy();
|
|
|
|
@mkdir(dirname($this->store->path()), 0755, true);
|
|
file_put_contents($this->store->path(), '{not json');
|
|
|
|
expect($this->store->all())->toBe([]);
|
|
|
|
Log::shouldHaveReceived('warning')->once();
|
|
});
|