506 lines
21 KiB
PHP
Executable File
506 lines
21 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* WEVAL Cloudflare Setup
|
|
* - Ajouter API keys aux comptes
|
|
* - Rapatrier automatiquement les zones/domaines
|
|
* - Configurer DNS pour tracking
|
|
*/
|
|
session_start();
|
|
|
|
function getDB() {
|
|
static $pdo = null;
|
|
if ($pdo === null) {
|
|
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123",
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
function cfAPI($endpoint, $email, $apiKey, $method = 'GET', $data = null) {
|
|
$ch = curl_init("https://api.cloudflare.com/client/v4" . $endpoint);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => [
|
|
'X-Auth-Email: ' . $email,
|
|
'X-Auth-Key: ' . $apiKey,
|
|
'Content-Type: application/json'
|
|
],
|
|
CURLOPT_CUSTOMREQUEST => $method,
|
|
CURLOPT_TIMEOUT => 30
|
|
]);
|
|
if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
|
$resp = curl_exec($ch);
|
|
curl_close($ch);
|
|
return json_decode($resp, true);
|
|
}
|
|
|
|
// AJAX
|
|
if (isset($_REQUEST['action'])) {
|
|
header('Content-Type: application/json');
|
|
$pdo = getDB();
|
|
|
|
switch ($_REQUEST['action']) {
|
|
|
|
case 'accounts':
|
|
$stmt = $pdo->query("
|
|
SELECT ca.id, ca.email, ca.password,
|
|
CASE WHEN ca.api_key IS NOT NULL AND ca.api_key != '' THEN true ELSE false END as has_api,
|
|
ca.api_key,
|
|
COUNT(cz.id) as zones_count
|
|
FROM admin.cloudflare_accounts ca
|
|
LEFT JOIN admin.cloudflare_zones cz ON cz.account_id = ca.id
|
|
GROUP BY ca.id
|
|
ORDER BY ca.id
|
|
");
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'test_api':
|
|
$email = $_POST['email'] ?? '';
|
|
$apiKey = $_POST['api_key'] ?? '';
|
|
|
|
$result = cfAPI('/user', $email, $apiKey);
|
|
echo json_encode([
|
|
'success' => $result['success'] ?? false,
|
|
'email' => $result['result']['email'] ?? null
|
|
]);
|
|
break;
|
|
|
|
case 'save_api':
|
|
$id = $_POST['id'] ?? 0;
|
|
$apiKey = $_POST['api_key'] ?? '';
|
|
|
|
$stmt = $pdo->prepare("UPDATE admin.cloudflare_accounts SET api_key = ?, last_api_check = NOW(), api_status = 'valid' WHERE id = ?");
|
|
$stmt->execute([$apiKey, $id]);
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
case 'fetch_zones':
|
|
$id = $_POST['id'] ?? 0;
|
|
|
|
$stmt = $pdo->prepare("SELECT email, api_key FROM admin.cloudflare_accounts WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$acc || !$acc['api_key']) {
|
|
echo json_encode(['success' => false, 'error' => 'No API key']);
|
|
break;
|
|
}
|
|
|
|
$result = cfAPI('/zones?per_page=50', $acc['email'], $acc['api_key']);
|
|
|
|
if (!$result['success']) {
|
|
echo json_encode(['success' => false, 'error' => $result['errors'][0]['message'] ?? 'API Error']);
|
|
break;
|
|
}
|
|
|
|
$imported = 0;
|
|
foreach ($result['result'] as $zone) {
|
|
// Insert into cloudflare_zones
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO admin.cloudflare_zones (account_id, zone_id, domain, status)
|
|
VALUES (?, ?, ?, ?)
|
|
ON CONFLICT (zone_id) DO UPDATE SET domain = EXCLUDED.domain, status = EXCLUDED.status
|
|
");
|
|
$stmt->execute([$id, $zone['id'], $zone['name'], $zone['status']]);
|
|
|
|
// Update domains_pool if exists
|
|
$stmt = $pdo->prepare("
|
|
UPDATE admin.domains_pool
|
|
SET zone_id = ?, cf_account_id = ?, provider = 'cloudflare'
|
|
WHERE domain = ? OR domain LIKE ?
|
|
");
|
|
$stmt->execute([$zone['id'], $id, $zone['name'], '%.' . $zone['name']]);
|
|
|
|
$imported++;
|
|
}
|
|
|
|
// Update account domains count
|
|
$stmt = $pdo->prepare("UPDATE admin.cloudflare_accounts SET domains_count = ? WHERE id = ?");
|
|
$stmt->execute([$imported, $id]);
|
|
|
|
echo json_encode(['success' => true, 'imported' => $imported, 'zones' => $result['result']]);
|
|
break;
|
|
|
|
case 'get_zones':
|
|
$id = $_POST['id'] ?? 0;
|
|
$stmt = $pdo->prepare("SELECT zone_id, domain, status FROM admin.cloudflare_zones WHERE account_id = ?");
|
|
$stmt->execute([$id]);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'update_dns':
|
|
$zoneId = $_POST['zone_id'] ?? '';
|
|
$domain = $_POST['domain'] ?? '';
|
|
$ip = $_POST['ip'] ?? '151.80.235.110';
|
|
$accountId = $_POST['account_id'] ?? 0;
|
|
|
|
$stmt = $pdo->prepare("SELECT email, api_key FROM admin.cloudflare_accounts WHERE id = ?");
|
|
$stmt->execute([$accountId]);
|
|
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$acc || !$acc['api_key']) {
|
|
echo json_encode(['success' => false, 'error' => 'No API key']);
|
|
break;
|
|
}
|
|
|
|
// Get existing A records
|
|
$existing = cfAPI("/zones/$zoneId/dns_records?type=A&name=$domain", $acc['email'], $acc['api_key']);
|
|
|
|
if (!empty($existing['result'])) {
|
|
// Update existing
|
|
$recordId = $existing['result'][0]['id'];
|
|
$result = cfAPI("/zones/$zoneId/dns_records/$recordId", $acc['email'], $acc['api_key'], 'PUT', [
|
|
'type' => 'A',
|
|
'name' => $domain,
|
|
'content' => $ip,
|
|
'ttl' => 1,
|
|
'proxied' => false
|
|
]);
|
|
} else {
|
|
// Create new
|
|
$result = cfAPI("/zones/$zoneId/dns_records", $acc['email'], $acc['api_key'], 'POST', [
|
|
'type' => 'A',
|
|
'name' => $domain,
|
|
'content' => $ip,
|
|
'ttl' => 1,
|
|
'proxied' => false
|
|
]);
|
|
}
|
|
|
|
echo json_encode($result);
|
|
break;
|
|
|
|
case 'create_subdomain':
|
|
$zoneId = $_POST['zone_id'] ?? '';
|
|
$subdomain = $_POST['subdomain'] ?? 'track';
|
|
$ip = $_POST['ip'] ?? '151.80.235.110';
|
|
$accountId = $_POST['account_id'] ?? 0;
|
|
|
|
$stmt = $pdo->prepare("SELECT email, api_key FROM admin.cloudflare_accounts WHERE id = ?");
|
|
$stmt->execute([$accountId]);
|
|
$acc = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
// Get zone name
|
|
$stmt = $pdo->prepare("SELECT domain FROM admin.cloudflare_zones WHERE zone_id = ?");
|
|
$stmt->execute([$zoneId]);
|
|
$zoneName = $stmt->fetchColumn();
|
|
|
|
$fullDomain = $subdomain . '.' . $zoneName;
|
|
|
|
$result = cfAPI("/zones/$zoneId/dns_records", $acc['email'], $acc['api_key'], 'POST', [
|
|
'type' => 'A',
|
|
'name' => $fullDomain,
|
|
'content' => $ip,
|
|
'ttl' => 1,
|
|
'proxied' => false
|
|
]);
|
|
|
|
if ($result['success']) {
|
|
// Add to tracking_domains
|
|
$pdo->prepare("
|
|
INSERT INTO admin.tracking_domains (domain, server_ip, is_primary, status)
|
|
VALUES (?, ?, FALSE, 'standby')
|
|
ON CONFLICT DO NOTHING
|
|
")->execute([$fullDomain, $ip]);
|
|
}
|
|
|
|
echo json_encode(array_merge($result, ['domain' => $fullDomain]));
|
|
break;
|
|
|
|
case 'bulk_fetch':
|
|
// Fetch zones for ALL accounts with API keys
|
|
$stmt = $pdo->query("SELECT id, email, api_key FROM admin.cloudflare_accounts WHERE api_key IS NOT NULL AND api_key != ''");
|
|
$accounts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$results = [];
|
|
foreach ($accounts as $acc) {
|
|
$zones = cfAPI('/zones?per_page=50', $acc['email'], $acc['api_key']);
|
|
|
|
if ($zones['success']) {
|
|
foreach ($zones['result'] as $zone) {
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO admin.cloudflare_zones (account_id, zone_id, domain, status)
|
|
VALUES (?, ?, ?, ?)
|
|
ON CONFLICT (zone_id) DO UPDATE SET status = EXCLUDED.status
|
|
");
|
|
$stmt->execute([$acc['id'], $zone['id'], $zone['name'], $zone['status']]);
|
|
}
|
|
$results[] = ['email' => $acc['email'], 'zones' => count($zones['result'])];
|
|
}
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'results' => $results]);
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>WEVAL | Cloudflare Setup</title>
|
|
<link href="plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
|
<style>
|
|
body { background: #0a0e17; color: #f1f5f9; font-family: 'Segoe UI', sans-serif; }
|
|
.container-main { max-width: 1400px; margin: 30px auto; padding: 20px; }
|
|
.card-dark { background: #1a2332; border: 1px solid #2a3a50; border-radius: 12px; margin-bottom: 20px; }
|
|
.card-header { background: #111827; border-bottom: 1px solid #2a3a50; padding: 15px 20px; font-weight: 600; }
|
|
.card-body { padding: 20px; }
|
|
.form-control-dark { background: #0d1219; border: 1px solid #2a3a50; color: #fff; border-radius: 8px; padding: 10px; }
|
|
.form-control-dark:focus { border-color: #00e5ff; outline: none; }
|
|
.btn-cyber { padding: 8px 16px; border-radius: 8px; font-weight: 600; border: none; cursor: pointer; margin: 2px; }
|
|
.btn-primary-cyber { background: linear-gradient(135deg, #00e5ff, #0891b2); color: #000; }
|
|
.btn-success-cyber { background: linear-gradient(135deg, #10b981, #059669); color: #fff; }
|
|
.btn-warning-cyber { background: linear-gradient(135deg, #f59e0b, #d97706); color: #000; }
|
|
.btn-danger-cyber { background: linear-gradient(135deg, #ef4444, #dc2626); color: #fff; }
|
|
table { width: 100%; border-collapse: collapse; }
|
|
th { color: #64748b; font-weight: 500; padding: 10px; text-align: left; border-bottom: 1px solid #2a3a50; }
|
|
td { padding: 10px; border-bottom: 1px solid #1e293b; font-size: 13px; }
|
|
.badge { padding: 4px 10px; border-radius: 12px; font-size: 11px; }
|
|
.badge-ok { background: #10b981; color: #fff; }
|
|
.badge-warn { background: #f59e0b; color: #000; }
|
|
.badge-error { background: #ef4444; color: #fff; }
|
|
h1 { color: #00e5ff; margin-bottom: 5px; }
|
|
.subtitle { color: #64748b; margin-bottom: 25px; }
|
|
code { background: #0d1219; padding: 2px 6px; border-radius: 4px; color: #f59e0b; }
|
|
.info-box { background: rgba(0,229,255,0.1); border: 1px solid rgba(0,229,255,0.3); border-radius: 8px; padding: 15px; margin-bottom: 20px; }
|
|
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 1000; }
|
|
.modal-content { background: #1a2332; border-radius: 12px; max-width: 600px; margin: 100px auto; padding: 25px; }
|
|
.modal-header { display: flex; justify-content: space-between; margin-bottom: 20px; }
|
|
.modal-close { background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; }
|
|
.zone-list { max-height: 300px; overflow-y: auto; }
|
|
.zone-item { background: #111827; padding: 10px; border-radius: 6px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
<div class="container-main">
|
|
<h1><i class="fa fa-cloud"></i> Cloudflare Setup</h1>
|
|
<p class="subtitle">Configurer les API keys et rapatrier les domaines automatiquement</p>
|
|
|
|
<div class="info-box">
|
|
<strong><i class="fa fa-info-circle"></i> Comment obtenir l'API Key:</strong><br>
|
|
1. Connectez-vous sur <a href="https://dash.cloudflare.com" target="_blank" style="color:#00e5ff;">dash.cloudflare.com</a><br>
|
|
2. Allez dans <strong>Profile → API Tokens → Global API Key → View</strong><br>
|
|
3. Copiez la clé et collez-la ici
|
|
</div>
|
|
|
|
<div class="card-dark">
|
|
<div class="card-header">
|
|
<i class="fa fa-list"></i> Comptes Cloudflare
|
|
<div class="float-right">
|
|
<button class="btn btn-cyber btn-warning-cyber btn-sm" onclick="bulkFetch()"><i class="fa fa-download"></i> Fetch All Zones</button>
|
|
<button class="btn btn-cyber btn-primary-cyber btn-sm" onclick="loadAccounts()"><i class="fa fa-refresh"></i></button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Email</th>
|
|
<th>Password</th>
|
|
<th>API Key</th>
|
|
<th>Zones</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="accounts-table"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-dark">
|
|
<div class="card-header"><i class="fa fa-crosshairs"></i> Quick Tracking Setup</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<label>Account ID</label>
|
|
<input type="number" class="form-control form-control-dark" id="track-account" value="37">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label>Zone ID</label>
|
|
<input type="text" class="form-control form-control-dark" id="track-zone" value="53e067fbc5c532a142222d60f7ecda9d">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label>Subdomain</label>
|
|
<input type="text" class="form-control form-control-dark" id="track-subdomain" value="track">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label>Tracking IP</label>
|
|
<input type="text" class="form-control form-control-dark" id="track-ip" value="151.80.235.110">
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-cyber btn-success-cyber mt-3" onclick="createTracking()">
|
|
<i class="fa fa-plus"></i> Create Tracking Subdomain
|
|
</button>
|
|
<div id="track-result" class="mt-3"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal API Key -->
|
|
<div class="modal" id="modal-api">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4><i class="fa fa-key"></i> Add API Key</h4>
|
|
<button class="modal-close" onclick="closeModal()">×</button>
|
|
</div>
|
|
<div id="modal-body">
|
|
<p>Email: <strong id="modal-email"></strong></p>
|
|
<p>Password: <code id="modal-password"></code></p>
|
|
<div class="form-group">
|
|
<label>Global API Key</label>
|
|
<input type="text" class="form-control form-control-dark" id="modal-apikey" placeholder="Paste API Key here">
|
|
</div>
|
|
<button class="btn btn-cyber btn-success-cyber" onclick="saveApiKey()"><i class="fa fa-save"></i> Test & Save</button>
|
|
<span id="modal-status"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Zones -->
|
|
<div class="modal" id="modal-zones">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4><i class="fa fa-globe"></i> Zones</h4>
|
|
<button class="modal-close" onclick="closeModal()">×</button>
|
|
</div>
|
|
<div class="zone-list" id="zones-list"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="plugins/jquery.min.js"></script>
|
|
<script>
|
|
var currentAccountId = 0;
|
|
|
|
function loadAccounts() {
|
|
$.post('?action=accounts', function(data) {
|
|
var html = '';
|
|
data.forEach(function(a) {
|
|
var apiStatus = a.has_api ? '<span class="badge badge-ok">✓</span>' : '<span class="badge badge-error">✗</span>';
|
|
var apiDisplay = a.api_key ? a.api_key.substring(0,10) + '...' : '-';
|
|
|
|
html += '<tr>';
|
|
html += '<td>' + a.id + '</td>';
|
|
html += '<td>' + a.email + '</td>';
|
|
html += '<td><code>' + (a.password || '-') + '</code></td>';
|
|
html += '<td>' + apiStatus + ' <small style="color:#64748b">' + apiDisplay + '</small></td>';
|
|
html += '<td>' + a.zones_count + '</td>';
|
|
html += '<td>';
|
|
html += '<button class="btn btn-cyber btn-primary-cyber btn-sm" onclick="openApiModal(' + a.id + ',\'' + a.email + '\',\'' + (a.password||'') + '\')"><i class="fa fa-key"></i></button> ';
|
|
if (a.has_api) {
|
|
html += '<button class="btn btn-cyber btn-warning-cyber btn-sm" onclick="fetchZones(' + a.id + ')"><i class="fa fa-download"></i></button> ';
|
|
html += '<button class="btn btn-cyber btn-success-cyber btn-sm" onclick="viewZones(' + a.id + ')"><i class="fa fa-globe"></i></button>';
|
|
}
|
|
html += '</td>';
|
|
html += '</tr>';
|
|
});
|
|
$('#accounts-table').html(html);
|
|
});
|
|
}
|
|
|
|
function openApiModal(id, email, password) {
|
|
currentAccountId = id;
|
|
$('#modal-email').text(email);
|
|
$('#modal-password').text(password);
|
|
$('#modal-apikey').val('');
|
|
$('#modal-status').html('');
|
|
$('#modal-api').show();
|
|
}
|
|
|
|
function closeModal() {
|
|
$('.modal').hide();
|
|
}
|
|
|
|
function saveApiKey() {
|
|
var apiKey = $('#modal-apikey').val().trim();
|
|
if (!apiKey) return alert('Enter API Key');
|
|
|
|
$('#modal-status').html('<i class="fa fa-spinner fa-spin"></i> Testing...');
|
|
|
|
$.post('?action=test_api', {
|
|
email: $('#modal-email').text(),
|
|
api_key: apiKey
|
|
}, function(r) {
|
|
if (r.success) {
|
|
$.post('?action=save_api', {id: currentAccountId, api_key: apiKey}, function() {
|
|
$('#modal-status').html('<span style="color:#10b981"><i class="fa fa-check"></i> Saved!</span>');
|
|
setTimeout(function() {
|
|
closeModal();
|
|
loadAccounts();
|
|
}, 1000);
|
|
});
|
|
} else {
|
|
$('#modal-status').html('<span style="color:#ef4444"><i class="fa fa-times"></i> Invalid API Key</span>');
|
|
}
|
|
});
|
|
}
|
|
|
|
function fetchZones(id) {
|
|
if (!confirm('Fetch all zones for this account?')) return;
|
|
|
|
$.post('?action=fetch_zones', {id: id}, function(r) {
|
|
if (r.success) {
|
|
alert('Imported ' + r.imported + ' zones!');
|
|
loadAccounts();
|
|
} else {
|
|
alert('Error: ' + r.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function viewZones(id) {
|
|
$.post('?action=get_zones', {id: id}, function(data) {
|
|
var html = '';
|
|
data.forEach(function(z) {
|
|
html += '<div class="zone-item">';
|
|
html += '<div><strong>' + z.domain + '</strong><br><small style="color:#64748b">' + z.zone_id + '</small></div>';
|
|
html += '<span class="badge badge-ok">' + z.status + '</span>';
|
|
html += '</div>';
|
|
});
|
|
$('#zones-list').html(html || '<p>No zones</p>');
|
|
$('#modal-zones').show();
|
|
});
|
|
}
|
|
|
|
function bulkFetch() {
|
|
if (!confirm('Fetch zones for ALL accounts with API keys?')) return;
|
|
|
|
$.post('?action=bulk_fetch', function(r) {
|
|
if (r.success) {
|
|
var msg = 'Results:\n';
|
|
r.results.forEach(function(x) {
|
|
msg += x.email + ': ' + x.zones + ' zones\n';
|
|
});
|
|
alert(msg);
|
|
loadAccounts();
|
|
}
|
|
});
|
|
}
|
|
|
|
function createTracking() {
|
|
$.post('?action=create_subdomain', {
|
|
account_id: $('#track-account').val(),
|
|
zone_id: $('#track-zone').val(),
|
|
subdomain: $('#track-subdomain').val(),
|
|
ip: $('#track-ip').val()
|
|
}, function(r) {
|
|
if (r.success) {
|
|
$('#track-result').html('<span style="color:#10b981"><i class="fa fa-check"></i> Created: <strong>' + r.domain + '</strong> → ' + $('#track-ip').val() + '</span>');
|
|
} else {
|
|
$('#track-result').html('<span style="color:#ef4444"><i class="fa fa-times"></i> Error: ' + (r.errors?.[0]?.message || 'Failed') + '</span>');
|
|
}
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
loadAccounts();
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|