<?php
 namespace App\Services\Fraud\Checks; use App\Models\Order; use App\Models\OrderFraudCheck; use App\Models\Setting; use Illuminate\Support\Facades\Http; class IpReputationCheck extends BaseFraudCheck { protected int $priority = 20; public function getName(): string { return 'IP Reputation Check'; } public function getType(): string { return OrderFraudCheck::TYPE_IP_REPUTATION; } public function getDescription(): string { return 'Checks IP address reputation, VPN/Proxy detection, and geo-location'; } public function isEnabled(): bool { if (!empty($this->moduleConfig)) { return !empty($this->moduleConfig['ip_check_enabled']); } return (bool) Setting::getValue('fraud_ip_check_enabled', true); } public function check(Order $order): array { $ipAddress = $order->ip_address; if (!$ipAddress) { return $this->skipped('No IP address provided'); } if ($this->isPrivateIp($ipAddress)) { return $this->skipped('Private or localhost IP address'); } $reputationData = $this->checkIpReputation($ipAddress); $data = [ 'ip_address' => $ipAddress, 'is_vpn' => $reputationData['is_vpn'] ?? false, 'is_proxy' => $reputationData['is_proxy'] ?? false, 'is_tor' => $reputationData['is_tor'] ?? false, 'is_datacenter' => $reputationData['is_datacenter'] ?? false, 'country_code' => $reputationData['country_code'] ?? null, 'city' => $reputationData['city'] ?? null, 'risk_score' => $reputationData['risk_score'] ?? 0, 'reputation_service' => $reputationData['service'] ?? 'internal', ]; if (!empty($this->moduleConfig)) { $blockTor = !empty($this->moduleConfig['block_tor']); } else { $blockTor = (bool) Setting::getValue('fraud_block_tor', true); } if ($blockTor && ($reputationData['is_tor'] ?? false)) { return $this->failed( 95, 'Order placed from TOR exit node', $data ); } if (!empty($this->moduleConfig)) { $blockVpnProxy = !empty($this->moduleConfig['block_vpn_proxy']); } else { $blockVpnProxy = (bool) Setting::getValue('fraud_block_vpn_proxy', false); } if ($blockVpnProxy && ($reputationData['is_vpn'] ?? false)) { return $this->failed( 75, 'Order placed from VPN connection', $data ); } if ($blockVpnProxy && ($reputationData['is_proxy'] ?? false)) { return $this->failed( 70, 'Order placed from proxy server', $data ); } if (!$blockVpnProxy) { if ($reputationData['is_vpn'] ?? false) { return $this->warning( 40, 'Order placed from VPN connection (warning only)', $data ); } if ($reputationData['is_proxy'] ?? false) { return $this->warning( 35, 'Order placed from proxy server (warning only)', $data ); } } if (!$blockTor && ($reputationData['is_tor'] ?? false)) { return $this->warning( 60, 'Order placed from TOR exit node (warning only)', $data ); } if ($reputationData['is_datacenter'] ?? false) { return $this->warning( 30, 'Order placed from datacenter IP', $data ); } if (!empty($this->moduleConfig['high_risk_countries'])) { $highRiskCountries = array_map('trim', explode(',', $this->moduleConfig['high_risk_countries'])); $highRiskCountries = array_filter($highRiskCountries); } else { $highRiskCountries = []; } if (!empty($highRiskCountries) && in_array($reputationData['country_code'] ?? '', $highRiskCountries)) { return $this->warning( 40, 'Order from high-risk country: ' . $reputationData['country_code'], $data ); } $externalRiskScore = $reputationData['risk_score'] ?? 0; if ($externalRiskScore >= 80) { return $this->failed( $externalRiskScore, 'IP has high fraud risk score from reputation service', $data ); } elseif ($externalRiskScore >= 50) { return $this->warning( $externalRiskScore, 'IP has moderate fraud risk score from reputation service', $data ); } return $this->passed('IP reputation is clean', $data); } protected function isPrivateIp(string $ip): bool { $privateRanges = [ '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.0/8', ]; foreach ($privateRanges as $range) { if ($this->ipInRange($ip, $range)) { return true; } } return $ip === '::1' || $ip === 'localhost'; } protected function ipInRange(string $ip, string $range): bool { list($subnet, $bits) = explode('/', $range); $ip = ip2long($ip); $subnet = ip2long($subnet); $mask = -1 << (32 - $bits); $subnet &= $mask; return ($ip & $mask) == $subnet; } protected function checkIpReputation(string $ip): array { $internalCheck = $this->checkInternalDatabase($ip); if ($internalCheck) { return $internalCheck; } return [ 'service' => 'internal', 'is_vpn' => false, 'is_proxy' => false, 'is_tor' => false, 'is_datacenter' => false, 'risk_score' => 0, 'country_code' => null, 'city' => null, ]; } protected function checkInternalDatabase(string $ip): ?array { return null; } protected function checkExternalService(string $ip): array { return [ 'service' => 'none', 'is_vpn' => false, 'is_proxy' => false, 'is_tor' => false, 'is_datacenter' => false, 'risk_score' => 0, ]; } } 