This commit is contained in:
Halbe Bruno
2025-12-05 19:40:39 -03:00
commit f37bc712e6
4312 changed files with 359196 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
<?php
namespace App\Services;
class ASNService
{
public static function validateIP($ip, $asn)
{
// Remove 'AS' prefix if present for comparison
$targetAsn = ltrim(strtoupper($asn), 'AS');
// Use whois command
// This command queries Cymru's whois server which is reliable for IP to ASN mapping
// Format: whois -h whois.cymru.com " -v [IP]"
$command = sprintf('whois -h whois.cymru.com " -v %s"', escapeshellarg($ip));
// Use proc_open to capture output and potential errors
$descriptorspec = [
0 => ["pipe", "r"], // stdin
1 => ["pipe", "w"], // stdout
2 => ["pipe", "w"] // stderr
];
$process = proc_open($command, $descriptorspec, $pipes);
if (is_resource($process)) {
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
if ($return_value !== 0 || empty($output)) {
// Whois command failed, try HTTP API fallback
// Using ip-api.com (free, no key required for limited use)
// Format: http://ip-api.com/json/{ip}?fields=status,message,as
$apiUrl = "http://ip-api.com/json/" . $ip . "?fields=status,message,as";
$context = stream_context_create(['http' => ['timeout' => 3]]);
$apiResponse = @file_get_contents($apiUrl, false, $context);
if ($apiResponse !== FALSE) {
$data = json_decode($apiResponse, true);
if (isset($data['status']) && $data['status'] === 'success' && isset($data['as'])) {
// Format example: "AS15169 Google LLC"
// Extract AS number
if (preg_match('/AS(\d+)/', $data['as'], $matches)) {
$foundAsn = $matches[1];
return $foundAsn === $targetAsn;
}
}
}
// If both fail, strictly return false as requested to prevent invalid registrations
return false;
}
} else {
return false;
}
// Parse output
// Output example:
// AS | IP | BGP Prefix | CC | Registry | Allocated | AS Name
// 15169 | 8.8.8.8 | 8.8.8.0/24 | US | arin | 2000-03-30 | GOOGLE, US
$lines = explode("\n", trim($output));
foreach ($lines as $line) {
if (strpos($line, 'AS') !== false && strpos($line, 'IP') !== false) {
continue;
}
$parts = explode('|', $line);
if (count($parts) >= 1) {
$foundAsn = trim($parts[0]);
if ($foundAsn === $targetAsn) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Services;
use App\Config\Database;
use PDO;
class OrderProcessor
{
public function process($orderId, $type, $csvPath)
{
$conn = Database::getInstance()->getConnection();
if (!file_exists($csvPath)) {
throw new \Exception("Arquivo CSV não encontrado.");
}
$handle = fopen($csvPath, "r");
if ($handle === FALSE) {
throw new \Exception("Erro ao abrir arquivo CSV.");
}
$domains = [];
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$raw = trim($data[0]);
if (empty($raw))
continue;
$domain = $this->cleanDomain($raw);
if ($domain) {
$domains[] = $domain;
}
}
fclose($handle);
$domains = array_unique($domains); // Remove duplicates in batch
$conn->beginTransaction();
try {
$stmtCheck = $conn->prepare("SELECT id FROM domains WHERE name = :name");
$stmtInsertDomain = $conn->prepare("INSERT INTO domains (name, status, last_order_id) VALUES (:name, :status, :order_id)");
$stmtUpdateDomain = $conn->prepare("UPDATE domains SET status = :status, last_order_id = :order_id WHERE id = :id");
$stmtInsertItem = $conn->prepare("INSERT INTO order_items (order_id, domain_id, action) VALUES (:order_id, :domain_id, :action)");
$status = ($type === 'block') ? 'blocked' : 'unblocked';
foreach ($domains as $domainName) {
// Check if exists
$stmtCheck->execute(['name' => $domainName]);
$existing = $stmtCheck->fetch();
$domainId = null;
if ($existing) {
$domainId = $existing['id'];
$stmtUpdateDomain->execute([
'status' => $status,
'order_id' => $orderId,
'id' => $domainId
]);
} else {
$stmtInsertDomain->execute([
'name' => $domainName,
'status' => $status,
'order_id' => $orderId
]);
$domainId = $conn->lastInsertId();
}
// Insert Item History
$stmtInsertItem->execute([
'order_id' => $orderId,
'domain_id' => $domainId,
'action' => $type
]);
}
$conn->commit();
return count($domains);
} catch (\Exception $e) {
$conn->rollBack();
throw $e;
}
}
private function cleanDomain($input)
{
// 1. Remove whitespace and common trailing punctuation
$input = trim($input);
$input = rtrim($input, ';,."\'');
// 2. Transliterate accents (e.g., domínio -> dominio)
// Using iconv to transliterate to ASCII
if (function_exists('iconv')) {
$input = iconv('UTF-8', 'ASCII//TRANSLIT', $input);
}
// 3. Handle Protocols and URLs
// If it doesn't have a protocol but looks like a URL path (e.g. domain.com/page), parse_url might fail or treat as path.
// We prepend http:// if missing to help parse_url, unless it's a mailto
if (stripos($input, 'mailto:') === 0) {
$input = str_ireplace('mailto:', '', $input);
}
if (strpos($input, '://') === false) {
$input = 'http://' . $input;
}
$parsed = parse_url($input);
if (!$parsed || !isset($parsed['host'])) {
return null;
}
$domain = $parsed['host'];
// 4. Remove 'www.' prefix (requested "www é um protocolo")
if (strpos($domain, 'www.') === 0) {
$domain = substr($domain, 4);
}
// 5. Lowercase
$domain = strtolower($domain);
// 6. Final Validation
// Must contain at least one dot (unless localhost, but for blocking usually FQDN)
// Must allow hyphens, dots, numbers, letters.
if (!preg_match('/^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?$/', $domain)) {
return null;
}
return $domain;
}
}