Files
wevads-platform/public/dkim_setup.php
2026-04-07 03:04:16 +02:00

317 lines
20 KiB
PHP

<?php
require_once('/opt/wevads/config/credentials.php');
session_start();
header('Content-Type: text/html; charset=utf-8');
$base_url = 'http://95.216.167.89:5821';
// Connexion DB pour récupérer les comptes Cloudflare
$cloudflare_accounts = [];
try {
$pdo = get_pdo('adx_system');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("SELECT id, email as name, email, api_key, cf_account_id as zone_id FROM admin.cloudflare_accounts WHERE status = 'active' ORDER BY name");
$cloudflare_accounts = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
// Action AJAX pour push vers Cloudflare
if (isset($_GET['action']) && $_GET['action'] === 'push_cloudflare') {
header('Content-Type: application/json');
$account_id = $_POST['account_id'] ?? '';
$domain = $_POST['domain'] ?? '';
$records = json_decode($_POST['records'] ?? '[]', true);
if (empty($account_id) || empty($domain) || empty($records)) {
die(json_encode(['status' => 'error', 'message' => 'Missing parameters']));
}
try {
$pdo = get_pdo('adx_system');
$stmt = $pdo->prepare("SELECT email, api_key, cf_account_id as zone_id FROM admin.cloudflare_accounts WHERE id = ?");
$stmt->execute([$account_id]);
$account = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$account) die(json_encode(['status' => 'error', 'message' => 'Cloudflare account not found']));
$email = $account['email'];
$api_key = $account['api_key'];
$zone_id = $account['zone_id'];
if (empty($zone_id)) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones?name=" . $domain);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Auth-Email: $email", "X-Auth-Key: $api_key", "Content-Type: application/json"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (!empty($data['result'][0]['id'])) {
$zone_id = $data['result'][0]['id'];
} else {
die(json_encode(['status' => 'error', 'message' => 'Zone not found for domain: ' . $domain]));
}
}
$results = [];
$success_count = 0;
$error_count = 0;
foreach ($records as $record) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Auth-Email: $email", "X-Auth-Key: $api_key", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['type' => $record['type'], 'name' => $record['name'], 'content' => $record['content'], 'ttl' => 3600, 'proxied' => false]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (isset($data['success']) && $data['success']) {
$success_count++;
$results[] = ['record' => $record['name'], 'status' => 'success'];
} else {
$error_count++;
$error_msg = isset($data['errors'][0]['message']) ? $data['errors'][0]['message'] : 'Unknown error';
$results[] = ['record' => $record['name'], 'status' => 'error', 'message' => $error_msg];
}
}
die(json_encode(['status' => $error_count == 0 ? 'success' : 'partial', 'message' => "$success_count record(s) created, $error_count error(s)", 'results' => $results]));
} catch (Exception $e) {
die(json_encode(['status' => 'error', 'message' => $e->getMessage()]));
}
}
$dns_records = "";
$dns_records_json = [];
$dkim_generated = false;
$domain = "";
$selector = "default";
$ips_input = "";
$private_key_pem = "";
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['generate'])) {
$domain = $_POST['domain'] ?? '';
$selector = $_POST['selector'] ?? 'default';
$ips_input = $_POST['ips'] ?? '';
if ($domain && $ips_input) {
$dkim_generated = true;
$ips = array_filter(array_map('trim', explode("\n", $ips_input)));
$private_key = openssl_pkey_new(['private_key_bits' => 2048]);
openssl_pkey_export($private_key, $private_key_pem);
$key_details = openssl_pkey_get_details($private_key);
$public_key = $key_details['key'];
$public_key_clean = preg_replace('/-----BEGIN PUBLIC KEY-----(.+?)-----END PUBLIC KEY-----/s', '$1', $public_key);
$public_key_clean = str_replace(["\n", "\r", ' '], '', $public_key_clean);
$dkim_name = "{$selector}._domainkey.{$domain}";
$dkim_value = "v=DKIM1; k=rsa; p={$public_key_clean}";
$dns_records .= "=== DKIM RECORD ===\nName: {$dkim_name}\nType: TXT\nValue: {$dkim_value}\n\n";
$dns_records_json[] = ['type' => 'TXT', 'name' => $dkim_name, 'content' => $dkim_value];
$spf_ips = 'ip4:' . implode(' ip4:', $ips);
$spf_value = "v=spf1 {$spf_ips} ~all";
$dns_records .= "=== SPF RECORD ===\nName: {$domain}\nType: TXT\nValue: {$spf_value}\n\n";
$dns_records_json[] = ['type' => 'TXT', 'name' => $domain, 'content' => $spf_value];
$dmarc_name = "_dmarc.{$domain}";
$dmarc_value = "v=DMARC1; p=none; rua=mailto:dmarc@{$domain}";
$dns_records .= "=== DMARC RECORD ===\nName: {$dmarc_name}\nType: TXT\nValue: {$dmarc_value}\n\n";
$dns_records_json[] = ['type' => 'TXT', 'name' => $dmarc_name, 'content' => $dmarc_value];
$dns_records .= "=== PTR RECORDS ===\n";
foreach ($ips as $ip) { $dns_records .= "IP: {$ip} → mail.{$domain}\n"; }
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>WEVAL APP | DNS Records Generator</title>
<meta content="width=device-width, initial-scale=1" name="viewport" />
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.16/webfont.js"></script>
<script>WebFont.load({google: {"families":["Poppins:300,400,500,600,700","Roboto Mono:400"]}});</script>
<link href="<?php echo $base_url; ?>/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="<?php echo $base_url; ?>/plugins/fontawesome5/css/all.min.css" rel="stylesheet" />
<link href="<?php echo $base_url; ?>/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link rel="shortcut icon" href="<?php echo $base_url; ?>/images/logos/favicon.ico" />
<style>
body { background: #f1f5f9 !important; font-family: 'Poppins', sans-serif; }
.dkim-container { max-width: 1200px; margin: 0 auto; padding: 20px; }
.back-link { color: #00e5ff; text-decoration: none; display: inline-flex; align-items: center; margin-bottom: 20px; }
.back-link:hover { color: #1e3a5f; }
.back-link i { margin-right: 8px; }
.dkim-header { background: #ffffff; border-radius: 8px; padding: 25px; margin-bottom: 25px; border: 1px solid #e2e8f0; }
.dkim-header h1 { color: #00e5ff; margin: 0; font-size: 24px; }
.dkim-header p { color: #64748b; margin: 10px 0 0 0; }
.card-light { background: #ffffff; border-radius: 8px; border: 1px solid #e2e8f0; margin-bottom: 20px; }
.card-light .card-header { padding: 15px 20px; border-bottom: 1px solid #e2e8f0; background: #f8fafc; border-radius: 8px 8px 0 0; }
.card-light .card-header h4 { margin: 0; color: #1e293b; font-size: 16px; }
.card-light .card-header h4 i { color: #00e5ff; margin-right: 10px; }
.card-light .card-body { padding: 20px; }
.form-group { margin-bottom: 15px; }
.form-group label { color: #1e293b; font-weight: 500; margin-bottom: 8px; display: block; font-size: 13px; }
.form-group label i { color: #00e5ff; margin-right: 5px; }
.form-control { border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px 15px; width: 100%; }
.form-control:focus { border-color: #00e5ff; box-shadow: 0 0 0 3px rgba(0,229,255,0.1); outline: none; }
textarea.form-control { min-height: 100px; resize: vertical; }
.btn-primary-custom { background: linear-gradient(135deg, #00e5ff 0%, #00b8d4 100%); color: #fff; border: none; padding: 12px 20px; border-radius: 6px; font-weight: 600; width: 100%; cursor: pointer; }
.btn-primary-custom:hover { background: linear-gradient(135deg, #00b8d4 0%, #0097a7 100%); color: #fff; }
.btn-cloudflare { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: #fff; border: none; padding: 12px 20px; border-radius: 6px; font-weight: 600; width: 100%; cursor: pointer; margin-top: 15px; }
.btn-cloudflare:hover { background: linear-gradient(135deg, #d97706 0%, #b45309 100%); color: #fff; }
.btn-copy { background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); color: #fff; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; }
.btn-copy:hover { background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%); color: #fff; }
.result-box { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 15px; font-family: 'Roboto Mono', monospace; font-size: 12px; white-space: pre-wrap; word-break: break-all; color: #065f46; max-height: 300px; overflow-y: auto; }
.private-key-box { background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 15px; font-family: 'Roboto Mono', monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; color: #92400e; max-height: 200px; overflow-y: auto; }
.alert-box { border-radius: 6px; padding: 12px 15px; margin-bottom: 15px; }
.alert-info { background: #e0f2fe; border: 1px solid #0ea5e9; color: #0369a1; }
.alert-success { background: #d1fae5; border: 1px solid #10b981; color: #065f46; }
.alert-warning { background: #fef3c7; border: 1px solid #f59e0b; color: #92400e; }
.alert-danger { background: #fee2e2; border: 1px solid #ef4444; color: #991b1b; }
.section-title { color: #1e293b; font-size: 14px; font-weight: 600; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; }
.cloudflare-section { border-top: 1px solid #e2e8f0; margin-top: 20px; padding-top: 20px; }
</style>
</head>
<body>
<div class="dkim-container">
<a href="<?php echo $base_url; ?>/dashboard.html" class="back-link"><i class="fa fa-arrow-left"></i> Back to Dashboard</a>
<div class="dkim-header">
<h1><i class="fa fa-key"></i> DNS Records Generator</h1>
<p>Generate DKIM, SPF, DMARC and PTR records for your email domains</p>
</div>
<div class="row">
<div class="col-md-5">
<div class="card-light">
<div class="card-header"><h4><i class="fa fa-cogs"></i> Configuration</h4></div>
<div class="card-body">
<form method="POST">
<div class="form-group">
<label><i class="fa fa-globe"></i> Domain</label>
<input type="text" name="domain" class="form-control" placeholder="example.com" value="<?php echo htmlspecialchars($domain); ?>" required>
</div>
<div class="form-group">
<label><i class="fa fa-tag"></i> DKIM Selector</label>
<input type="text" name="selector" class="form-control" placeholder="default" value="<?php echo htmlspecialchars($selector); ?>">
</div>
<div class="form-group">
<label><i class="fa fa-server"></i> Server IPs (one per line)</label>
<textarea name="ips" class="form-control" placeholder="192.168.1.1&#10;192.168.1.2" required><?php echo htmlspecialchars($ips_input); ?></textarea>
</div>
<button type="submit" name="generate" class="btn-primary-custom"><i class="fa fa-magic"></i> Generate DNS Records</button>
</form>
</div>
</div>
<div class="card-light">
<div class="card-header"><h4><i class="fa fa-info-circle"></i> Instructions</h4></div>
<div class="card-body">
<div class="alert-box alert-info">
<strong>Step 1:</strong> Enter your domain name<br>
<strong>Step 2:</strong> Add all server IPs (one per line)<br>
<strong>Step 3:</strong> Click Generate<br>
<strong>Step 4:</strong> Copy records to your DNS or push to Cloudflare
</div>
</div>
</div>
</div>
<div class="col-md-7">
<?php if (true): ?>
<div class="card-light">
<div class="card-header"><h4><i class="fa fa-file-text"></i> Generated DNS Records</h4></div>
<div class="card-body">
<div class="section-title">
<span><i class="fa fa-list"></i> DNS Records</span>
<button class="btn-copy" onclick="copyToClipboard('dns-records')"><i class="fa fa-copy"></i> Copy All</button>
</div>
<div id="dns-records" class="result-box"><?php echo htmlspecialchars($dns_records); ?></div>
<div class="cloudflare-section">
<div class="section-title"><span><i class="fab fa-cloudflare"></i> Push to Cloudflare</span></div>
<?php if (count($cloudflare_accounts) > 0): ?>
<div class="form-group">
<label><i class="fa fa-cloud"></i> Select Cloudflare Account</label>
<select id="cloudflare-account" class="form-control">
<option value="">-- Select Cloudflare Account --</option>
<?php foreach ($cloudflare_accounts as $acc): ?>
<option value="<?php echo $acc['id']; ?>"><?php echo htmlspecialchars($acc['name']); ?> (<?php echo htmlspecialchars($acc['email']); ?>)<?php echo empty($acc['api_key']) ? ' [API key manquante]' : ''; ?></option>
<?php endforeach; ?>
</select>
</div>
<button id="btn-push-cloudflare" class="btn-cloudflare"><i class="fab fa-cloudflare"></i> Push DNS Records to Cloudflare</button>
<div id="cloudflare-status" style="margin-top: 15px;"></div>
<?php else: ?>
<div class="alert-box alert-warning"><i class="fa fa-exclamation-triangle"></i> No Cloudflare accounts configured. Add accounts in Settings → Cloudflare Accounts.</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="card-light">
<div class="card-header"><h4><i class="fa fa-lock"></i> Private Key (for PMTA)</h4></div>
<div class="card-body">
<div class="alert-box alert-warning"><i class="fa fa-exclamation-triangle"></i> <strong>Keep this private!</strong> This key is used in your PMTA configuration.</div>
<div class="section-title">
<span><i class="fa fa-key"></i> Private Key</span>
<button class="btn-copy" onclick="copyToClipboard('private-key')"><i class="fa fa-copy"></i> Copy</button>
</div>
<div id="private-key" class="private-key-box"><?php echo htmlspecialchars($private_key_pem); ?></div>
</div>
</div>
<?php else: ?>
<div class="card-light">
<div class="card-header"><h4><i class="fa fa-file-text"></i> Generated DNS Records</h4></div>
<div class="card-body">
<div class="alert-box alert-info" style="text-align: center;">
<i class="fa fa-arrow-left" style="font-size: 24px; margin-bottom: 10px; display: block;"></i>
Fill in the form and click <strong>Generate</strong> to create your DNS records.
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script src="<?php echo $base_url; ?>/plugins/jquery.min.js"></script>
<script>
var dnsRecordsJson = <?php echo json_encode($dns_records_json); ?>;
var domain = '<?php echo addslashes($domain); ?>';
function copyToClipboard(elementId) {
var text = document.getElementById(elementId).innerText;
navigator.clipboard.writeText(text).then(function() { alert('Copied to clipboard!'); }).catch(function() {
var textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('Copied to clipboard!');
});
}
$('#btn-push-cloudflare').on('click', function() {
var btn = $(this);
var accountId = $('#cloudflare-account').val();
if (!accountId) { alert('Please select a Cloudflare account'); return; }
if (dnsRecordsJson.length === 0) { alert('No DNS records to push'); return; }
btn.html('<i class="fa fa-spinner fa-spin"></i> Pushing to Cloudflare...').prop('disabled', true);
$('#cloudflare-status').html('<div class="alert-box alert-info"><i class="fa fa-spinner fa-spin"></i> Connecting to Cloudflare API...</div>');
$.ajax({
url: '?action=push_cloudflare',
method: 'POST',
data: { account_id: accountId, domain: domain, records: JSON.stringify(dnsRecordsJson) },
dataType: 'json',
success: function(r) {
var html = '';
if (r.status === 'success') { html = '<div class="alert-box alert-success"><i class="fa fa-check-circle"></i> ' + r.message + '</div>'; }
else if (r.status === 'partial') { html = '<div class="alert-box alert-warning"><i class="fa fa-exclamation-triangle"></i> ' + r.message + '</div>'; }
else { html = '<div class="alert-box alert-danger"><i class="fa fa-times-circle"></i> ' + r.message + '</div>'; }
if (r.results && r.results.length > 0) {
html += '<div style="margin-top: 10px;">';
r.results.forEach(function(res) {
var icon = res.status === 'success' ? 'check' : 'times';
var color = res.status === 'success' ? '#10b981' : '#ef4444';
html += '<div style="padding: 8px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 4px; margin-bottom: 5px; font-size: 13px;">';
html += '<i class="fa fa-' + icon + '" style="color: ' + color + ';"></i> ' + res.record;
if (res.message) html += ' <small style="color: #64748b;">(' + res.message + ')</small>';
html += '</div>';
});
html += '</div>';
}
$('#cloudflare-status').html(html);
},
error: function() { $('#cloudflare-status').html('<div class="alert-box alert-danger"><i class="fa fa-times-circle"></i> Connection error</div>'); },
complete: function() { btn.html('<i class="fab fa-cloudflare"></i> Push DNS Records to Cloudflare').prop('disabled', false); }
});
});
</script>
<?php include("includes/chatbot-widget.php"); ?>
</body>
</html>