Files
Atomcms-edit/app/Filament/Pages/VPN/VPNManagement.php
T
2026-05-09 17:32:17 +02:00

440 lines
19 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace App\Filament\Pages\VPN;
use App\Models\Miscellaneous\WebsiteBlockedCountry;
use App\Models\Miscellaneous\WebsiteIpBlacklist;
use App\Models\Miscellaneous\WebsiteIpWhitelist;
use App\Models\Miscellaneous\WebsiteSetting;
use App\Services\IpLookupService;
use Filament\Actions\Action;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
final class VPNManagement extends Page implements HasForms
{
use InteractsWithForms;
#[\Override]
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-shield-exclamation';
#[\Override]
protected static string|\UnitEnum|null $navigationGroup = 'Website';
#[\Override]
protected static ?string $navigationLabel = 'VPN Beheer';
#[\Override]
protected static ?string $title = 'VPN & IP Beheer';
#[\Override]
protected string $view = 'filament.pages.vpn.vpn-management';
/** @var array<string, mixed> */
public array $data = [];
public $blockedCountries;
public $whitelistedIps;
public $blacklistedIps;
public $blocklistStats;
public function mount(): void
{
$this->fillForm();
$this->loadData();
}
protected function loadData(): void
{
$this->blockedCountries = WebsiteBlockedCountry::orderBy('country_name')->get();
$this->whitelistedIps = WebsiteIpWhitelist::orderBy('created_at', 'desc')->get();
$this->blacklistedIps = WebsiteIpBlacklist::orderBy('created_at', 'desc')->get();
$ipService = new IpLookupService('');
$this->blocklistStats = $ipService->getBlocklistStats();
}
protected function fillForm(): void
{
$this->data = [
'vpn_block_enabled' => $this->getSettingBool('vpn_block_enabled'),
'country_block_enabled' => $this->getSettingBool('country_block_enabled'),
'block_vpn' => $this->getSettingBool('block_vpn'),
'block_tor' => $this->getSettingBool('block_tor'),
'block_malicious' => $this->getSettingBool('block_malicious'),
];
}
protected function getSetting(string $key, string $default = ''): string
{
return WebsiteSetting::where('key', $key)->first()?->value ?? $default;
}
protected function getSettingBool(string $key): bool
{
return WebsiteSetting::where('key', $key)->first()?->value === '1';
}
public function form(Schema $schema): Schema
{
return $schema
->components([
Tabs::make('VPN Beheer')
->tabs([
Tab::make('Instellingen')
->icon('heroicon-o-cog-6-tooth')
->schema([
Section::make('Gratis Blokkering (Onbeperkt)')
->description('Gebruikt gratis community blocklists - geen API keys nodig')
->schema([
Toggle::make('data.vpn_block_enabled')
->label('VPN/TOR/Proxy Blokker Actief')
->helperText('Blokkeer VPN, TOR exit nodes, proxies en bekende malicious IPs'),
]),
Section::make('Wat blokkeren?')
->schema([
Toggle::make('data.block_vpn')
->label('VPN & Proxies')
->helperText('FireHol blocklist'),
Toggle::make('data.block_tor')
->label('TOR Exit Nodes')
->helperText('Alle bekende TOR exit nodes'),
Toggle::make('data.block_malicious')
->label('Malicious IPs')
->helperText('Bekende kwaadwillende IPs uit community databases'),
]),
Section::make('Land Blokkering')
->schema([
Toggle::make('data.country_block_enabled')
->label('Land Blokkering Actief')
->helperText('Sta alleen bezoekers uit toegestane landen toe'),
]),
]),
Tab::make('Geblokkeerde Landen')
->icon('heroicon-o-globe-alt')
->schema([
Section::make('Land toevoegen')
->schema([
Select::make('country_to_block')
->label('Selecteer Land')
->options($this->getCountryOptions())
->searchable()
->placeholder('Kies een land'),
Action::make('addCountry')
->label('Blokkeer Land')
->action('addBlockedCountry')
->color('danger'),
]),
]),
Tab::make('Whitelist')
->icon('heroicon-o-check-circle')
->schema([
Section::make('Whitelist toevoegen')
->schema([
TextInput::make('whitelist_ip')
->label('IP Adres')
->placeholder('192.168.1.1'),
TextInput::make('whitelist_asn')
->label('ASN')
->placeholder('AS15169'),
Select::make('whitelist_country')
->label('Land')
->options($this->getCountryOptions())
->searchable(),
Action::make('addToWhitelist')
->label('Toevoegen')
->action('addToWhitelist')
->color('success'),
]),
]),
Tab::make('Blacklist')
->icon('heroicon-o-x-circle')
->schema([
Section::make('Blacklist toevoegen')
->schema([
TextInput::make('blacklist_ip')
->label('IP Adres')
->placeholder('192.168.1.1'),
TextInput::make('blacklist_asn')
->label('ASN')
->placeholder('AS15169'),
Select::make('blacklist_country')
->label('Land')
->options($this->getCountryOptions())
->searchable(),
Action::make('addToBlacklist')
->label('Toevoegen')
->action('addToBlacklist')
->color('danger'),
]),
]),
Tab::make('IP Lookup')
->icon('heroicon-o-magnifying-glass')
->schema([
Section::make('IP Opzoeken')
->schema([
TextInput::make('lookup_ip')
->label('IP Adres')
->placeholder('Voer IP in om te controleren'),
Action::make('lookupIp')
->label('Controleer')
->action('lookupIp')
->color('info'),
]),
]),
Tab::make('Blocklist Stats')
->icon('heroicon-o-chart-bar')
->schema([
Section::make('Huidige Blocklists')
->description('Deze lijsten worden automatisch gedownload en dagelijks ververst')
->schema([
TextColumn::make('type')->label('Type'),
TextColumn::make('count')->label('Aantal IPs'),
]),
]),
]),
])
->statePath('data');
}
protected function getCountryOptions(): array
{
return [
'AD' => 'Andorra', 'AE' => 'United Arab Emirates', 'AF' => 'Afghanistan',
'AG' => 'Antigua and Barbuda', 'AI' => 'Anguilla', 'AL' => 'Albania',
'AM' => 'Armenia', 'AO' => 'Angola', 'AR' => 'Argentina',
'AT' => 'Austria', 'AU' => 'Australia', 'AW' => 'Aruba',
'AZ' => 'Azerbaijan', 'BA' => 'Bosnia and Herzegovina', 'BB' => 'Barbados',
'BD' => 'Bangladesh', 'BE' => 'Belgium', 'BG' => 'Bulgaria',
'BH' => 'Bahrain', 'BI' => 'Burundi', 'BJ' => 'Benin',
'BM' => 'Bermuda', 'BN' => 'Brunei', 'BO' => 'Bolivia',
'BR' => 'Brazil', 'BS' => 'Bahamas', 'BT' => 'Bhutan',
'BW' => 'Botswana', 'BY' => 'Belarus', 'BZ' => 'Belize',
'CA' => 'Canada', 'CH' => 'Switzerland', 'CL' => 'Chile',
'CN' => 'China', 'CO' => 'Colombia', 'CR' => 'Costa Rica',
'CU' => 'Cuba', 'CY' => 'Cyprus', 'CZ' => 'Czechia',
'DE' => 'Germany', 'DK' => 'Denmark', 'DO' => 'Dominican Republic',
'DZ' => 'Algeria', 'EC' => 'Ecuador', 'EE' => 'Estonia',
'EG' => 'Egypt', 'ES' => 'Spain', 'ET' => 'Ethiopia',
'FI' => 'Finland', 'FJ' => 'Fiji', 'FR' => 'France',
'GB' => 'United Kingdom', 'GD' => 'Grenada', 'GE' => 'Georgia',
'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GL' => 'Greenland',
'GM' => 'Gambia', 'GN' => 'Guinea', 'GR' => 'Greece',
'GT' => 'Guatemala', 'HK' => 'Hong Kong', 'HN' => 'Honduras',
'HR' => 'Croatia', 'HU' => 'Hungary', 'ID' => 'Indonesia',
'IE' => 'Ireland', 'IL' => 'Israel', 'IN' => 'India',
'IQ' => 'Iraq', 'IR' => 'Iran', 'IS' => 'Iceland',
'IT' => 'Italy', 'JM' => 'Jamaica', 'JO' => 'Jordan',
'JP' => 'Japan', 'KE' => 'Kenya', 'KH' => 'Cambodia',
'KR' => 'South Korea', 'KW' => 'Kuwait', 'KZ' => 'Kazakhstan',
'LA' => 'Laos', 'LB' => 'Lebanon', 'LK' => 'Sri Lanka',
'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'LV' => 'Latvia',
'MA' => 'Morocco', 'MC' => 'Monaco', 'MD' => 'Moldova',
'ME' => 'Montenegro', 'MG' => 'Madagascar', 'MK' => 'North Macedonia',
'MM' => 'Myanmar', 'MN' => 'Mongolia', 'MO' => 'Macao',
'MT' => 'Malta', 'MU' => 'Mauritius', 'MV' => 'Maldives',
'MX' => 'Mexico', 'MY' => 'Malaysia', 'MZ' => 'Mozambique',
'NA' => 'Namibia', 'NG' => 'Nigeria', 'NI' => 'Nicaragua',
'NL' => 'Netherlands', 'NO' => 'Norway', 'NP' => 'Nepal',
'NZ' => 'New Zealand', 'OM' => 'Oman', 'PA' => 'Panama',
'PE' => 'Peru', 'PH' => 'Philippines', 'PK' => 'Pakistan',
'PL' => 'Poland', 'PR' => 'Puerto Rico', 'PT' => 'Portugal',
'PY' => 'Paraguay', 'QA' => 'Qatar', 'RO' => 'Romania',
'RS' => 'Serbia', 'RU' => 'Russia', 'RW' => 'Rwanda',
'SA' => 'Saudi Arabia', 'SC' => 'Seychelles', 'SD' => 'Sudan',
'SE' => 'Sweden', 'SG' => 'Singapore', 'SI' => 'Slovenia',
'SK' => 'Slovakia', 'SN' => 'Senegal', 'SO' => 'Somalia',
'SR' => 'Suriname', 'SV' => 'El Salvador', 'SY' => 'Syria',
'TH' => 'Thailand', 'TJ' => 'Tajikistan', 'TN' => 'Tunisia',
'TR' => 'Turkey', 'TT' => 'Trinidad and Tobago', 'TW' => 'Taiwan',
'TZ' => 'Tanzania', 'UA' => 'Ukraine', 'UG' => 'Uganda',
'US' => 'United States', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan',
'VE' => 'Venezuela', 'VN' => 'Vietnam', 'ZA' => 'South Africa',
'ZM' => 'Zambia', 'ZW' => 'Zimbabwe',
];
}
public function save(): void
{
$settings = [
'vpn_block_enabled' => $this->data['vpn_block_enabled'] ? '1' : '0',
'country_block_enabled' => $this->data['country_block_enabled'] ? '1' : '0',
'block_vpn' => $this->data['block_vpn'] ?? true ? '1' : '0',
'block_tor' => $this->data['block_tor'] ?? true ? '1' : '0',
'block_malicious' => $this->data['block_malicious'] ?? true ? '1' : '0',
];
foreach ($settings as $key => $value) {
WebsiteSetting::updateOrCreate(['key' => $key], ['value' => $value]);
}
Notification::make()->title(__('Saved'))->success()->send();
}
public function refreshBlocklists(): void
{
$ipService = new IpLookupService('');
$ipService->refreshBlocklists();
$this->loadData();
Notification::make()->title('Blocklists vernieuwd')->success()->send();
}
public function addBlockedCountry(): void
{
$countryCode = $this->data['country_to_block'] ?? null;
if (! $countryCode) {
Notification::make()->title('Selecteer een land')->danger()->send();
return;
}
if (WebsiteBlockedCountry::where('country_code', $countryCode)->exists()) {
Notification::make()->title('Land is al geblokkeerd')->warning()->send();
return;
}
$countries = $this->getCountryOptions();
$countryCode = (string) $countryCode;
WebsiteBlockedCountry::create([
'country_code' => $countryCode,
'country_name' => $countries[$countryCode] ?? $countryCode,
]);
$this->loadData();
Notification::make()->title('Land geblokkeerd')->success()->send();
}
public function removeBlockedCountry(int $id): void
{
WebsiteBlockedCountry::destroy($id);
$this->loadData();
Notification::make()->title('Verwijderd')->success()->send();
}
public function addToWhitelist(): void
{
$ip = $this->data['whitelist_ip'] ?? null;
$asn = $this->data['whitelist_asn'] ?? null;
$countryCode = $this->data['whitelist_country'] ?? null;
if (! $ip && ! $asn && ! $countryCode) {
Notification::make()->title('Voer IP, ASN of land in')->danger()->send();
return;
}
$countries = $this->getCountryOptions();
$countryCodeStr = (string) ($countryCode ?? '');
$countryName = $countryCode ? ($countries[$countryCodeStr] ?? null) : null;
WebsiteIpWhitelist::create([
'ip_address' => $ip ?? null,
'asn' => $asn ?? null,
'country_code' => $countryCodeStr,
'country_name' => $countryName,
'whitelist_asn' => ! empty($asn),
'whitelist_country' => ! empty($countryCode),
]);
$this->loadData();
Notification::make()->title('Toegevoegd aan whitelist')->success()->send();
}
public function addToBlacklist(): void
{
$ip = $this->data['blacklist_ip'] ?? null;
$asn = $this->data['blacklist_asn'] ?? null;
$countryCode = $this->data['blacklist_country'] ?? null;
if (! $ip && ! $asn && ! $countryCode) {
Notification::make()->title('Voer IP, ASN of land in')->danger()->send();
return;
}
$countries = $this->getCountryOptions();
$countryCodeStr = (string) ($countryCode ?? '');
$countryName = $countryCode ? ($countries[$countryCodeStr] ?? null) : null;
WebsiteIpBlacklist::create([
'ip_address' => $ip ?? null,
'asn' => $asn ?? null,
'country_code' => $countryCodeStr,
'country_name' => $countryName,
'blacklist_asn' => ! empty($asn),
'blacklist_country' => ! empty($countryCode),
]);
$this->loadData();
Notification::make()->title('Toegevoegd aan blacklist')->success()->send();
}
public function removeFromWhitelist(int $id): void
{
WebsiteIpWhitelist::destroy($id);
$this->loadData();
Notification::make()->title('Verwijderd')->success()->send();
}
public function removeFromBlacklist(int $id): void
{
WebsiteIpBlacklist::destroy($id);
$this->loadData();
Notification::make()->title('Verwijderd')->success()->send();
}
public function lookupIp(): void
{
$ip = $this->data['lookup_ip'] ?? null;
if (! $ip) {
Notification::make()->title('Voer een IP in')->danger()->send();
return;
}
$ipService = new IpLookupService('');
$countryInfo = $ipService->getCountryInfo($ip);
$threatInfo = $ipService->checkVpnProxyTor($ip);
$message = "IP: {$ip}\n\n";
if (! empty($countryInfo['country_name'])) {
$message .= "📍 {$countryInfo['country_name']} ({$countryInfo['country_code']})\n";
$message .= " {$countryInfo['city']} - {$countryInfo['isp']}\n\n";
}
$message .= "🚫 Blokkeren:\n";
$message .= ' VPN/Proxy: ' . ($threatInfo['is_vpn'] ? 'JA' : 'Nee') . "\n";
$message .= ' TOR: ' . ($threatInfo['is_tor'] ? 'JA' : 'Nee') . "\n";
$message .= ' Malicious: ' . ($threatInfo['is_malicious'] ? 'JA' : 'Nee') . "\n";
Notification::make()->title('Resultaat')->body($message)->success()->send();
}
#[\Override]
protected function getActions(): array
{
return [
Action::make('save')->label('Opslaan')->action('save')->color('primary'),
Action::make('refreshBlocklists')->label('Vernieuw Blocklists')->action('refreshBlocklists')->color('warning'),
];
}
}