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();
|
||||
if ($zip->open($zipFile) !== true) {
|
||||
error_log("zip unzip problem");
|
||||
error_log("zip unzip problem");
|
||||
fail('Unable to open ZIP');
|
||||
}
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
|
|
@ -220,13 +220,10 @@ EwIDAQAB
|
|||
exec('sudo reboot');
|
||||
break;
|
||||
case 'backup':
|
||||
|
||||
$jsonFiles = [
|
||||
'input.json',
|
||||
'output.json',
|
||||
'firewall.json',
|
||||
'network.json',
|
||||
'firmware.json',
|
||||
];
|
||||
|
||||
$tmpZip = sys_get_temp_dir() . '/backup.zip';
|
||||
|
|
@ -238,8 +235,6 @@ EwIDAQAB
|
|||
$zip = new ZipArchive();
|
||||
$zip->open($tmpZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
||||
|
||||
|
||||
/* Add JSON files if exist */
|
||||
foreach ($jsonFiles as $json) {
|
||||
if (file_exists($json)) {
|
||||
$zip->addFile($json, basename($json));
|
||||
|
|
@ -249,11 +244,9 @@ EwIDAQAB
|
|||
$zip->close();
|
||||
$data = file_get_contents($tmpZip);
|
||||
|
||||
/* Generate AES key */
|
||||
$aesKey = random_bytes(32);
|
||||
$iv = random_bytes(16);
|
||||
|
||||
/* Encrypt ZIP */
|
||||
$encryptedData = openssl_encrypt(
|
||||
$data,
|
||||
'AES-256-CBC',
|
||||
|
|
@ -262,10 +255,7 @@ EwIDAQAB
|
|||
$iv
|
||||
);
|
||||
|
||||
/* Encrypt AES key using RSA public key */
|
||||
openssl_public_encrypt($aesKey, $encryptedKey, $publicKey);
|
||||
|
||||
/* Final binary format */
|
||||
$payload = json_encode([
|
||||
'key' => base64_encode($encryptedKey),
|
||||
'iv' => base64_encode($iv),
|
||||
|
|
@ -281,7 +271,6 @@ EwIDAQAB
|
|||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: 0');
|
||||
|
||||
echo $payload;
|
||||
flush();
|
||||
|
||||
|
|
@ -292,10 +281,8 @@ EwIDAQAB
|
|||
case 'restore':
|
||||
$jsonFiles = [
|
||||
'input.json',
|
||||
'output.json',
|
||||
'firewall.json',
|
||||
'network.json',
|
||||
'firmware.json',
|
||||
];
|
||||
|
||||
foreach ($jsonFiles as $json) {
|
||||
|
|
@ -372,15 +359,6 @@ EwIDAQAB
|
|||
$zip->close();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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="certification.html">Certificate</a></span>
|
||||
</div>
|
||||
<div class="pill-row">
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<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