717 lines
28 KiB
PHP
Executable File
717 lines
28 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* WEVAL Namecheap Setup
|
|
* - Stocker credentials
|
|
* - Activer API et récupérer domaines
|
|
* - Configurer DNS 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 getServerIP() {
|
|
return trim(file_get_contents('https://api.ipify.org') ?: '89.167.40.150');
|
|
}
|
|
|
|
function namecheapAPI($command, $params, $username, $apiKey) {
|
|
$baseUrl = "https://api.namecheap.com/xml.response";
|
|
|
|
$defaultParams = [
|
|
'ApiUser' => $username,
|
|
'ApiKey' => $apiKey,
|
|
'UserName' => $username,
|
|
'ClientIp' => getServerIP(),
|
|
'Command' => $command
|
|
];
|
|
|
|
$allParams = array_merge($defaultParams, $params);
|
|
$url = $baseUrl . '?' . http_build_query($allParams);
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 30,
|
|
CURLOPT_SSL_VERIFYPEER => true
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error) {
|
|
return ['success' => false, 'error' => $error];
|
|
}
|
|
|
|
$xml = @simplexml_load_string($response);
|
|
if (!$xml) {
|
|
return ['success' => false, 'error' => 'Invalid XML response'];
|
|
}
|
|
|
|
$status = (string)$xml['Status'];
|
|
if ($status === 'ERROR') {
|
|
$errors = [];
|
|
foreach ($xml->Errors->Error as $err) {
|
|
$errors[] = (string)$err;
|
|
}
|
|
return ['success' => false, 'error' => implode(', ', $errors)];
|
|
}
|
|
|
|
return ['success' => true, 'xml' => $xml, 'raw' => $response];
|
|
}
|
|
|
|
// Créer la table si nécessaire
|
|
function ensureTable() {
|
|
$pdo = getDB();
|
|
$pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS admin.namecheap_accounts (
|
|
id SERIAL PRIMARY KEY,
|
|
username VARCHAR(255) NOT NULL,
|
|
password VARCHAR(255),
|
|
api_key VARCHAR(255),
|
|
api_user VARCHAR(255),
|
|
whitelisted_ip VARCHAR(50),
|
|
status VARCHAR(50) DEFAULT 'pending',
|
|
domains_count INTEGER DEFAULT 0,
|
|
last_sync TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(username)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS admin.namecheap_domains (
|
|
id SERIAL PRIMARY KEY,
|
|
account_id INTEGER,
|
|
domain VARCHAR(255) NOT NULL,
|
|
expires_at DATE,
|
|
is_locked BOOLEAN DEFAULT FALSE,
|
|
auto_renew BOOLEAN DEFAULT FALSE,
|
|
nameservers TEXT,
|
|
status VARCHAR(50) DEFAULT 'active',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(domain)
|
|
);
|
|
");
|
|
}
|
|
|
|
// AJAX Handler
|
|
if (isset($_REQUEST['action'])) {
|
|
header('Content-Type: application/json');
|
|
ensureTable();
|
|
$pdo = getDB();
|
|
|
|
switch ($_REQUEST['action']) {
|
|
|
|
case 'get_ip':
|
|
echo json_encode(['ip' => getServerIP()]);
|
|
break;
|
|
|
|
case 'accounts':
|
|
$stmt = $pdo->query("
|
|
SELECT id, username, password, api_key IS NOT NULL AND api_key != '' as has_api,
|
|
whitelisted_ip, status, domains_count, last_sync
|
|
FROM admin.namecheap_accounts
|
|
ORDER BY id
|
|
");
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'add_account':
|
|
$username = trim($_POST['username'] ?? '');
|
|
$password = trim($_POST['password'] ?? '');
|
|
|
|
if (!$username) {
|
|
echo json_encode(['success' => false, 'error' => 'Username required']);
|
|
break;
|
|
}
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO admin.namecheap_accounts (username, password, status)
|
|
VALUES (?, ?, 'pending')
|
|
ON CONFLICT (username) DO UPDATE SET password = EXCLUDED.password
|
|
RETURNING id
|
|
");
|
|
$stmt->execute([$username, $password]);
|
|
$id = $stmt->fetchColumn();
|
|
|
|
echo json_encode(['success' => true, 'id' => $id]);
|
|
break;
|
|
|
|
case 'save_api':
|
|
$id = $_POST['id'] ?? 0;
|
|
$apiKey = trim($_POST['api_key'] ?? '');
|
|
$apiUser = trim($_POST['api_user'] ?? '');
|
|
|
|
$stmt = $pdo->prepare("
|
|
UPDATE admin.namecheap_accounts
|
|
SET api_key = ?, api_user = COALESCE(NULLIF(?, ''), username),
|
|
whitelisted_ip = ?, status = 'active'
|
|
WHERE id = ?
|
|
");
|
|
$stmt->execute([$apiKey, $apiUser, getServerIP(), $id]);
|
|
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
|
|
case 'test_api':
|
|
$username = $_POST['username'] ?? '';
|
|
$apiKey = $_POST['api_key'] ?? '';
|
|
$apiUser = $_POST['api_user'] ?? $username;
|
|
|
|
$result = namecheapAPI('namecheap.domains.getList', ['PageSize' => 1], $apiUser, $apiKey);
|
|
echo json_encode($result);
|
|
break;
|
|
|
|
case 'fetch_domains':
|
|
$id = $_POST['id'] ?? 0;
|
|
|
|
$stmt = $pdo->prepare("SELECT username, api_key, api_user FROM admin.namecheap_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;
|
|
}
|
|
|
|
$apiUser = $acc['api_user'] ?: $acc['username'];
|
|
$result = namecheapAPI('namecheap.domains.getList', ['PageSize' => 100], $apiUser, $acc['api_key']);
|
|
|
|
if (!$result['success']) {
|
|
echo json_encode($result);
|
|
break;
|
|
}
|
|
|
|
$domains = [];
|
|
$xml = $result['xml'];
|
|
|
|
if (isset($xml->CommandResponse->DomainGetListResult->Domain)) {
|
|
foreach ($xml->CommandResponse->DomainGetListResult->Domain as $domain) {
|
|
$domainName = (string)$domain['Name'];
|
|
$expires = (string)$domain['Expires'];
|
|
$isLocked = ((string)$domain['IsLocked']) === 'true';
|
|
$autoRenew = ((string)$domain['AutoRenew']) === 'true';
|
|
|
|
// Insert into namecheap_domains
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO admin.namecheap_domains (account_id, domain, expires_at, is_locked, auto_renew)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
ON CONFLICT (domain) DO UPDATE SET
|
|
expires_at = EXCLUDED.expires_at,
|
|
is_locked = EXCLUDED.is_locked,
|
|
auto_renew = EXCLUDED.auto_renew
|
|
");
|
|
$stmt->execute([$id, $domainName, $expires, $isLocked, $autoRenew]);
|
|
|
|
// Also add to domains_pool
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO admin.domains_pool (domain, provider, status)
|
|
VALUES (?, 'namecheap', 'FREE')
|
|
ON CONFLICT DO NOTHING
|
|
");
|
|
$stmt->execute([$domainName]);
|
|
|
|
$domains[] = [
|
|
'domain' => $domainName,
|
|
'expires' => $expires,
|
|
'locked' => $isLocked
|
|
];
|
|
}
|
|
}
|
|
|
|
// Update account
|
|
$pdo->prepare("UPDATE admin.namecheap_accounts SET domains_count = ?, last_sync = NOW() WHERE id = ?")
|
|
->execute([count($domains), $id]);
|
|
|
|
echo json_encode(['success' => true, 'domains' => $domains, 'count' => count($domains)]);
|
|
break;
|
|
|
|
case 'get_domains':
|
|
$id = $_POST['id'] ?? 0;
|
|
$stmt = $pdo->prepare("SELECT domain, expires_at, is_locked, auto_renew FROM admin.namecheap_domains WHERE account_id = ? ORDER BY domain");
|
|
$stmt->execute([$id]);
|
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
break;
|
|
|
|
case 'get_dns':
|
|
$id = $_POST['account_id'] ?? 0;
|
|
$domain = $_POST['domain'] ?? '';
|
|
|
|
$stmt = $pdo->prepare("SELECT api_key, api_user, username FROM admin.namecheap_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;
|
|
}
|
|
|
|
// Split domain into SLD and TLD
|
|
$parts = explode('.', $domain);
|
|
$tld = array_pop($parts);
|
|
$sld = implode('.', $parts);
|
|
|
|
$apiUser = $acc['api_user'] ?: $acc['username'];
|
|
$result = namecheapAPI('namecheap.domains.dns.getHosts', [
|
|
'SLD' => $sld,
|
|
'TLD' => $tld
|
|
], $apiUser, $acc['api_key']);
|
|
|
|
if (!$result['success']) {
|
|
echo json_encode($result);
|
|
break;
|
|
}
|
|
|
|
$records = [];
|
|
if (isset($result['xml']->CommandResponse->DomainDNSGetHostsResult->host)) {
|
|
foreach ($result['xml']->CommandResponse->DomainDNSGetHostsResult->host as $host) {
|
|
$records[] = [
|
|
'id' => (string)$host['HostId'],
|
|
'name' => (string)$host['Name'],
|
|
'type' => (string)$host['Type'],
|
|
'address' => (string)$host['Address'],
|
|
'ttl' => (string)$host['TTL']
|
|
];
|
|
}
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'records' => $records]);
|
|
break;
|
|
|
|
case 'set_dns':
|
|
$id = $_POST['account_id'] ?? 0;
|
|
$domain = $_POST['domain'] ?? '';
|
|
$ip = $_POST['ip'] ?? '151.80.235.110';
|
|
|
|
$stmt = $pdo->prepare("SELECT api_key, api_user, username FROM admin.namecheap_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;
|
|
}
|
|
|
|
// Split domain
|
|
$parts = explode('.', $domain);
|
|
$tld = array_pop($parts);
|
|
$sld = implode('.', $parts);
|
|
|
|
$apiUser = $acc['api_user'] ?: $acc['username'];
|
|
|
|
// First get existing records
|
|
$existing = namecheapAPI('namecheap.domains.dns.getHosts', [
|
|
'SLD' => $sld,
|
|
'TLD' => $tld
|
|
], $apiUser, $acc['api_key']);
|
|
|
|
// Build new records array (keep existing + add/update @ A record)
|
|
$params = [
|
|
'SLD' => $sld,
|
|
'TLD' => $tld
|
|
];
|
|
|
|
$recordNum = 1;
|
|
$foundRoot = false;
|
|
|
|
if ($existing['success'] && isset($existing['xml']->CommandResponse->DomainDNSGetHostsResult->host)) {
|
|
foreach ($existing['xml']->CommandResponse->DomainDNSGetHostsResult->host as $host) {
|
|
$name = (string)$host['Name'];
|
|
$type = (string)$host['Type'];
|
|
|
|
// Skip root A record (we'll add our own)
|
|
if ($name === '@' && $type === 'A') {
|
|
continue;
|
|
}
|
|
|
|
$params["HostName{$recordNum}"] = $name;
|
|
$params["RecordType{$recordNum}"] = $type;
|
|
$params["Address{$recordNum}"] = (string)$host['Address'];
|
|
$params["TTL{$recordNum}"] = (string)$host['TTL'];
|
|
$recordNum++;
|
|
}
|
|
}
|
|
|
|
// Add our tracking A record
|
|
$params["HostName{$recordNum}"] = '@';
|
|
$params["RecordType{$recordNum}"] = 'A';
|
|
$params["Address{$recordNum}"] = $ip;
|
|
$params["TTL{$recordNum}"] = '300';
|
|
|
|
$result = namecheapAPI('namecheap.domains.dns.setHosts', $params, $apiUser, $acc['api_key']);
|
|
|
|
if ($result['success']) {
|
|
// Update domains_pool
|
|
$pdo->prepare("UPDATE admin.domains_pool SET status = 'TRACKING', usage_type = 'tracking', tracking_ip = ? WHERE domain = ?")
|
|
->execute([$ip, $domain]);
|
|
}
|
|
|
|
echo json_encode($result);
|
|
break;
|
|
|
|
case 'delete_account':
|
|
$id = $_POST['id'] ?? 0;
|
|
$pdo->prepare("DELETE FROM admin.namecheap_domains WHERE account_id = ?")->execute([$id]);
|
|
$pdo->prepare("DELETE FROM admin.namecheap_accounts WHERE id = ?")->execute([$id]);
|
|
echo json_encode(['success' => true]);
|
|
break;
|
|
}
|
|
exit;
|
|
}
|
|
|
|
ensureTable();
|
|
$serverIP = getServerIP();
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>WEVAL | Namecheap 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; width: 100%; margin-bottom: 10px; }
|
|
.form-control-dark:focus { border-color: #f97316; 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, #f97316, #ea580c); color: #fff; }
|
|
.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; }
|
|
.btn-info-cyber { background: linear-gradient(135deg, #3b82f6, #2563eb); 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; }
|
|
.badge-nc { background: #f97316; color: #fff; }
|
|
h1 { color: #f97316; margin-bottom: 5px; }
|
|
.subtitle { color: #64748b; margin-bottom: 25px; }
|
|
code { background: #0d1219; padding: 2px 6px; border-radius: 4px; color: #f97316; }
|
|
.info-box { background: rgba(249,115,22,0.1); border: 1px solid rgba(249,115,22,0.3); border-radius: 8px; padding: 15px; margin-bottom: 20px; }
|
|
.info-box h4 { color: #f97316; margin-bottom: 10px; }
|
|
.step { background: #111827; border-radius: 8px; padding: 15px; margin-bottom: 10px; }
|
|
.step-num { display: inline-block; width: 28px; height: 28px; background: #f97316; color: #fff; border-radius: 50%; text-align: center; line-height: 28px; margin-right: 10px; font-weight: 600; }
|
|
.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: 700px; margin: 50px auto; padding: 25px; max-height: 80vh; overflow-y: auto; }
|
|
.modal-header { display: flex; justify-content: space-between; margin-bottom: 20px; }
|
|
.modal-close { background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; }
|
|
.domain-item { background: #111827; padding: 10px 15px; border-radius: 6px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
|
|
.copy-btn { cursor: pointer; color: #64748b; }
|
|
.copy-btn:hover { color: #f97316; }
|
|
</style>
|
|
|
|
</head>
|
|
<body>
|
|
<div class="container-main">
|
|
<h1><i class="fa fa-globe"></i> Namecheap Setup</h1>
|
|
<p class="subtitle">Configurer les comptes Namecheap et récupérer les domaines</p>
|
|
|
|
<div class="info-box">
|
|
<h4><i class="fa fa-info-circle"></i> Comment activer l'API Namecheap</h4>
|
|
<div class="step">
|
|
<span class="step-num">1</span>
|
|
Connectez-vous sur <a href="https://www.namecheap.com/myaccount/login" target="_blank" style="color:#f97316;">namecheap.com</a>
|
|
</div>
|
|
<div class="step">
|
|
<span class="step-num">2</span>
|
|
Allez dans <strong>Profile → Tools → API Access</strong>
|
|
</div>
|
|
<div class="step">
|
|
<span class="step-num">3</span>
|
|
Activez l'API et ajoutez cette IP dans la whitelist: <code id="server-ip"><?= $serverIP ?></code>
|
|
<i class="fa fa-copy copy-btn" onclick="copyIP()"></i>
|
|
</div>
|
|
<div class="step">
|
|
<span class="step-num">4</span>
|
|
Copiez l'<strong>API Key</strong> générée
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Account -->
|
|
<div class="card-dark">
|
|
<div class="card-header"><i class="fa fa-plus"></i> Ajouter un compte</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<input type="text" class="form-control form-control-dark" id="new-username" placeholder="Username Namecheap">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="password" class="form-control form-control-dark" id="new-password" placeholder="Password (optionnel)">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button class="btn btn-cyber btn-primary-cyber" onclick="addAccount()"><i class="fa fa-plus"></i> Ajouter</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Accounts List -->
|
|
<div class="card-dark">
|
|
<div class="card-header">
|
|
<i class="fa fa-list"></i> Comptes Namecheap
|
|
<button class="btn btn-cyber btn-primary-cyber btn-sm float-right" onclick="loadAccounts()"><i class="fa fa-refresh"></i></button>
|
|
</div>
|
|
<div class="card-body">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Username</th>
|
|
<th>Password</th>
|
|
<th>API</th>
|
|
<th>Whitelisted IP</th>
|
|
<th>Domains</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="accounts-table"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick DNS Setup -->
|
|
<div class="card-dark">
|
|
<div class="card-header"><i class="fa fa-crosshairs"></i> Quick Tracking DNS</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="dns-account" value="1">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label>Domain</label>
|
|
<input type="text" class="form-control form-control-dark" id="dns-domain" placeholder="example.com">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label>Tracking IP</label>
|
|
<input type="text" class="form-control form-control-dark" id="dns-ip" value="151.80.235.110">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label> </label>
|
|
<button class="btn btn-cyber btn-success-cyber" style="width:100%" onclick="setDNS()"><i class="fa fa-save"></i> Set</button>
|
|
</div>
|
|
</div>
|
|
<div id="dns-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> Configure API Key</h4>
|
|
<button class="modal-close" onclick="closeModal()">×</button>
|
|
</div>
|
|
<div id="modal-body">
|
|
<p>Username: <strong id="modal-username"></strong></p>
|
|
<p>Password: <code id="modal-password"></code></p>
|
|
<p style="color:#f97316"><i class="fa fa-exclamation-triangle"></i> N'oubliez pas d'ajouter <code><?= $serverIP ?></code> dans la whitelist API!</p>
|
|
|
|
<div class="form-group">
|
|
<label>API User (généralement = username)</label>
|
|
<input type="text" class="form-control form-control-dark" id="modal-apiuser" placeholder="Laisser vide si = username">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>API Key</label>
|
|
<input type="text" class="form-control form-control-dark" id="modal-apikey" placeholder="Coller l'API Key ici">
|
|
</div>
|
|
<button class="btn btn-cyber btn-success-cyber" onclick="saveApiKey()"><i class="fa fa-check"></i> Test & Save</button>
|
|
<span id="modal-status" class="ml-3"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Domains -->
|
|
<div class="modal" id="modal-domains">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4><i class="fa fa-globe"></i> Domaines</h4>
|
|
<button class="modal-close" onclick="closeModal()">×</button>
|
|
</div>
|
|
<div id="domains-list"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="plugins/jquery.min.js"></script>
|
|
<script>
|
|
var currentAccountId = 0;
|
|
|
|
function copyIP() {
|
|
navigator.clipboard.writeText($('#server-ip').text());
|
|
alert('IP copiée!');
|
|
}
|
|
|
|
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>';
|
|
|
|
html += '<tr>';
|
|
html += '<td>' + a.id + '</td>';
|
|
html += '<td><span class="badge badge-nc"><i class="fa fa-globe"></i></span> ' + a.username + '</td>';
|
|
html += '<td><code>' + (a.password || '-') + '</code></td>';
|
|
html += '<td>' + apiStatus + '</td>';
|
|
html += '<td>' + (a.whitelisted_ip || '-') + '</td>';
|
|
html += '<td>' + a.domains_count + '</td>';
|
|
html += '<td>';
|
|
html += '<button class="btn btn-cyber btn-primary-cyber btn-sm" onclick="openApiModal(' + a.id + ',\'' + a.username + '\',\'' + (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="fetchDomains(' + a.id + ')"><i class="fa fa-download"></i></button> ';
|
|
html += '<button class="btn btn-cyber btn-info-cyber btn-sm" onclick="viewDomains(' + a.id + ')"><i class="fa fa-list"></i></button> ';
|
|
}
|
|
html += '<button class="btn btn-cyber btn-danger-cyber btn-sm" onclick="deleteAccount(' + a.id + ')"><i class="fa fa-trash"></i></button>';
|
|
html += '</td>';
|
|
html += '</tr>';
|
|
});
|
|
$('#accounts-table').html(html || '<tr><td colspan="7">Aucun compte</td></tr>');
|
|
});
|
|
}
|
|
|
|
function addAccount() {
|
|
var username = $('#new-username').val().trim();
|
|
var password = $('#new-password').val().trim();
|
|
|
|
if (!username) return alert('Username requis');
|
|
|
|
$.post('?action=add_account', {username: username, password: password}, function(r) {
|
|
if (r.success) {
|
|
$('#new-username').val('');
|
|
$('#new-password').val('');
|
|
loadAccounts();
|
|
alert('Compte ajouté! Configurez maintenant l\'API key.');
|
|
} else {
|
|
alert('Erreur: ' + r.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function openApiModal(id, username, password) {
|
|
currentAccountId = id;
|
|
$('#modal-username').text(username);
|
|
$('#modal-password').text(password || '-');
|
|
$('#modal-apiuser').val('');
|
|
$('#modal-apikey').val('');
|
|
$('#modal-status').html('');
|
|
$('#modal-api').show();
|
|
}
|
|
|
|
function closeModal() {
|
|
$('.modal').hide();
|
|
}
|
|
|
|
function saveApiKey() {
|
|
var apiKey = $('#modal-apikey').val().trim();
|
|
var apiUser = $('#modal-apiuser').val().trim() || $('#modal-username').text();
|
|
|
|
if (!apiKey) return alert('API Key requise');
|
|
|
|
$('#modal-status').html('<i class="fa fa-spinner fa-spin"></i> Test en cours...');
|
|
|
|
$.post('?action=test_api', {
|
|
username: apiUser,
|
|
api_key: apiKey,
|
|
api_user: apiUser
|
|
}, function(r) {
|
|
if (r.success) {
|
|
$.post('?action=save_api', {
|
|
id: currentAccountId,
|
|
api_key: apiKey,
|
|
api_user: apiUser
|
|
}, function() {
|
|
$('#modal-status').html('<span style="color:#10b981"><i class="fa fa-check"></i> Sauvegardé!</span>');
|
|
setTimeout(function() {
|
|
closeModal();
|
|
loadAccounts();
|
|
}, 1000);
|
|
});
|
|
} else {
|
|
$('#modal-status').html('<span style="color:#ef4444"><i class="fa fa-times"></i> ' + (r.error || 'API invalide') + '</span>');
|
|
}
|
|
});
|
|
}
|
|
|
|
function fetchDomains(id) {
|
|
if (!confirm('Récupérer tous les domaines?')) return;
|
|
|
|
$.post('?action=fetch_domains', {id: id}, function(r) {
|
|
if (r.success) {
|
|
alert('Importé: ' + r.count + ' domaines');
|
|
loadAccounts();
|
|
} else {
|
|
alert('Erreur: ' + r.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function viewDomains(id) {
|
|
$.post('?action=get_domains', {id: id}, function(data) {
|
|
var html = '';
|
|
data.forEach(function(d) {
|
|
html += '<div class="domain-item">';
|
|
html += '<div><strong>' + d.domain + '</strong><br><small style="color:#64748b">Expire: ' + (d.expires_at || 'N/A') + '</small></div>';
|
|
html += '<div>';
|
|
html += '<button class="btn btn-cyber btn-success-cyber btn-sm" onclick="setTrackingDomain(\'' + d.domain + '\',' + id + ')"><i class="fa fa-crosshairs"></i></button>';
|
|
html += '</div>';
|
|
html += '</div>';
|
|
});
|
|
$('#domains-list').html(html || '<p>Aucun domaine</p>');
|
|
$('#modal-domains').show();
|
|
});
|
|
}
|
|
|
|
function setTrackingDomain(domain, accountId) {
|
|
closeModal();
|
|
$('#dns-domain').val(domain);
|
|
$('#dns-account').val(accountId);
|
|
}
|
|
|
|
function deleteAccount(id) {
|
|
if (!confirm('Supprimer ce compte?')) return;
|
|
$.post('?action=delete_account', {id: id}, function() {
|
|
loadAccounts();
|
|
});
|
|
}
|
|
|
|
function setDNS() {
|
|
var domain = $('#dns-domain').val().trim();
|
|
var ip = $('#dns-ip').val().trim();
|
|
var accountId = $('#dns-account').val();
|
|
|
|
if (!domain) return alert('Domain requis');
|
|
|
|
$('#dns-result').html('<i class="fa fa-spinner fa-spin"></i> Configuration DNS...');
|
|
|
|
$.post('?action=set_dns', {
|
|
account_id: accountId,
|
|
domain: domain,
|
|
ip: ip
|
|
}, function(r) {
|
|
if (r.success) {
|
|
$('#dns-result').html('<span style="color:#10b981"><i class="fa fa-check"></i> DNS configuré: ' + domain + ' → ' + ip + '</span>');
|
|
} else {
|
|
$('#dns-result').html('<span style="color:#ef4444"><i class="fa fa-times"></i> Erreur: ' + (r.error || 'Failed') + '</span>');
|
|
}
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
loadAccounts();
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|