83 lines
2.5 KiB
PHP
83 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Models\Concerns\HasUuid;
|
|
use App\Services\Security\HostFirewall;
|
|
use Database\Factories\SecurityBlockFactory;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
|
|
/**
|
|
* Eine Sperre gegen eine Adresse — an genau einem Subjekt, einer Instanz oder
|
|
* einem Host (nie beiden). Entsteht in `BlockAddress` auch dann, wenn
|
|
* `HostFirewall::block()` selbst scheitert: der Datensatz IST die Sperre, die
|
|
* Firewall-Menge ist nur ihr aktueller Abdruck (siehe HostFirewall).
|
|
*/
|
|
class SecurityBlock extends Model
|
|
{
|
|
/** @use HasFactory<SecurityBlockFactory> */
|
|
use HasFactory, HasUuid;
|
|
|
|
protected $fillable = [
|
|
'host_id', 'instance_id', 'ip', 'reason', 'attempts', 'strikes',
|
|
'blocked_at', 'expires_at', 'released_at', 'released_by_type', 'released_by_id',
|
|
];
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'attempts' => 'integer',
|
|
'strikes' => 'integer',
|
|
'blocked_at' => 'datetime',
|
|
'expires_at' => 'datetime',
|
|
'released_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
public function host(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Host::class);
|
|
}
|
|
|
|
public function instance(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Instance::class);
|
|
}
|
|
|
|
/** Wer vorzeitig aufgehoben hat — Operator oder Customer, wenn jemand. */
|
|
public function releasedBy(): MorphTo
|
|
{
|
|
return $this->morphTo();
|
|
}
|
|
|
|
/** Was gerade gilt: noch nicht aufgehoben und noch nicht abgelaufen. */
|
|
public function scopeActive(Builder $query): Builder
|
|
{
|
|
return $query->whereNull('released_at')->where('expires_at', '>', now());
|
|
}
|
|
|
|
/**
|
|
* Hebt die Sperre vorzeitig auf — am Datensatz UND, wenn das Subjekt einen
|
|
* erreichbaren Host hat, in dessen Firewall. `$by` ist null, wenn der
|
|
* Kernel sie ohnehin schon fallen ließ (Ablauf) und niemand sie manuell
|
|
* aufgehoben hat; sonst der Operator oder Customer, der den Knopf gedrückt
|
|
* hat (R23-Modal auf der aufrufenden Seite, nicht hier).
|
|
*/
|
|
public function release(?Model $by): void
|
|
{
|
|
$this->releasedBy()->associate($by);
|
|
$this->released_at = now();
|
|
$this->save();
|
|
|
|
$host = $this->host ?? $this->instance?->host;
|
|
|
|
if ($host !== null) {
|
|
app(HostFirewall::class)->release($host, $this->ip);
|
|
}
|
|
}
|
|
}
|