236 lines
9.8 KiB
PHP
Executable File
236 lines
9.8 KiB
PHP
Executable File
|
|
<?php
|
|
/**
|
|
* API Domains Pool - Gestion centralisée des domaines de send
|
|
* Sources: Cloudflare, FreeDNS, Namecheap
|
|
*/
|
|
header('Content-Type: application/json');
|
|
|
|
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
$action = $_GET['action'] ?? $_POST['action'] ?? '';
|
|
$input = json_decode(file_get_contents('php://input'), true) ?? [];
|
|
|
|
// Config Cloudflare
|
|
function getCFConfig() {
|
|
$file = '/opt/wevads/storage/office365/cloudflare_config.json';
|
|
return file_exists($file) ? json_decode(file_get_contents($file), true) : [];
|
|
}
|
|
|
|
// Appel API Cloudflare
|
|
function cfApi($endpoint, $method = 'GET', $data = null) {
|
|
$config = getCFConfig();
|
|
if (!$config['api_key']) return ['success' => false, 'error' => 'No API key'];
|
|
|
|
$ch = curl_init("https://api.cloudflare.com/client/v4/$endpoint");
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => [
|
|
"X-Auth-Email: {$config['api_email']}",
|
|
"X-Auth-Key: {$config['api_key']}",
|
|
"Content-Type: application/json"
|
|
],
|
|
CURLOPT_TIMEOUT => 30
|
|
]);
|
|
if ($method === 'POST') {
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
|
} elseif ($method === 'DELETE') {
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
|
}
|
|
$result = curl_exec($ch);
|
|
curl_close($ch);
|
|
return json_decode($result, true);
|
|
}
|
|
|
|
switch ($action) {
|
|
|
|
// === LISTER DOMAINES ===
|
|
case 'list':
|
|
$status = $_GET['status'] ?? null;
|
|
$provider = $_GET['provider'] ?? null;
|
|
$limit = min((int)($_GET['limit'] ?? 100), 500);
|
|
|
|
$sql = "SELECT * FROM admin.domains_pool WHERE 1=1";
|
|
$params = [];
|
|
if ($status) { $sql .= " AND status = ?"; $params[] = $status; }
|
|
if ($provider) { $sql .= " AND provider = ?"; $params[] = $provider; }
|
|
$sql .= " ORDER BY created_at DESC LIMIT $limit";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
echo json_encode(['success' => true, 'domains' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
|
|
break;
|
|
|
|
// === STATS ===
|
|
case 'stats':
|
|
$stats = $pdo->query("
|
|
SELECT
|
|
COUNT(*) as total,
|
|
COUNT(CASE WHEN status = 'FREE' THEN 1 END) as free,
|
|
COUNT(CASE WHEN status = 'ASSIGNED' THEN 1 END) as assigned,
|
|
COUNT(CASE WHEN verification = 'VERIFIED' THEN 1 END) as verified,
|
|
COUNT(CASE WHEN dns_complete = true THEN 1 END) as dns_complete,
|
|
COUNT(CASE WHEN provider = 'cloudflare' THEN 1 END) as cloudflare,
|
|
COUNT(CASE WHEN provider = 'freedns' THEN 1 END) as freedns,
|
|
COUNT(CASE WHEN provider = 'office365' THEN 1 END) as office365
|
|
FROM admin.domains_pool
|
|
")->fetch(PDO::FETCH_ASSOC);
|
|
echo json_encode(['success' => true, 'stats' => $stats]);
|
|
break;
|
|
|
|
// === SYNC CLOUDFLARE ZONES ===
|
|
case 'sync_cloudflare':
|
|
$result = cfApi('zones?per_page=50');
|
|
if (!$result['success']) {
|
|
echo json_encode(['success' => false, 'error' => $result['errors'][0]['message'] ?? 'CF API error']);
|
|
break;
|
|
}
|
|
|
|
$synced = 0;
|
|
foreach ($result['result'] as $zone) {
|
|
// Insérer dans cloudflare_zones
|
|
$stmt = $pdo->prepare("INSERT INTO admin.cloudflare_zones (zone_id, domain, status)
|
|
VALUES (?, ?, ?) ON CONFLICT (zone_id) DO UPDATE SET status = EXCLUDED.status");
|
|
$stmt->execute([$zone['id'], $zone['name'], $zone['status']]);
|
|
$synced++;
|
|
}
|
|
echo json_encode(['success' => true, 'synced' => $synced, 'zones' => $result['result']]);
|
|
break;
|
|
|
|
// === CRÉER SOUS-DOMAINE CLOUDFLARE ===
|
|
case 'create_cf_subdomain':
|
|
$config = getCFConfig();
|
|
$subdomain = $input['subdomain'] ?? substr(md5(rand()), 0, 5);
|
|
$baseDomain = $input['base_domain'] ?? $config['base_domain'];
|
|
$zoneId = $input['zone_id'] ?? $config['zone_id'];
|
|
$fullDomain = "$subdomain.$baseDomain";
|
|
|
|
// Créer les records DNS pour Office365
|
|
$mxTarget = "$fullDomain.mail.protection.outlook.com";
|
|
$records = [
|
|
['type' => 'MX', 'name' => $fullDomain, 'content' => $mxTarget, 'priority' => 10],
|
|
['type' => 'TXT', 'name' => $fullDomain, 'content' => "v=spf1 include:spf.protection.outlook.com -all"],
|
|
['type' => 'CNAME', 'name' => "autodiscover.$fullDomain", 'content' => 'autodiscover.outlook.com']
|
|
];
|
|
|
|
$recordIds = [];
|
|
$errors = [];
|
|
foreach ($records as $rec) {
|
|
$res = cfApi("zones/$zoneId/dns_records", 'POST', $rec);
|
|
if ($res['success']) {
|
|
$recordIds[$rec['type']] = $res['result']['id'];
|
|
} else {
|
|
$errors[] = $rec['type'] . ': ' . ($res['errors'][0]['message'] ?? 'error');
|
|
}
|
|
}
|
|
|
|
if (count($recordIds) >= 2) {
|
|
// Insérer dans domains_pool
|
|
$stmt = $pdo->prepare("INSERT INTO admin.domains_pool
|
|
(domain, zone_id, zone_name, provider, status, verification, mx_content, spf_record, cf_record_ids, created_at)
|
|
VALUES (?, ?, ?, 'cloudflare', 'FREE', 'PENDING', ?, ?, ?, NOW())
|
|
ON CONFLICT (domain) DO UPDATE SET updated_at = NOW()
|
|
RETURNING id");
|
|
$stmt->execute([
|
|
$fullDomain, $zoneId, $baseDomain, $mxTarget,
|
|
"v=spf1 include:spf.protection.outlook.com -all",
|
|
json_encode($recordIds)
|
|
]);
|
|
$id = $stmt->fetchColumn();
|
|
echo json_encode(['success' => true, 'domain' => $fullDomain, 'id' => $id, 'records' => $recordIds, 'errors' => $errors]);
|
|
} else {
|
|
echo json_encode(['success' => false, 'errors' => $errors]);
|
|
}
|
|
break;
|
|
|
|
// === ASSIGNER DOMAINE À COMPTE OFFICE ===
|
|
case 'assign':
|
|
$domainId = $input['domain_id'] ?? 0;
|
|
$officeAccountId = $input['office_account_id'] ?? 0;
|
|
|
|
if (!$domainId || !$officeAccountId) {
|
|
echo json_encode(['success' => false, 'error' => 'domain_id and office_account_id required']);
|
|
break;
|
|
}
|
|
|
|
$stmt = $pdo->prepare("UPDATE admin.domains_pool
|
|
SET office_account_id = ?, status = 'ASSIGNED', updated_at = NOW()
|
|
WHERE id = ? AND status = 'FREE'");
|
|
$stmt->execute([$officeAccountId, $domainId]);
|
|
|
|
echo json_encode(['success' => $stmt->rowCount() > 0, 'updated' => $stmt->rowCount()]);
|
|
break;
|
|
|
|
// === LIBÉRER DOMAINE ===
|
|
case 'release':
|
|
$domainId = $input['domain_id'] ?? 0;
|
|
$stmt = $pdo->prepare("UPDATE admin.domains_pool
|
|
SET office_account_id = NULL, status = 'FREE', updated_at = NOW()
|
|
WHERE id = ?");
|
|
$stmt->execute([$domainId]);
|
|
echo json_encode(['success' => true, 'released' => $stmt->rowCount()]);
|
|
break;
|
|
|
|
// === SUPPRIMER DOMAINE ===
|
|
case 'delete':
|
|
$domainId = $input['domain_id'] ?? 0;
|
|
|
|
// Récupérer les infos pour supprimer de CF
|
|
$domain = $pdo->query("SELECT * FROM admin.domains_pool WHERE id = $domainId")->fetch(PDO::FETCH_ASSOC);
|
|
if ($domain && $domain['provider'] === 'cloudflare' && $domain['cf_record_ids']) {
|
|
$recordIds = json_decode($domain['cf_record_ids'], true);
|
|
foreach ($recordIds as $recId) {
|
|
cfApi("zones/{$domain['zone_id']}/dns_records/$recId", 'DELETE');
|
|
}
|
|
}
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM admin.domains_pool WHERE id = ?");
|
|
$stmt->execute([$domainId]);
|
|
echo json_encode(['success' => true, 'deleted' => $stmt->rowCount()]);
|
|
break;
|
|
|
|
// === VÉRIFIER DNS COMPLET ===
|
|
case 'check_dns':
|
|
$domainId = $input['domain_id'] ?? $_GET['domain_id'] ?? 0;
|
|
$domain = $pdo->query("SELECT * FROM admin.domains_pool WHERE id = $domainId")->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$domain) {
|
|
echo json_encode(['success' => false, 'error' => 'Domain not found']);
|
|
break;
|
|
}
|
|
|
|
$dnsComplete = !empty($domain['mx_content']) && !empty($domain['spf_record']);
|
|
$pdo->prepare("UPDATE admin.domains_pool SET dns_complete = ?, last_dns_check = NOW() WHERE id = ?")
|
|
->execute([$dnsComplete, $domainId]);
|
|
|
|
echo json_encode(['success' => true, 'domain' => $domain['domain'], 'dns_complete' => $dnsComplete]);
|
|
break;
|
|
|
|
// === OBTENIR DOMAINE LIBRE POUR ENVOI ===
|
|
case 'get_free_for_send':
|
|
$officeAccountId = $_GET['office_account_id'] ?? 0;
|
|
|
|
// Priorité: domaines déjà assignés à ce compte, sinon FREE avec DNS complet
|
|
$sql = "SELECT * FROM admin.domains_pool
|
|
WHERE (office_account_id = ? OR (status = 'FREE' AND dns_complete = true))
|
|
AND verification = 'VERIFIED'
|
|
ORDER BY CASE WHEN office_account_id = ? THEN 0 ELSE 1 END,
|
|
provider ASC -- freedns first
|
|
LIMIT 1";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$officeAccountId, $officeAccountId]);
|
|
$domain = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode(['success' => (bool)$domain, 'domain' => $domain]);
|
|
break;
|
|
|
|
default:
|
|
echo json_encode([
|
|
'error' => 'Invalid action',
|
|
'available' => ['list', 'stats', 'sync_cloudflare', 'create_cf_subdomain', 'assign', 'release', 'delete', 'check_dns', 'get_free_for_send']
|
|
]);
|
|
}
|
|
|