181 lines
5.4 KiB
PHP
181 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace Paymenter\Extensions\Others\Security\Services;
|
|
|
|
use Paymenter\Extensions\Others\Security\Models\BlockedIP;
|
|
use Paymenter\Extensions\Others\Security\Models\LoginAttempt;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class VPNDetectionService
|
|
{
|
|
public static function checkAndBlockVPN(string $ipAddress, string $email = null, string $action = 'login'): bool
|
|
{
|
|
$extension = app(\Paymenter\Extensions\Others\Security\Security::class);
|
|
$config = $extension->getConfig();
|
|
|
|
$blockVPNs = false;
|
|
foreach ($config as $setting) {
|
|
if ($setting['name'] === 'block_vpn_ips') {
|
|
$blockVPNs = $setting['default'] ?? false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$blockVPNs) {
|
|
return false;
|
|
}
|
|
|
|
$cacheKey = "vpn_check_{$ipAddress}";
|
|
$isVPN = Cache::get($cacheKey);
|
|
|
|
if ($isVPN === null) {
|
|
$isVPN = static::detectVPN($ipAddress);
|
|
Cache::put($cacheKey, $isVPN, now()->addHours(6));
|
|
}
|
|
|
|
if ($isVPN) {
|
|
LoginAttempt::recordAttempt(
|
|
$ipAddress,
|
|
$email,
|
|
false,
|
|
request()->userAgent(),
|
|
null,
|
|
"Blocked VPN/Proxy IP detected during {$action}"
|
|
);
|
|
|
|
BlockedIP::blockIP(
|
|
$ipAddress,
|
|
'Auto-blocked VPN/Proxy IP address',
|
|
null,
|
|
false,
|
|
now()->addDays(1),
|
|
'Detected as VPN/Proxy service'
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected static function detectVPN(string $ipAddress): bool
|
|
{
|
|
if (static::isPrivateIP($ipAddress)) {
|
|
return false;
|
|
}
|
|
|
|
if (static::isKnownVPNRange($ipAddress)) {
|
|
return true;
|
|
}
|
|
|
|
if (static::checkWithFreeAPI($ipAddress)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected static function isPrivateIP(string $ipAddress): bool
|
|
{
|
|
return !filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
|
|
}
|
|
|
|
protected static function isKnownVPNRange(string $ipAddress): bool
|
|
{
|
|
$knownVPNRanges = [
|
|
'185.220.', // Tor exit nodes
|
|
'199.87.154.', // NordVPN
|
|
'103.216.60.', // ExpressVPN
|
|
'146.70.', // Surfshark
|
|
'91.219.', // CyberGhost
|
|
'185.159.', // ProtonVPN
|
|
'104.244.', // Private Internet Access
|
|
'149.154.', // Windscribe
|
|
'193.148.', // IPVanish
|
|
'185.246.', // Hide.me
|
|
];
|
|
|
|
foreach ($knownVPNRanges as $range) {
|
|
if (str_starts_with($ipAddress, $range)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected static function checkWithFreeAPI(string $ipAddress): bool
|
|
{
|
|
try {
|
|
$response = Http::timeout(5)->get("http://ip-api.com/json/{$ipAddress}", [
|
|
'fields' => 'proxy,hosting,query'
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
if (isset($data['proxy']) && $data['proxy']) {
|
|
return true;
|
|
}
|
|
if (isset($data['hosting']) && $data['hosting']) {
|
|
return true;
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::warning('VPN detection API failed', ['ip' => $ipAddress, 'error' => $e->getMessage()]);
|
|
}
|
|
|
|
try {
|
|
$response = Http::timeout(5)->get("https://vpnapi.io/api/{$ipAddress}", [
|
|
'key' => 'free'
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
if (isset($data['security']['vpn']) && $data['security']['vpn']) {
|
|
return true;
|
|
}
|
|
if (isset($data['security']['proxy']) && $data['security']['proxy']) {
|
|
return true;
|
|
}
|
|
if (isset($data['security']['tor']) && $data['security']['tor']) {
|
|
return true;
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::warning('VPN detection API failed', ['ip' => $ipAddress, 'error' => $e->getMessage()]);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static function isVPNBlocked(string $ipAddress): bool
|
|
{
|
|
$extension = app(\Paymenter\Extensions\Others\Security\Security::class);
|
|
$config = $extension->getConfig();
|
|
|
|
$blockVPNs = false;
|
|
foreach ($config as $setting) {
|
|
if ($setting['name'] === 'block_vpn_ips') {
|
|
$blockVPNs = $setting['default'] ?? false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$blockVPNs) {
|
|
return false;
|
|
}
|
|
|
|
$cacheKey = "vpn_check_{$ipAddress}";
|
|
$isVPN = Cache::get($cacheKey);
|
|
|
|
if ($isVPN === null) {
|
|
$isVPN = static::detectVPN($ipAddress);
|
|
Cache::put($cacheKey, $isVPN, now()->addHours(6));
|
|
}
|
|
|
|
return $isVPN;
|
|
}
|
|
}
|