init
This commit is contained in:
parent
fa6a8b6e61
commit
503c86ac0a
214
html/domain.php
214
html/domain.php
|
|
@ -1,214 +0,0 @@
|
||||||
<?php include 'header.php'; ?>
|
|
||||||
<?php
|
|
||||||
$jsonFile = __DIR__ . '/domain.json';
|
|
||||||
$defaults = [
|
|
||||||
'domain' => 'example.com',
|
|
||||||
'subdomain' => 'www.example.com',
|
|
||||||
'email' => 'name@example.com',
|
|
||||||
];
|
|
||||||
|
|
||||||
if (file_exists($jsonFile)) {
|
|
||||||
$raw = file_get_contents($jsonFile);
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
if (!is_array($data)) $data = $defaults;
|
|
||||||
} else {
|
|
||||||
$data = $defaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--accent: #0b74de;
|
|
||||||
--muted: #6b7280;
|
|
||||||
--bg: #f8fafc
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: Inter, system-ui, Arial, Helvetica, sans-serif;
|
|
||||||
background: var(--bg);
|
|
||||||
color: #111;
|
|
||||||
margin: 0;
|
|
||||||
padding: 28px
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 18px;
|
|
||||||
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.06)
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-top: 12px;
|
|
||||||
font-weight: 600
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text],
|
|
||||||
input[type=email],
|
|
||||||
select {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
margin-top: 6px;
|
|
||||||
border: 1px solid #e6eef6;
|
|
||||||
border-radius: 8px
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 12px
|
|
||||||
}
|
|
||||||
|
|
||||||
.muted {
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 13px
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 14px
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 10px 14px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 0;
|
|
||||||
background: var(--accent);
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 700
|
|
||||||
}
|
|
||||||
|
|
||||||
.ghost {
|
|
||||||
background: transparent;
|
|
||||||
border: 1px solid #e6eef6;
|
|
||||||
color: var(--accent)
|
|
||||||
}
|
|
||||||
|
|
||||||
.links {
|
|
||||||
margin-top: 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
.note {
|
|
||||||
margin-top: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
background: #f1f5f9;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 13px
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 12px
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
background: #fbfcfe;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px dashed #e6eef6;
|
|
||||||
font-size: 13px
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:700px) {
|
|
||||||
.row {
|
|
||||||
grid-template-columns: 1fr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="containerindex">
|
|
||||||
<div class="grid">
|
|
||||||
<div class="wrap">
|
|
||||||
<div class="card">
|
|
||||||
<form method="post" action="request_cert.php">
|
|
||||||
<label for="domain">Primary domain</label>
|
|
||||||
<input id="domain" name="domain" type="text" placeholder="example.com" required pattern="^[A-Za-z0-9.-]{1,253}$" value="<?php if ($data['domain'] !== "example.com") echo $data['domain']; ?>" />
|
|
||||||
|
|
||||||
<label for="subdomains" class="muted">Subdomains</label>
|
|
||||||
<input id="subdomains" name="subdomains" type="text" placeholder="example.com (optional)" value="<?php if ($data['subdomain'] !== "www.example.com") echo $data['subdomain']; ?>" />
|
|
||||||
|
|
||||||
<label for="email">Contact email (for Let\'s Encrypt notices)</label>
|
|
||||||
<input id="email" name="email" type="email" placeholder="your_name@example.com" value="<?php if ($data['email'] !== "name@example.com") echo $data['email']; ?>" required />
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div>
|
|
||||||
<label for="staging">Test mode</label>
|
|
||||||
<select id="staging" name="staging">
|
|
||||||
<option value="0">Production</option>
|
|
||||||
<option value="1">Staging (use for testing to avoid rate limits)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="checkbox">
|
|
||||||
<input type="checkbox" id="agree_tc" name="agree_tc" required />
|
|
||||||
<div>
|
|
||||||
<label for="agree_tc" style="font-weight:700">I agree to Certbot's Terms of Service and confirm that ports <strong>80 (HTTP)</strong> and <strong>443 (HTTPS)</strong> are forwarded to this server.</label>
|
|
||||||
<div class="muted">By checking this you authorise the server operator to run Certbot and modify nginx configuration for the supplied domain(s).</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="links">
|
|
||||||
<a href="https://letsencrypt.org/repository/#let-s-encrypt-subscriber-agreement" target="_blank" rel="noopener">Certbot / Let's Encrypt Terms & Conditions</a>
|
|
||||||
•
|
|
||||||
<a href="https://letsencrypt.org/privacy/">Privacy Policy</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="actions">
|
|
||||||
<button type="submit">Request Certificate</button>
|
|
||||||
<button type="reset" class="ghost">Reset</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="note">
|
|
||||||
<strong>Why ports 80 and 443 are required</strong>
|
|
||||||
<pre>
|
|
||||||
- Port 80 (HTTP) is used by Certbot for the HTTP-01 challenge: Let's Encrypt connects over HTTP to verify you control the domain.
|
|
||||||
- Port 443 (HTTPS) is required to serve TLS traffic after the certificate is issued. Nginx must accept HTTPS on port 443 so browsers and streaming clients can connect securely.
|
|
||||||
|
|
||||||
|
|
||||||
Ensure both ports are reachable from the public internet and forwarded to this server's IP. If you use a firewall, add rules to allow inbound TCP 80 and 443.
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.getElementById('certForm').addEventListener('submit', function(e) {
|
|
||||||
var dom = document.getElementById('domain').value.trim();
|
|
||||||
var subs = document.getElementById('subdomains').value.trim();
|
|
||||||
if (!dom) {
|
|
||||||
e.preventDefault();
|
|
||||||
alert('Primary domain is required');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok = document.getElementById('agree_tc').checked;
|
|
||||||
if (!ok) {
|
|
||||||
e.preventDefault();
|
|
||||||
alert('You must agree to the terms and confirm ports 80 and 443 are forwarded.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
<?php include 'footer.php'; ?>
|
|
||||||
|
|
@ -162,7 +162,7 @@ EwIDAQAB
|
||||||
|
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
if ($zip->open($zipFile) !== true) {
|
if ($zip->open($zipFile) !== true) {
|
||||||
error_log("zip unzip problem");
|
error_log("zip unzip problem");
|
||||||
fail('Unable to open ZIP');
|
fail('Unable to open ZIP');
|
||||||
}
|
}
|
||||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||||
|
|
@ -214,19 +214,16 @@ EwIDAQAB
|
||||||
unlink($file);
|
unlink($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'reboot':
|
case 'reboot':
|
||||||
exec('sudo reboot');
|
exec('sudo reboot');
|
||||||
break;
|
break;
|
||||||
case 'backup':
|
case 'backup':
|
||||||
|
|
||||||
$jsonFiles = [
|
$jsonFiles = [
|
||||||
'input.json',
|
'input.json',
|
||||||
'output.json',
|
|
||||||
'firewall.json',
|
'firewall.json',
|
||||||
'network.json',
|
'network.json',
|
||||||
'firmware.json',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$tmpZip = sys_get_temp_dir() . '/backup.zip';
|
$tmpZip = sys_get_temp_dir() . '/backup.zip';
|
||||||
|
|
@ -238,8 +235,6 @@ EwIDAQAB
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
$zip->open($tmpZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
$zip->open($tmpZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
||||||
|
|
||||||
|
|
||||||
/* Add JSON files if exist */
|
|
||||||
foreach ($jsonFiles as $json) {
|
foreach ($jsonFiles as $json) {
|
||||||
if (file_exists($json)) {
|
if (file_exists($json)) {
|
||||||
$zip->addFile($json, basename($json));
|
$zip->addFile($json, basename($json));
|
||||||
|
|
@ -249,11 +244,9 @@ EwIDAQAB
|
||||||
$zip->close();
|
$zip->close();
|
||||||
$data = file_get_contents($tmpZip);
|
$data = file_get_contents($tmpZip);
|
||||||
|
|
||||||
/* Generate AES key */
|
|
||||||
$aesKey = random_bytes(32);
|
$aesKey = random_bytes(32);
|
||||||
$iv = random_bytes(16);
|
$iv = random_bytes(16);
|
||||||
|
|
||||||
/* Encrypt ZIP */
|
|
||||||
$encryptedData = openssl_encrypt(
|
$encryptedData = openssl_encrypt(
|
||||||
$data,
|
$data,
|
||||||
'AES-256-CBC',
|
'AES-256-CBC',
|
||||||
|
|
@ -262,10 +255,7 @@ EwIDAQAB
|
||||||
$iv
|
$iv
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Encrypt AES key using RSA public key */
|
|
||||||
openssl_public_encrypt($aesKey, $encryptedKey, $publicKey);
|
openssl_public_encrypt($aesKey, $encryptedKey, $publicKey);
|
||||||
|
|
||||||
/* Final binary format */
|
|
||||||
$payload = json_encode([
|
$payload = json_encode([
|
||||||
'key' => base64_encode($encryptedKey),
|
'key' => base64_encode($encryptedKey),
|
||||||
'iv' => base64_encode($iv),
|
'iv' => base64_encode($iv),
|
||||||
|
|
@ -281,7 +271,6 @@ EwIDAQAB
|
||||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||||
header('Pragma: no-cache');
|
header('Pragma: no-cache');
|
||||||
header('Expires: 0');
|
header('Expires: 0');
|
||||||
|
|
||||||
echo $payload;
|
echo $payload;
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
|
|
@ -292,10 +281,8 @@ EwIDAQAB
|
||||||
case 'restore':
|
case 'restore':
|
||||||
$jsonFiles = [
|
$jsonFiles = [
|
||||||
'input.json',
|
'input.json',
|
||||||
'output.json',
|
|
||||||
'firewall.json',
|
'firewall.json',
|
||||||
'network.json',
|
'network.json',
|
||||||
'firmware.json',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($jsonFiles as $json) {
|
foreach ($jsonFiles as $json) {
|
||||||
|
|
@ -372,15 +359,6 @@ EwIDAQAB
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
unlink($tmpZip);
|
unlink($tmpZip);
|
||||||
update_service("display");
|
|
||||||
update_service("rtmp0");
|
|
||||||
update_service("rtmp1");
|
|
||||||
update_service("udp0");
|
|
||||||
update_service("udp1");
|
|
||||||
update_service("udp2");
|
|
||||||
update_service("srt");
|
|
||||||
update_service("custom");
|
|
||||||
update_service("input");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,8 @@
|
||||||
<span class="pill"><a style="color: #ffffff;" href="tel:+918000741919">Call Us</a></span>
|
<span class="pill"><a style="color: #ffffff;" href="tel:+918000741919">Call Us</a></span>
|
||||||
<span class="pill"><a style="color: #ffffff;" href="certification.html">Certificate</a></span>
|
<span class="pill"><a style="color: #ffffff;" href="certification.html">Certificate</a></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pill-row">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; padding: 20px; }
|
||||||
|
button { padding: 8px 14px; cursor: pointer; }
|
||||||
|
#popup {
|
||||||
|
display:none; position: fixed; top: 50%; left: 50%;
|
||||||
|
transform: translate(-50%, -50%); background: #fff;
|
||||||
|
padding: 20px; border:1px solid #333; width: 350px;
|
||||||
|
}
|
||||||
|
#popup input, #popup select { width: 100%; margin-bottom: 10px; padding: 6px; }
|
||||||
|
#overlay { display:none; position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.6); }
|
||||||
|
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||||
|
.table th, .table td { padding: 10px; border: 1px solid #ccc; text-align: left; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<h2>Service List</h2>
|
||||||
|
<button onclick="openPopup()">Add Service</button>
|
||||||
|
|
||||||
|
<!-- TABLE LIST -->
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Input UDP</th>
|
||||||
|
<th>Output UDP</th>
|
||||||
|
<th>Video Format</th>
|
||||||
|
<th>Audio Format</th>
|
||||||
|
<th>Resolution</th>
|
||||||
|
<th>Video Bitrate</th>
|
||||||
|
<th>Audio Bitrate</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php foreach ($data as $row): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($row["id"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["input_udp"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["output_udp"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["video_format"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["audio_format"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["resolution"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["video_bitrate"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["audio_bitrate"]) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row["status"]) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- POPUP -->
|
||||||
|
<div id="overlay"></div>
|
||||||
|
|
||||||
|
<div id="popup">
|
||||||
|
<h3>Add Service</h3>
|
||||||
|
|
||||||
|
<input type="text" id="in_udp" placeholder="Input UDP">
|
||||||
|
<input type="text" id="out_udp" placeholder="Output UDP">
|
||||||
|
|
||||||
|
<select id="video_format">
|
||||||
|
<option value="h264">H.264</option>
|
||||||
|
<option value="h265">H.265</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="audio_format">
|
||||||
|
<option value="aac">AAC</option>
|
||||||
|
<option value="mp3">MP3</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="resolution">
|
||||||
|
<option value="1920x1080">1920x1080</option>
|
||||||
|
<option value="1280x720">1280x720</option>
|
||||||
|
<option value="720x576">720x576</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="text" id="video_bitrate" placeholder="Video Bitrate (kbps)">
|
||||||
|
<input type="text" id="audio_bitrate" placeholder="Audio Bitrate (kbps)">
|
||||||
|
|
||||||
|
<select id="status">
|
||||||
|
<option value="enable">Enable</option>
|
||||||
|
<option value="disable">Disable</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button onclick="saveService()">Save</button>
|
||||||
|
<button onclick="closePopup()">Close</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openPopup() {
|
||||||
|
document.getElementById("popup").style.display = "block";
|
||||||
|
document.getElementById("overlay").style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePopup() {
|
||||||
|
document.getElementById("popup").style.display = "none";
|
||||||
|
document.getElementById("overlay").style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveService() {
|
||||||
|
let form = new FormData();
|
||||||
|
form.append("action", "add");
|
||||||
|
form.append("input_udp", document.getElementById("in_udp").value);
|
||||||
|
form.append("output_udp", document.getElementById("out_udp").value);
|
||||||
|
form.append("video_format", document.getElementById("video_format").value);
|
||||||
|
form.append("audio_format", document.getElementById("audio_format").value);
|
||||||
|
form.append("resolution", document.getElementById("resolution").value);
|
||||||
|
form.append("video_bitrate", document.getElementById("video_bitrate").value);
|
||||||
|
form.append("audio_bitrate", document.getElementById("audio_bitrate").value);
|
||||||
|
form.append("status", document.getElementById("status").value);
|
||||||
|
|
||||||
|
fetch("input.php", { method: "POST", body: form })
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(res => {
|
||||||
|
if (res === "OK") location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
<?php
|
|
||||||
// request_cert.php
|
|
||||||
// Parameters (POST):
|
|
||||||
// - domain (required)
|
|
||||||
// - subdomains (optional, comma-separated)
|
|
||||||
// - email (required)
|
|
||||||
// - staging (0 or 1)
|
|
||||||
|
|
||||||
$FORM_PAGE = "domain.php"; // redirect back to your form
|
|
||||||
$https = false;
|
|
||||||
function alert_and_back($message)
|
|
||||||
{
|
|
||||||
global $https;
|
|
||||||
global $domain;
|
|
||||||
global $subdomains_raw;
|
|
||||||
global $email;
|
|
||||||
|
|
||||||
$jsonFile = __DIR__ . '/domain.json';
|
|
||||||
$new = [
|
|
||||||
'domain' => $domain,
|
|
||||||
'subdomain' => $subdomains_raw,
|
|
||||||
'email' => $email,
|
|
||||||
'https' => $https
|
|
||||||
];
|
|
||||||
$json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
|
||||||
file_put_contents($jsonFile, $json, LOCK_EX);
|
|
||||||
|
|
||||||
|
|
||||||
global $FORM_PAGE;
|
|
||||||
// SAFELY escape entire message for JavaScript (supports newlines, quotes, etc.)
|
|
||||||
$msg = json_encode($message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
||||||
|
|
||||||
// Escape redirect target too
|
|
||||||
$page = json_encode($FORM_PAGE);
|
|
||||||
|
|
||||||
echo "<script>
|
|
||||||
(function(){
|
|
||||||
var msg = $msg;
|
|
||||||
var dest = $page;
|
|
||||||
|
|
||||||
// Run after DOM to avoid errors when printed inside <head>
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', function(){
|
|
||||||
alert(msg);
|
|
||||||
window.location.href = dest;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
alert(msg);
|
|
||||||
window.location.href = dest;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$domain = trim($_POST['domain'] ?? '');
|
|
||||||
$subdomains_raw = trim($_POST['subdomains'] ?? '');
|
|
||||||
$email = trim($_POST['email'] ?? '');
|
|
||||||
|
|
||||||
$staging = ($_POST['staging'] ?? "0") === "1" ? 1 : 0;
|
|
||||||
|
|
||||||
// Validation helpers
|
|
||||||
function valid_domain_name($d)
|
|
||||||
{
|
|
||||||
$d = trim($d); // important!
|
|
||||||
return (bool) preg_match(
|
|
||||||
'/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i',
|
|
||||||
$d
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate domain
|
|
||||||
if ($domain === '' || !valid_domain_name($domain)) {
|
|
||||||
alert_and_back("Invalid domain name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate email
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
alert_and_back("Invalid email address.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process subdomains
|
|
||||||
$subdomains = [];
|
|
||||||
if ($subdomains_raw !== '') {
|
|
||||||
$parts = preg_split('/[,\s;]+/', $subdomains_raw, -1, PREG_SPLIT_NO_EMPTY);
|
|
||||||
|
|
||||||
foreach ($parts as $p) {
|
|
||||||
$p = trim($p);
|
|
||||||
if ($p === '') continue;
|
|
||||||
|
|
||||||
// If user only entered "www", convert -> www.domain.com
|
|
||||||
if (strpos($p, '.') === FALSE) {
|
|
||||||
$candidate = "$p.$domain";
|
|
||||||
} else {
|
|
||||||
$candidate = $p;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid_domain_name($candidate)) {
|
|
||||||
alert_and_back("Invalid subdomain: $p");
|
|
||||||
}
|
|
||||||
|
|
||||||
$subdomains[] = $candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge primary domain + subdomains
|
|
||||||
$domains = array_values(array_unique(array_merge([$domain], $subdomains)));
|
|
||||||
|
|
||||||
// Build Certbot -d parameters
|
|
||||||
$dargs = "";
|
|
||||||
foreach ($domains as $d) {
|
|
||||||
$dargs .= " -d " . escapeshellarg($d);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build certbot command
|
|
||||||
$certbot = "/usr/bin/certbot";
|
|
||||||
$cmd = "sudo $certbot --nginx --agree-tos --non-interactive --email "
|
|
||||||
. escapeshellarg($email)
|
|
||||||
. " $dargs";
|
|
||||||
|
|
||||||
if ($staging === 1) {
|
|
||||||
$cmd .= " --staging";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run certbot
|
|
||||||
exec("$cmd 2>&1", $out, $rc);
|
|
||||||
|
|
||||||
if ($rc !== 0) {
|
|
||||||
alert_and_back("Certbot failed:\n" . implode("\n", $out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test nginx
|
|
||||||
exec("sudo nginx -t 2>&1", $test_out, $test_rc);
|
|
||||||
|
|
||||||
if ($test_rc !== 0) {
|
|
||||||
alert_and_back("Certificate created, but nginx test failed:\n" . implode("\n", $test_out));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload nginx
|
|
||||||
exec("sudo systemctl reload nginx 2>&1", $reload_out, $reload_rc);
|
|
||||||
|
|
||||||
if ($reload_rc !== 0) {
|
|
||||||
alert_and_back("Cert created, nginx tested OK, but reload failed:\n" . implode("\n", $reload_out));
|
|
||||||
}
|
|
||||||
$https = true;
|
|
||||||
// Success
|
|
||||||
alert_and_back("Certificate installed successfully for:\n" . implode(", ", $domains));
|
|
||||||
1134
html/static.php
1134
html/static.php
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue