172 lines
7.0 KiB
PHP
Executable File
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;
|
|
}
|