Files
wevads-platform/scripts/api_cloudflare-harvester.php
2026-02-26 04:53:11 +01:00

172 lines
7.0 KiB
PHP
Executable File

<?php
/**
* CLOUDFLARE DOMAIN HARVESTER
* Scans all CF accounts, harvests zones/domains, stores in DB
* Uses CF API v4: https://api.cloudflare.com/client/v4/
*/
require_once("/opt/wevads/config/credentials.php");
header('Content-Type: application/json');
$db = pg_connect("host=localhost dbname=adx_system user=admin password=".WEVADS_DB_PASS);
pg_query($db,"SET search_path TO admin");
$action = $_GET['action'] ?? $_POST['action'] ?? 'status';
function cf_api($endpoint, $email, $key, $method='GET', $data=null) {
$ch = curl_init("https://api.cloudflare.com/client/v4/$endpoint");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
"X-Auth-Email: $email",
"X-Auth-Key: $key",
"Content-Type: application/json"
]
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ['code' => $code, 'data' => json_decode($resp, true)];
}
switch($action) {
case 'harvest':
// Scan all CF accounts with valid API keys
$accounts = pg_fetch_all(pg_query($db,
"SELECT id, email, api_key, cf_account_id FROM cloudflare_accounts
WHERE api_key IS NOT NULL AND api_key != '' AND status='active'
ORDER BY id"));
if (!$accounts) { echo json_encode(['error' => 'No active CF accounts with API keys']); break; }
$total_domains = 0;
$results = [];
foreach ($accounts as $acc) {
$page = 1;
$account_domains = [];
do {
$resp = cf_api("zones?page=$page&per_page=50&status=active", $acc['email'], $acc['api_key']);
if ($resp['code'] != 200 || !$resp['data']['success']) {
$results[] = [
'account_id' => $acc['id'],
'email' => $acc['email'],
'error' => $resp['data']['errors'][0]['message'] ?? 'API error ' . $resp['code']
];
break;
}
$zones = $resp['data']['result'] ?? [];
foreach ($zones as $zone) {
$domain = pg_escape_string($db, $zone['name']);
$zone_id = pg_escape_string($db, $zone['id']);
$status = pg_escape_string($db, $zone['status']);
$ns = json_encode($zone['name_servers'] ?? []);
// Save to cloudflare_domains
pg_query($db, "INSERT INTO cloudflare_domains(account_id, domain, zone_id, status, created_at)
VALUES({$acc['id']}, '$domain', '$zone_id', '$status', NOW())
ON CONFLICT DO NOTHING");
// Save to cloudflare_zones
pg_query($db, "INSERT INTO cloudflare_zones(account_id, zone_id, domain, status, name_servers, created_at)
VALUES({$acc['id']}, '$zone_id', '$domain', '$status', '$ns', NOW())
ON CONFLICT DO NOTHING");
// Also add to domains_pool if not exists
pg_query($db, "INSERT INTO domains_pool(domain, provider, status, created_at)
VALUES('$domain', 'cloudflare', '$status', NOW())
ON CONFLICT DO NOTHING");
$account_domains[] = $domain;
$total_domains++;
}
$total_pages = $resp['data']['result_info']['total_pages'] ?? 1;
$page++;
} while ($page <= $total_pages);
// Update account domain count
$cnt = count($account_domains);
pg_query($db, "UPDATE cloudflare_accounts SET domains_count=$cnt, last_api_check=NOW() WHERE id={$acc['id']}");
$results[] = [
'account_id' => $acc['id'],
'email' => $acc['email'],
'domains_found' => $cnt,
'domains' => array_slice($account_domains, 0, 10) // First 10 only
];
}
echo json_encode([
'status' => 'success',
'accounts_scanned' => count($accounts),
'total_domains_harvested' => $total_domains,
'results' => $results
]);
break;
case 'dns_scan':
// Scan DNS records for harvested domains
$account_id = $_GET['account_id'] ?? null;
$where = $account_id ? "AND account_id=$account_id" : "";
$domains = pg_fetch_all(pg_query($db,
"SELECT cd.domain, cd.zone_id, cd.account_id, ca.email, ca.api_key
FROM cloudflare_domains cd
JOIN cloudflare_accounts ca ON ca.id = cd.account_id
WHERE ca.api_key IS NOT NULL $where
ORDER BY cd.id LIMIT 50"));
if (!$domains) { echo json_encode(['error' => 'No domains to scan']); break; }
$scanned = [];
foreach ($domains as $d) {
$resp = cf_api("zones/{$d['zone_id']}/dns_records?per_page=100", $d['email'], $d['api_key']);
if ($resp['code'] == 200 && $resp['data']['success']) {
$records = $resp['data']['result'] ?? [];
foreach ($records as $rec) {
$name = pg_escape_string($db, $rec['name']);
$type = pg_escape_string($db, $rec['type']);
$content = pg_escape_string($db, $rec['content']);
$ttl = (int)$rec['ttl'];
$prio = isset($rec['priority']) ? (int)$rec['priority'] : 0;
pg_query($db, "INSERT INTO dns_records(domain, record_type, name, value, ttl, priority, provider, status)
VALUES('{$d['domain']}', '$type', '$name', '$content', $ttl, $prio, 'cloudflare', 'active')
ON CONFLICT DO NOTHING");
}
$scanned[] = ['domain' => $d['domain'], 'records' => count($records)];
}
}
echo json_encode(['status' => 'success', 'scanned' => count($scanned), 'details' => $scanned]);
break;
case 'status':
$stats = pg_fetch_assoc(pg_query($db, "
SELECT
(SELECT COUNT(*) FROM cloudflare_accounts WHERE api_key IS NOT NULL AND status='active') as active_accounts,
(SELECT COUNT(*) FROM cloudflare_domains) as total_domains,
(SELECT COUNT(DISTINCT account_id) FROM cloudflare_domains) as accounts_with_domains,
(SELECT COUNT(*) FROM cloudflare_zones) as total_zones,
(SELECT COUNT(*) FROM dns_records WHERE provider='cloudflare') as dns_records
"));
echo json_encode(['status' => 'success', 'stats' => $stats]);
break;
case 'list_domains':
$r = pg_query($db, "SELECT cd.domain, cd.status, ca.email as account_email, cd.account_id
FROM cloudflare_domains cd JOIN cloudflare_accounts ca ON ca.id=cd.account_id
ORDER BY cd.account_id, cd.domain");
$domains = [];
while ($row = pg_fetch_assoc($r)) $domains[] = $row;
echo json_encode(['status' => 'success', 'count' => count($domains), 'domains' => $domains]);
break;
}