init
This commit is contained in:
commit
fa6a8b6e61
|
|
@ -0,0 +1,52 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCaSua4bKKMn8hX
|
||||||
|
zoH8afGUjdAd5WuLBZk8X4L98LxMN4fPcy7NwOPlEb6JUNnBcrbtOYbA++bOuXho
|
||||||
|
LMNLPQJhXpSPV2Bdyu9ttDZ3HSEiTl8aauQixNec2LxBaXdVl9BptPYPy9ME0uMR
|
||||||
|
lk/RZgUmQHs6+NmZS02MLUH1H8hOWgcse15MXLdb5ZRSwqsjsLnuAKeyrbjbYdAb
|
||||||
|
Xjv9hQRQMeFwfI/dByPzv1TZ5CbJJ8hRO4unzXLCx5XTVfyFbhaChCAJi32FCZSW
|
||||||
|
wtPEIX3/Vxu/SeAO3Z8PSdDEPPirFUYkEV+JB3m3Ts0dsYCFo78STa/KhmMkGEtA
|
||||||
|
dK+Pe2zWd8Z5cLg2DHtQROyLJ+iGX767kPOB04PlG+rJTDYHOZBAMgKv4DxiDMRK
|
||||||
|
hRNF4l3CDiKtnA35au6bjuWgiseTfgQuRuJt9GK7tnN+r6RcUPRVs1Ys/1EvJDLd
|
||||||
|
4e9VAiZraELnFprE3N/oh3F6TVDTUr/bCY++RGLCEFOY5iUQ/4FnJHONbFYRdYa8
|
||||||
|
ga2gfZYA+X2x26thdn0rjoj5Opl5K/AQ7l7DYz2VJjG+ZTYAV0Y7Frb9HDEsoZa3
|
||||||
|
/oqDlbB7jk6t3ZbxN9LpDODITqfid8hLlURm2F9uW/wU4GVWc0D0nnZnaoXPL0nA
|
||||||
|
bQWZuwpK06QiIIxDKs/MsIQfaIlNKwIDAQABAoICAEeB/kMsCfvdk8bqLQE0gqOk
|
||||||
|
Q/ePG9P/IMFDzNxvRX2XYOiKy/7M7nH8Us+mOn228kOonST0ukhF2iGB2XMVz/Qb
|
||||||
|
lwOF7eIaSvQPiQyUYgZZxybhsmDQ1NLa+gjg3c88AHn1RfMVNnPuXxGIFe8I9sr/
|
||||||
|
KH2w1nx+025rjT2TYMy7WcbKWG5QrCQ5lw/yK8nrPoipIg+kBuAaCY6dknURQGoA
|
||||||
|
bCireitog0eU/bjMThN9ThAj5jo7c/wE7xHWsKWQW3tay9RQozhUs9pZajbkhNYh
|
||||||
|
43i4vtB08yJtRgWk8mSsA+l0adACuGz15wdjfBqzxLqxaY8V0H3qinnReoonnE1i
|
||||||
|
wpBpK34DFL8NIWJZ2SVpnn847kW/cP0jxeLDDgQZMPC8WDSQsu1gOO+n98ACr9Iv
|
||||||
|
WuXp3TcIsHSXNQm6KATH9opiNM7dqxR2KklGYNBC+Vr2Z1J8nszLUtNH+VeU30qE
|
||||||
|
Q/4p/M9Akqy6fI4Gx52a98f1hyeG0VGJ247qA56Mlg1lUMZoBjr57xpHgoVBc3Bp
|
||||||
|
YvTuN9eNUJWgkSFWwiET+sjbVLLnwyH3pDCjohl9PLUze2RqMhb3WWHy/ZelzEnX
|
||||||
|
k71XuCseduCO4jgpQeGy3bg8k1qJaj0veiuon6+WVvZ333iwO4cWF/bxPJkgLS0X
|
||||||
|
pRf2e8iGBppXFR641YxhAoIBAQDXGa+2t9tFq6EQBgvYMVxP+b0y2DCJAt2mq3ZT
|
||||||
|
sABSExbg6/o9ZW+wE9CE5G7Vh6Tqu1kgMwCUY4LWBj/hPrb7n817H78e0kkUemHh
|
||||||
|
NehvPSgHnwOPoRl2suQTy60I7Qdr3pWnkrqIixJFGL/HB9ULiBV/+iEfzdiivIqL
|
||||||
|
5mTRtAnRjtPHaPD5pCm9YqI0lFJGs9PNQUnDHt0JgemNCzeqAWwoonI/szcSxvrT
|
||||||
|
0qQJI7688Hgr/fRnG6hAkOYN4QyIpwZ9fF43MzH3WiwkRz3YKVEiEkoZXTLK5X05
|
||||||
|
7/X4H6TY/AG2puFhwBALcLE2CjutHCmsllCi/8W970lL1kqhAoIBAQC3oU+wlnIt
|
||||||
|
bMNsVraTDvTfN+3H96sJ/snh0mDZQYyUxbN22TMnEqcjKJ/afNymvp3UffZT9EiK
|
||||||
|
wm05UxMlBXAXPTiXI+71K9QVgew9lIoXop8/7BoACeLCvzRsFzYNsH0vtDHTz1yO
|
||||||
|
0RGrarb3BsONeDLtUikwfgi+CLtYRbSeRAULvU29yOFr10cHOXw7ItDMBSMwU/hP
|
||||||
|
3aKSEYAn6CVqLqAAPr6T5RwjXuT2daDKoyq3P/X0NkLMVMtGaeSjO41QnLf4pSWb
|
||||||
|
7x1ec0D6l6OEboKLilknh/x/2nedmOwAEiNM4pSIhqSY1JZw6rO+J6Y6FEkdxzy0
|
||||||
|
zWYLLQEdO3BLAoIBAQC0KzHBDHNAAihgcZAOQBogawEMy4Sr3pil+EyegHdkR9UM
|
||||||
|
BNyP/Jz2kUJBbc1gUcPTUaWvkMjVghyfBJERLCS80vecP9UoDd9kpbXCnBLayhDz
|
||||||
|
gT/MWJYplGHyKtH+/fsPYVtdB0vy/voIolhQb8EFbbEEhxCjwRnKBb7Ou+aKuBDZ
|
||||||
|
VJcTGlVt5RGJLkrLW8kmq42nCR6trvZZ9lUX7ONtJM/hoV+s94IT2lNShcccWLJ1
|
||||||
|
M76UqpzCmKnvmu73hR+ofq6zAS8xcVJS61a59Gpa2xC4RzWF1UisJlkj5FjUwjyj
|
||||||
|
+0G8Kj/yTpuh2Xy11RBzSXmmtClKvo51Ly7ntNDBAoIBACwZfmTfTJ5iH3CWRpR8
|
||||||
|
pAwzh1Rdw2LMILmt53plhph3/kiNkv5QOXl1GSbEk80rvAW7FnxFD2LbnJWGwPNE
|
||||||
|
Ig5CsqOBirKwiud7YzvKv3s7n9kfH4Ng3Gd+ud03mdCh0P6y3MCMbSMTTJYJM9WR
|
||||||
|
d0czVa+u6pttuTXCLRPe8aiMl1WhadkpNBHNCo7OnGorS0+j8DZ8BAdSJ+fCci+j
|
||||||
|
TdD5T42fg+9Kt347HOufhjUECI8nui6jFVmzB3pqlfEprR9t87SwHJ8dRsVXEoTc
|
||||||
|
A/YbABj46b5XpykhU1ay0gKWWInvZFKBW2gkrdiCVRZWuVH7ay/OmGKnbVlDvp/B
|
||||||
|
lY8CggEALa9Dw8kMDet9sysx4zC9f3IyQT6iR15RaD6uTc2J2wTBjry5deC+M+pt
|
||||||
|
g277uvfRgr5EGsXidJ03jD7Sc5wNM1i1q1AC8QPAKX4j0l35N7SxjJP+cxIdwll+
|
||||||
|
dQqg0dr1A4mCbgm22IatmlvEH4oGu/WozDDlhz11WLhG2m28npAspdEAacCsvncX
|
||||||
|
DDzaff/4FxjN8BilhqBHaLgZuqQROfDVWJb7vfq/BTO4uZBUjYONLEgG37cA002H
|
||||||
|
HIBqMEzbewdNtLSbi4xCvmgnofZ1WtsyPfAWCHX+A6wjF8Ey8PdU2/0ILHQwx3WO
|
||||||
|
oo7uGCyxw179QUUzXs18xVnordQGvA==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmkrmuGyijJ/IV86B/Gnx
|
||||||
|
lI3QHeVriwWZPF+C/fC8TDeHz3MuzcDj5RG+iVDZwXK27TmGwPvmzrl4aCzDSz0C
|
||||||
|
YV6Uj1dgXcrvbbQ2dx0hIk5fGmrkIsTXnNi8QWl3VZfQabT2D8vTBNLjEZZP0WYF
|
||||||
|
JkB7OvjZmUtNjC1B9R/ITloHLHteTFy3W+WUUsKrI7C57gCnsq2422HQG147/YUE
|
||||||
|
UDHhcHyP3Qcj879U2eQmySfIUTuLp81ywseV01X8hW4WgoQgCYt9hQmUlsLTxCF9
|
||||||
|
/1cbv0ngDt2fD0nQxDz4qxVGJBFfiQd5t07NHbGAhaO/Ek2vyoZjJBhLQHSvj3ts
|
||||||
|
1nfGeXC4Ngx7UETsiyfohl++u5DzgdOD5RvqyUw2BzmQQDICr+A8YgzESoUTReJd
|
||||||
|
wg4irZwN+Wrum47loIrHk34ELkbibfRiu7Zzfq+kXFD0VbNWLP9RLyQy3eHvVQIm
|
||||||
|
a2hC5xaaxNzf6Idxek1Q01K/2wmPvkRiwhBTmOYlEP+BZyRzjWxWEXWGvIGtoH2W
|
||||||
|
APl9sdurYXZ9K46I+TqZeSvwEO5ew2M9lSYxvmU2AFdGOxa2/RwxLKGWt/6Kg5Ww
|
||||||
|
e45Ord2W8TfS6QzgyE6n4nfIS5VEZthfblv8FOBlVnNA9J52Z2qFzy9JwG0FmbsK
|
||||||
|
StOkIiCMQyrPzLCEH2iJTSsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>ShreeBhattJi</h3>
|
||||||
|
<p>If you’ve ever read the Panchatantra, a few stories begin like this: “Once upon a time, there lived a poor Brahmin in a village.” In this story, that Brahmin is me — ShreeBhattJi, also known as Devdatt Bhatt, the King of Automation and Remote Control from the land of great beginnings, Bhavnagar.
|
||||||
|
<p>I am here to help provide a great viewing experience for users, generate strong commissions for LCOs, MSOs, and ISPs, and create substantial revenue for content owners while contributing fair taxes to the government. I have reason to believe that by upgrading a few devices at the transmission point, both streaming operations and customer viewing experiences can be improved exponentially.
|
||||||
|
<p>We are proud to present Universal Digital Encoder Decoder as all format to all format encoder cum decoder for dedicated hardware , virtual machines and proxmox lxc images .
|
||||||
|
<p><a href="https://urmic.org/trusted-partners/" target="_blank"><button class="red-btn">Meet Our Partners</button></a>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Bhavnagar :- The Land Of Great Beginnings</h3>
|
||||||
|
<ul>
|
||||||
|
<li>The great country called India began to exist at Bhavnagar. On 15 August 1947, Indian administrative control effectively began with Bhavnagar after Maharaja Krishnakumarsinhji Bhavsinhji Gohil merged his princely state into the independent Union of India.</li>
|
||||||
|
<p>
|
||||||
|
<li>The “bull gift” from Maharaja Krishnakumarsinhji of Bhavnagar to Brazilian cattle baron Celso Garcia Sid helped shape the Brazilian dairy industry, leading to the world-famous Girolando breed. Today, Girolando cows produce over 80% of Brazil’s milk. <a href="https://youtu.be/HLJHFibZ130">DD INDIA REPORT</a></li>
|
||||||
|
<p>
|
||||||
|
<li>The first diamond-cutting industry in India started in Bhavnagar, not Surat. Skilled jewelers and artisans in Bhavnagar (Saurashtra region, Gujarat) began cutting and polishing small rough diamonds imported from Africa. These craftsmen later moved to Surat, which eventually became the world’s largest diamond-cutting and polishing hub.</li>
|
||||||
|
<p>
|
||||||
|
<li>The largest ship-breaking yard in the world, “Alang Ship Breaking Yard,” located in Bhavnagar district, Gujarat, started operations in 1983. It handles over 50% of global ship recycling by tonnage and is a major source of recycled steel for India’s economy.</li>
|
||||||
|
<p>
|
||||||
|
<li>After the Kurukshetra war, the Pandavas sought absolution for the killing that occurred in battle. Following the guidance of Lord Krishna, who gave them a black flag and a black cow, they were instructed to follow the cow until both turned white. Krishna told them that when this happened, they would be forgiven. The Pandavas followed the cow for many years to various places, but the flag and cow remained black. Finally, when they reached Koliyak Beach, both miraculously turned white.</li>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Self Certification</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
background: #f4f6f8;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar {
|
||||||
|
background: #0f172a;
|
||||||
|
padding: 12px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar button {
|
||||||
|
background: #2563eb;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar button:hover {
|
||||||
|
background: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 24px auto;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 32px;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature {
|
||||||
|
margin-top: 48px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-box {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-line {
|
||||||
|
margin-top: 40px;
|
||||||
|
border-top: 1px solid #000;
|
||||||
|
padding-top: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.top-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
box-shadow: none;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function goHome() {
|
||||||
|
window.location.href = "index.html";
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPage() {
|
||||||
|
window.print();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="top-bar">
|
||||||
|
<button onclick="goHome()">Home</button>
|
||||||
|
<button onclick="printPage()">Print</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Self Certification Declaration</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This document serves as a formal self-certification confirming compliance with all applicable
|
||||||
|
legal, security, and operational requirements related to the provided software, firmware,
|
||||||
|
service, or system.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">Compliance & Safety Declaration</div>
|
||||||
|
<p>
|
||||||
|
I hereby declare and guarantee that the delivered software or system contains no malware,
|
||||||
|
spyware, backdoors, or harmful components of any kind. The system does not perform unauthorized
|
||||||
|
surveillance, user behavior tracking, or data collection beyond what is strictly required for
|
||||||
|
its intended operation.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">Privacy Assurance</div>
|
||||||
|
<p>
|
||||||
|
No usage tracking, analytics, or hidden monitoring mechanisms are implemented. Any data processed
|
||||||
|
by the system is handled transparently and solely for functional or security-related purposes.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">License Verification Notice</div>
|
||||||
|
<p>
|
||||||
|
For licensing and authenticity verification purposes, limited hardware-related identifiers may
|
||||||
|
be securely stored. This information is used exclusively for license validation and protection
|
||||||
|
against unauthorized use, duplication, or redistribution.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">Limitation of Liability</div>
|
||||||
|
<p>
|
||||||
|
The developer, author, or distributor shall not be held liable for any direct, indirect,
|
||||||
|
incidental, special, consequential, or punitive damages, including but not limited to loss
|
||||||
|
of data, system failure, business interruption, or financial loss, arising from the use,
|
||||||
|
misuse, or inability to use the software or system.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The software or system is provided on an “as-is” and “as-available” basis, without warranties
|
||||||
|
of any kind, whether express or implied. The user assumes full responsibility for deployment,
|
||||||
|
configuration, operation, and compliance with applicable laws and regulations.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">Declaration</div>
|
||||||
|
<p>
|
||||||
|
I confirm that the above statements are true and accurate to the best of my knowledge and accept
|
||||||
|
full responsibility for compliance with this declaration.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="section-title">Device Id</div>
|
||||||
|
<p>
|
||||||
|
certificatecertificatecertificatecertificate
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="signature">
|
||||||
|
<div class="sign-box">
|
||||||
|
Devdatt Bhatt aka ShreeBhattji <br> Bhavnagar
|
||||||
|
<div class="sign-line">Authorized Signature</div>
|
||||||
|
</div>
|
||||||
|
<div class="sign-box">
|
||||||
|
<br>01 Jan , 2026
|
||||||
|
<div class="sign-line">Date</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>How Can We Help ?</h3>
|
||||||
|
<ul>
|
||||||
|
<li>We provide free RTMP and EPG file hosting for Registared Broadcastors.</li>
|
||||||
|
<li>Auto Publishing channel on Cable Tv, IPTV , OTT APP like <a href="https://play.google.com/store/apps/details?id=org.urmic.ott">URMIC OTT.</a></li>
|
||||||
|
<li>LCO and MSO can get local channels via STREAMINGBOX ( One Box 30 channel - No Encoder Needed - QAM is must )</li>
|
||||||
|
<li>ISP will get scalable Intranet OTT for resellers and customers .</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Say Hello to Us</h3>
|
||||||
|
<p>C-1819 , <br>Radhesyam Soc,<br>Kalyabid, <br>Bhavnagar - 364001<br>INDIA
|
||||||
|
<p>support@urmic.org
|
||||||
|
<br>+91-8000-74-1919
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<div class="social-row" aria-label="Social links">
|
||||||
|
<a class="social-btn" href="https://www.facebook.com/WorldwideDigitalAssociation" target="_blank" rel="noopener" aria-label="Facebook page">
|
||||||
|
<svg viewBox="0 0 23 23" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M22 12.07C22 6.47 17.52 2 11.92 2S2 6.47 2 12.07c0 4.99 3.66 9.12 8.44 9.86v-6.98H8.1v-2.88h2.34V9.41c0-2.31 1.37-3.59 3.46-3.59.99 0 2.03.18 2.03.18v2.23h-1.14c-1.12 0-1.47.7-1.47 1.42v1.7h2.5l-.4 2.88h-2.1v6.98C18.34 21.19 22 17.06 22 12.07z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a class="social-btn" href="https://www.linkedin.com/in/dbhatt-org/" target="_blank" rel="noopener" aria-label="LinkedIn profile">
|
||||||
|
<svg viewBox="0 0 23 23" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M4.98 3.5C4.98 4.88 3.86 6 2.5 6S0 4.88 0 3.5 1.12 1 2.5 1 4.98 2.12 4.98 3.5zM.5 8h4v14h-4V8zm7.5 0h3.84v1.93h.05c.54-1.02 1.86-2.1 3.83-2.1 4.1 0 4.86 2.7 4.86 6.21V22h-4V15.2c0-1.61-.03-3.68-2.24-3.68-2.24 0-2.58 1.75-2.58 3.55V22h-4V8z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a class="social-btn" href="https://wa.me/918000741919?text=Hello%20from%20website" target="_blank" rel="noopener" aria-label="WhatsApp chat">
|
||||||
|
<svg viewBox="0 0 23 23" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M20.52 3.48A11.93 11.93 0 0 0 12 0C5.37 0 .05 5.32.05 11.92c0 2.1.55 4.15 1.6 5.95L0 24l6.4-1.68c1.75 1.02 3.77 1.56 5.6 1.56 6.63 0 11.95-5.32 11.95-11.95 0-3.2-1.25-6.2-3.43-8.45zM12 21.95c-1.55 0-3.06-.4-4.36-1.16l-.31-.18-3.8 1 1-3.5-.2-.34A8.72 8.72 0 0 1 3.1 11.9c0-4.85 3.95-8.8 8.8-8.8 2.35 0 4.56.92 6.22 2.6a8.76 8.76 0 0 1-6.13 15.45zM17.03 14.1c-.29-.15-1.7-.84-1.97-.93-.27-.09-.47-.14-.67.14-.2.28-.77.93-.94 1.12-.17.19-.34.21-.63.07-.29-.15-1.23-.45-2.34-1.44-.87-.78-1.46-1.74-1.63-2.03-.17-.29-.02-.45.13-.6.13-.13.29-.34.44-.51.14-.17.19-.29.29-.48.1-.19.05-.36-.02-.51-.07-.15-.67-1.6-.92-2.19-.24-.58-.49-.5-.67-.51l-.57-.01c-.19 0-.5.07-.76.36-.27.29-1.03 1.01-1.03 2.47s1.05 2.87 1.2 3.07c.15.19 2.07 3.19 5.02 4.47 2.95 1.28 3.12.88 3.68.83.56-.05 1.78-.72 2.03-1.41.25-.69.25-1.28.18-1.41-.07-.13-.27-.19-.56-.34z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a class="social-btn" href="sms:+918000741919?body=Test%20message" aria-label="Send test SMS">
|
||||||
|
<svg viewBox="0 0 23 23" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M20 2H4c-1.1 0-2 .9-2 2v14l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a class="social-btn" href="mailto:hello@urmic.org?subject=Hello&body=Hi%2C%20I%20am%20contacting%20you%20from%20the%20website." aria-label="Send email">
|
||||||
|
<svg viewBox="0 0 23 23" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
<?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'; ?>
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?php include 'header.php' ?>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$jsonFile = __DIR__ . '/firewall.json';
|
||||||
|
|
||||||
|
$defaults = [
|
||||||
|
'80' => '',
|
||||||
|
'443' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$data = $defaults;
|
||||||
|
|
||||||
|
if (is_file($jsonFile)) {
|
||||||
|
$stored = json_decode(file_get_contents($jsonFile), true);
|
||||||
|
if (is_array($stored)) {
|
||||||
|
$data = $stored;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
|
exec("echo y | sudo ufw reset");
|
||||||
|
exec("sudo ufw default allow outgoing");
|
||||||
|
exec("sudo ufw default deny incoming");
|
||||||
|
exec("sudo ufw allow proto udp to 224.0.0.0/4");
|
||||||
|
exec("sudo ufw route allow proto udp to 224.0.0.0/4");
|
||||||
|
exec("sudo ufw deny out to 239.255.254.254 port 39000 proto udp");
|
||||||
|
|
||||||
|
foreach ($defaults as $port => $_) {
|
||||||
|
$data[$port] = trim($_POST["port_$port"] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmp = $jsonFile . '.tmp';
|
||||||
|
file_put_contents(
|
||||||
|
$tmp,
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
|
||||||
|
);
|
||||||
|
rename($tmp, $jsonFile);
|
||||||
|
|
||||||
|
foreach ($data as $port => $value) {
|
||||||
|
$tmp = array_filter(
|
||||||
|
array_map('trim', explode(',', (string)$value)),
|
||||||
|
'strlen'
|
||||||
|
);
|
||||||
|
if (count($tmp) > 0) {
|
||||||
|
foreach ($tmp as $ip) {
|
||||||
|
exec("sudo ufw allow from " . $ip." to any port " . $port . " proto tcp");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exec("sudo ufw allow " . $port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exec("sudo ufw allow from 172.16.111.112 to 172.16.111.111 port 80");
|
||||||
|
exec("sudo ufw allow from 172.16.111.112 to 172.16.111.111 port 443");
|
||||||
|
exec("sudo ufw --force enable");
|
||||||
|
exec("sudo ufw reload");
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 520px;
|
||||||
|
margin: 40px auto;
|
||||||
|
background: #fff;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input[type=text]:invalid {
|
||||||
|
border-color: #d33;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #2563eb;
|
||||||
|
box-shadow: 0 0 0 2px rgba(37, 99, 235, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #1e4ed8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function validateIPs(input) {
|
||||||
|
if (!input.value.trim()) return true;
|
||||||
|
|
||||||
|
const ips = input.value.split(',').map(i => i.trim());
|
||||||
|
|
||||||
|
const ipv4 =
|
||||||
|
/^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
|
||||||
|
|
||||||
|
const ipv6 =
|
||||||
|
/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::1|::)$/;
|
||||||
|
|
||||||
|
for (const ip of ips) {
|
||||||
|
if (!(ipv4.test(ip) || ipv6.test(ip))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachValidation() {
|
||||||
|
document.querySelectorAll('input[type=text]').forEach(inp => {
|
||||||
|
inp.addEventListener('input', () => {
|
||||||
|
inp.setCustomValidity(
|
||||||
|
validateIPs(inp) ? '' : 'Invalid IPv4 or IPv6 address'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.onload = attachValidation;
|
||||||
|
</script>
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
<h2>Limit Access</h2>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<?php foreach ($data as $port => $value): ?>
|
||||||
|
<div class="row">
|
||||||
|
<label>Port <?= htmlspecialchars($port) ?></label>
|
||||||
|
<textarea
|
||||||
|
name="port_<?= $port ?>"
|
||||||
|
rows="2"
|
||||||
|
placeholder="IPv4, IPv6 (comma separated)"><?= htmlspecialchars($value) ?></textarea>
|
||||||
|
|
||||||
|
<small>Example: 192.168.1.10/24, 2001:db8::1</small>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<button type="submit">Limit Access</button>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php include 'footer.php' ?>
|
||||||
|
|
@ -0,0 +1,456 @@
|
||||||
|
<?php
|
||||||
|
include 'header.php';
|
||||||
|
|
||||||
|
exec("sudo chmod 444 /sys/class/dmi/id/product_uuid");
|
||||||
|
$version = 1;
|
||||||
|
|
||||||
|
function fail(string $msg): never
|
||||||
|
{
|
||||||
|
fwrite(STDERR, "ERROR: $msg\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(string $url, string $dest): void
|
||||||
|
{
|
||||||
|
$fp = fopen($dest, 'wb');
|
||||||
|
if (!$fp) fail("Cannot write $dest");
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_FILE => $fp,
|
||||||
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
|
CURLOPT_FAILONERROR => true,
|
||||||
|
CURLOPT_TIMEOUT => 60,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!curl_exec($ch)) {
|
||||||
|
fail("Download failed: " . curl_error($ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
fclose($fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$device_id = trim(file_get_contents('/sys/class/dmi/id/product_uuid'));
|
||||||
|
|
||||||
|
$publicKey = "-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAm6glpTALuc82R+9Mqb5f
|
||||||
|
HVRC5dScc7USgWoIsYN1tF8YE0d7rhSIFvayVabiyabVmWscjAIlmYf6InSlLsDx
|
||||||
|
avfmapg32ECd92H49ZbsvXQpLqasyOkN7z6FUcuQ6pEMqfPBmBXKGngHazPp420o
|
||||||
|
Iki9hLc7IE9EMlDHfozckuJI8mB+bsd2oqua6SSTBYx5HYuSCbootf9GliSd7PVk
|
||||||
|
H6uir88j49/NFfvmrReicFBiMba959uOdBIhWl9AveZL+iI2NdS5SPw6eWltaMot
|
||||||
|
PSk7/5Z4Vn5Od7sQA0yUqmCj5XNV5EzRlP1jhP7SDv0D6Mpdf3HuKWdCBqepJBe2
|
||||||
|
rCHPQ9KrChQau4eEbJb5LIE3gFDpLxTHk9FEp+50evkpFONj0aAjSb3P4wsEGiOk
|
||||||
|
95Tm56gDRirnbbw/6SzhE7pEvXRUfMl1KO6maYK1z7KNMgEH99C2zCjZhpaXL5Io
|
||||||
|
rywCw009zoMT2qdKPMGOyQ4KPlCLCJYSF0y/rE07WNgl4BupVZR41B5MbXL5L7+X
|
||||||
|
OD0jBpbWI7v2ChP9rn5u6Lqpq6ewvc2RJO8lrAyZtzrNJNZNYmUKHrm7qAHJeJZX
|
||||||
|
Zh7OEf9U/T9JBpzf8l0MzyywlQGUBzb/niG0iZILt3XIpD+Xeyrr6hr+nabeiKXV
|
||||||
|
jHyUcG84zzLjv7sREzWEGoLBrdztMy69rbfd3d0DpjS90xceKZYBDd3vwjn6h0TN
|
||||||
|
KssqUb7BMH+zkCe/LQg6EGdXB13+xUSUjFKLLeBKu1VxMPfd/WmV1QumOodidvee
|
||||||
|
rQAv6yMevq2hVFkiFo7CUpaRv6dvQnQaqX2rHFKZY6zEIzbJXTznl6ZMtCcmcZMk
|
||||||
|
CYcoWZIAUR5tFP221XzIfJmymVRfJGiKTvt+g/SUUFJt6mq8ettu11XS4KSIxtaA
|
||||||
|
l8q2SSxpRQa80NUuaBpQc/3eP293wgcf/EOfzhCjxDLjsHSKV1AkSMyjvCzSsCdG
|
||||||
|
mMEIuT/D7PB7N8vlfhn5qsyt1Sm81/1EZ3u8UqToELhe8j7G26GVl/8ptSxofvZE
|
||||||
|
X0goYwW18PPhtZvkR8CXpZ7qwjqDcL5cQzcCldufjtqJ5GAwN6SrcmnYjQoo2cu9
|
||||||
|
XlWo0InPE8BpjR7vJpKLbppQzwUs9GQYx2bMSTbsrduc8zDXlPT5aOfgkJui/NQa
|
||||||
|
uxttvsXqXd3nNJhbO0BN+wCDT0j4LNRvMlJloWEGrBkY4SA5I1MX8XBL34Csy6Bu
|
||||||
|
bHWxXNBAGYMchcJKly7XN2hA61V4QCCiFz/MP9l1llw/Mk4D5IUTxcfcEDHx7LO0
|
||||||
|
To+pc5kuXS6Aps6lKJdwv6h0Bi9SWtBpFi2RtpQpAc+dVPQ9lwq3VTJV5GZz3AgV
|
||||||
|
KQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
";
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
switch ($_POST['action']) {
|
||||||
|
case 'update':
|
||||||
|
|
||||||
|
$payload['device_id'] = $device_id;
|
||||||
|
$payload['project_id'] = "28f27590923d962388f0da125553c5";
|
||||||
|
$payload['version'] = $version;
|
||||||
|
$payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
openssl_public_encrypt(
|
||||||
|
$payload,
|
||||||
|
$encrypted,
|
||||||
|
$publicKey,
|
||||||
|
OPENSSL_PKCS1_OAEP_PADDING
|
||||||
|
);
|
||||||
|
|
||||||
|
$postData = [
|
||||||
|
'encrypted' => base64_encode($encrypted)
|
||||||
|
];
|
||||||
|
|
||||||
|
$ch = curl_init('https://account.urmic.org/encoder/update_transcoder.php');
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $postData,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_TIMEOUT => 10,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
|
echo '<script>alert("'
|
||||||
|
. htmlspecialchars($data['message'], ENT_QUOTES)
|
||||||
|
. '");</script>';
|
||||||
|
|
||||||
|
error_log($data['status']);
|
||||||
|
|
||||||
|
if ($data['status'] == "valid") {
|
||||||
|
$public_key = "-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAm+7Vl0fEgey2tF6v2mTn
|
||||||
|
3C/FDGn589uY5a9rpDeZLlhjdOdFaTMWL3d8oEhmImCd+aPELpxydQ+xGxVPNOzO
|
||||||
|
WKbF3V/FymwxyU3yCD8rfCPyd05z9ANeicVEZMO2K0CwjLoM1OFpxoo/GRmetHuY
|
||||||
|
Yt2WxDWHPN9DjDDkIMrx2PKFHPqJnyWliyFWJ4aaaK174GH+b4rHRkAm31fUhbaG
|
||||||
|
RBcQWJhWv1gJ+lxz2z3oHi9nI6Q/Hkb+u3B11tcx3j6rScxKXk8T6Bw64vEk3t0l
|
||||||
|
i1kYgnPI4Eya0BXuROMfn+zGG50TNgq+vWntzBoKaWuPVbvvmzTlHK8My9qZUliy
|
||||||
|
otDNd340xhBCmIYqkwxiN2w4g+TAM9X3r9/4lgJYx5ezh3Y0uLGf6mHZ5wFyDAhh
|
||||||
|
uLJxkOCZY0b3zoRW5wqqKR67/FxBCpcLS6Y8wlKSR8UU8y73hr2tGD28JgNr9sjx
|
||||||
|
reRItpdGhQgO8gLZKLK6LhihTFtbt5tiL1l6Fkc11DSac+N/xFyHfRe6K3lIV+cD
|
||||||
|
WMx0+6YX3p8i4cmRXGn59Xu1VdZvmB03Dl5YmIb6wBNMCEPWohRz0bGmamXGW1Ze
|
||||||
|
EZQhGJRUqIFNuTQwc/RI1wPUgefXXXitCOlo52oyahuKWxWuGMN/8Uyw74poK7NK
|
||||||
|
7Tbu+JLNuqMsuPoVkrl7havRUbwQy7xUt93wFew0GFDaOobZzoGIjp3pWGvZiQ7y
|
||||||
|
XMyzklS42/ZC7rJAJTyuLTHxMeUMB4Zt7Qmp7GQ3NaOUq4egPQ6KZUO4qDNtAJaK
|
||||||
|
mvHca0HHmskP20/yb4iVtz65zhj6BWt98SsFuRMrMDDoBDEtcd1T7xIRK4nqfIhX
|
||||||
|
8Nw8z1+m8TVItJM3XxvLx6eXgtnJ8BqWInjRoFkbpzEON56zA1ZwPCFm7MWACKEs
|
||||||
|
m4Gul3+liBwDnpaJvHLLs6+9R4T1/d6nrwwRPDBz9AhBZV2Qz0/Z67qAyGvT2Joh
|
||||||
|
qR6fIHe+jsKlPSW4TBBx8C2H6avKv7W0CH7z4Y9APuDucvMQ2X3CCekTRaejU7nr
|
||||||
|
JOGs8ALAtsL+eXL+KMvU/16zxzcbT4ZW/6kdRFtwkaWlq07Q1yU13s+JQRzenut5
|
||||||
|
7j1GMcmtt1K/CSBzhs2d2UTwiO3fRDs4TCUAj/vq2OlfL1UOAZ3ni8QmfA1vD/BD
|
||||||
|
Xqfivizijmypv83rv8se5b6dr78ti+wiAIEJEDX+/yISmEWuDXGaL+eVATr1Rw+0
|
||||||
|
8vFY2f7lS2/QsSv+X7B6lOs3L18sG7AAYrkFjrfhQ8RC9Lv62ITUAV6B6G/BJ4o0
|
||||||
|
UubReGWsYm092Z9SWEB8KBUlwMWjEMl6Q2f3AfkAKR3EMYBqmNfL8teAcb711xA2
|
||||||
|
EwIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
";
|
||||||
|
|
||||||
|
error_log("starting");
|
||||||
|
$tmpDir = sys_get_temp_dir() . '/payload_' . bin2hex(random_bytes(6));
|
||||||
|
$zipFile = $tmpDir . '/payload.zip';
|
||||||
|
$sigFile = $tmpDir . '/payload.zip.sig';
|
||||||
|
$extractDir = $tmpDir . '/extract';
|
||||||
|
error_log("setting up directory");
|
||||||
|
|
||||||
|
mkdir($tmpDir, 0700, true);
|
||||||
|
mkdir($extractDir, 0700, true);
|
||||||
|
error_log("directory created");
|
||||||
|
error_log($tmpDir);
|
||||||
|
|
||||||
|
download($data['link'], $zipFile);
|
||||||
|
download($data['signature'], $sigFile);
|
||||||
|
error_log("download compltete");
|
||||||
|
|
||||||
|
$publicKey = openssl_pkey_get_public($public_key);
|
||||||
|
if (!$publicKey) fail('Invalid public key');
|
||||||
|
|
||||||
|
$data = file_get_contents($zipFile);
|
||||||
|
$signature = file_get_contents($sigFile);
|
||||||
|
error_log("loading zip and sig");
|
||||||
|
|
||||||
|
$verified = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
|
||||||
|
|
||||||
|
if ($verified !== 1) {
|
||||||
|
error_log("verification failed");
|
||||||
|
fail('Signature verification FAILED');
|
||||||
|
}
|
||||||
|
error_log("varification complete");
|
||||||
|
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
if ($zip->open($zipFile) !== true) {
|
||||||
|
error_log("zip unzip problem");
|
||||||
|
fail('Unable to open ZIP');
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||||
|
$name = $zip->getNameIndex($i);
|
||||||
|
if (str_contains($name, '..') || str_starts_with($name, '/')) {
|
||||||
|
fail('Zip traversal detected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->extractTo($extractDir);
|
||||||
|
$zip->close();
|
||||||
|
$setup = $extractDir . '/setup.sh';
|
||||||
|
|
||||||
|
if (!is_file($setup)) {
|
||||||
|
fail('setup.sh not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
chmod($setup, 0755);
|
||||||
|
|
||||||
|
$descriptorSpec = [
|
||||||
|
1 => ['pipe', 'w'],
|
||||||
|
2 => ['pipe', 'w'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$process = proc_open(
|
||||||
|
['/bin/bash', $setup],
|
||||||
|
$descriptorSpec,
|
||||||
|
$pipes,
|
||||||
|
$extractDir
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_resource($process)) {
|
||||||
|
fail('Failed to execute setup.sh');
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = stream_get_contents($pipes[1]);
|
||||||
|
$error = stream_get_contents($pipes[2]);
|
||||||
|
|
||||||
|
fclose($pipes[1]);
|
||||||
|
fclose($pipes[2]);
|
||||||
|
|
||||||
|
$exitCode = proc_close($process);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
$files = glob('/var/www/encoder/*.json');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (is_file($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'reboot':
|
||||||
|
exec('sudo reboot');
|
||||||
|
break;
|
||||||
|
case 'backup':
|
||||||
|
|
||||||
|
$jsonFiles = [
|
||||||
|
'input.json',
|
||||||
|
'output.json',
|
||||||
|
'firewall.json',
|
||||||
|
'network.json',
|
||||||
|
'firmware.json',
|
||||||
|
];
|
||||||
|
|
||||||
|
$tmpZip = sys_get_temp_dir() . '/backup.zip';
|
||||||
|
$outputFile = __DIR__ . '/universal_encoder_decoder.bin';
|
||||||
|
|
||||||
|
$publicKey = file_get_contents('/var/www/backup_private.pem');
|
||||||
|
$publicKey = file_get_contents('/var/www/backup_public.pem');
|
||||||
|
|
||||||
|
$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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$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',
|
||||||
|
$aesKey,
|
||||||
|
OPENSSL_RAW_DATA,
|
||||||
|
$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),
|
||||||
|
'data' => base64_encode($encryptedData)
|
||||||
|
]);
|
||||||
|
|
||||||
|
$filename = 'universal_encoder_decoder.bin';
|
||||||
|
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||||
|
header('Content-Length: ' . strlen($payload));
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||||
|
header('Pragma: no-cache');
|
||||||
|
header('Expires: 0');
|
||||||
|
|
||||||
|
echo $payload;
|
||||||
|
flush();
|
||||||
|
|
||||||
|
unlink($tmpZip);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'restore':
|
||||||
|
$jsonFiles = [
|
||||||
|
'input.json',
|
||||||
|
'output.json',
|
||||||
|
'firewall.json',
|
||||||
|
'network.json',
|
||||||
|
'firmware.json',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($jsonFiles as $json) {
|
||||||
|
if (file_exists($json)) {
|
||||||
|
unlink($json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpZip = sys_get_temp_dir() . '/restore.zip';
|
||||||
|
|
||||||
|
$upload = $_FILES['shree_bhattji_encoder'];
|
||||||
|
|
||||||
|
if ($upload['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
die('Upload failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathinfo($upload['name'], PATHINFO_EXTENSION) !== 'bin') {
|
||||||
|
die('Invalid file type');
|
||||||
|
}
|
||||||
|
|
||||||
|
$privateKeyPem = file_get_contents('/var/www/backup_private.pem');
|
||||||
|
if (!$privateKeyPem) {
|
||||||
|
die('Private key not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$privateKey = openssl_pkey_get_private($privateKeyPem);
|
||||||
|
if (!$privateKey) {
|
||||||
|
die('Invalid private key');
|
||||||
|
}
|
||||||
|
|
||||||
|
$payloadRaw = file_get_contents($upload['tmp_name']);
|
||||||
|
$payload = json_decode($payloadRaw, true);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!is_array($payload)
|
||||||
|
|| !isset($payload['key'], $payload['iv'], $payload['data'])
|
||||||
|
) {
|
||||||
|
die('Invalid backup file format');
|
||||||
|
}
|
||||||
|
|
||||||
|
$encryptedKey = base64_decode($payload['key'], true);
|
||||||
|
$iv = base64_decode($payload['iv'], true);
|
||||||
|
$encryptedData = base64_decode($payload['data'], true);
|
||||||
|
|
||||||
|
if ($encryptedKey === false || $iv === false || $encryptedData === false) {
|
||||||
|
die('Corrupt backup data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!openssl_private_decrypt($encryptedKey, $aesKey, $privateKey)) {
|
||||||
|
die('Key mismatch or wrong private key');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zipBinary = openssl_decrypt(
|
||||||
|
$encryptedData,
|
||||||
|
'AES-256-CBC',
|
||||||
|
$aesKey,
|
||||||
|
OPENSSL_RAW_DATA,
|
||||||
|
$iv
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($zipBinary === false) {
|
||||||
|
die('Failed to decrypt data');
|
||||||
|
}
|
||||||
|
$tmpZip = sys_get_temp_dir() . '/restore_' . uniqid() . '.zip';
|
||||||
|
file_put_contents($tmpZip, $zipBinary);
|
||||||
|
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
if ($zip->open($tmpZip) !== true) {
|
||||||
|
unlink($tmpZip);
|
||||||
|
die('Invalid ZIP archive');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->extractTo(__DIR__); // overwrites existing JSON
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
function confirmReboot() {
|
||||||
|
return confirm("Are you sure you want to reboot?");
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmReset() {
|
||||||
|
return confirm("All settings will be gone . Are you sure you want to reset ?");
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmUpdate() {
|
||||||
|
return confirm("Newer version will be downloaded and installed Do not turn off power .");
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmbackup() {
|
||||||
|
return confirm("Are you sure you want to download backup ? ");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
Device ID :- <?php echo trim(file_get_contents('/sys/class/dmi/id/product_uuid')); ?><br>
|
||||||
|
Project Name :- URMI Universal Encoder / Decoder<br>
|
||||||
|
Software Version :- <?php echo $version; ?> <br>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<form method="post" class="form-center">
|
||||||
|
<button type="submit" name="action" value="backup" class="green-btn">Download Backup File</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<form method="post" class="form-center" onsubmit="return confirmReboot();">
|
||||||
|
<button type="submit" name="action" value="reboot" class="green-btn">Reboot</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<form method="post" class="form-center" onsubmit="return confirmReset();">
|
||||||
|
<button type="submit" name="action" value="reset" class="red-btn">Reset Settings</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<form method="post" class="form-center">
|
||||||
|
<button type="submit" name="action" value="update" class="red-btn">Update Firmware</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<form method="post" class="form-center" enctype="multipart/form-data"
|
||||||
|
onsubmit="return confirm('Are you sure you want to restore using this file ? All settings will be restored as per backup file .')">
|
||||||
|
|
||||||
|
<label>Select restore file (.bin only):</label><br><br>
|
||||||
|
|
||||||
|
<input type="file"
|
||||||
|
name="shree_bhattji_encoder"
|
||||||
|
accept=".bin"
|
||||||
|
required><br><br>
|
||||||
|
|
||||||
|
<button type="submit" name="action" value="restore" class="red-btn">Restore</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<footer class="site-footer">
|
||||||
|
Crafted with ❤️ by ShreeBhattJi ( Devdatt Bhatt ) • +91-8000-74-1919
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,408 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$ALLOWED_IP = '172.16.111.112';
|
||||||
|
$clientIp = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||||
|
|
||||||
|
$usersFile = '/var/www/users.json';
|
||||||
|
|
||||||
|
/* ---------- helpers ---------- */
|
||||||
|
function load_json(string $file): array {
|
||||||
|
return is_file($file) ? json_decode(file_get_contents($file), true) ?: [] : [];
|
||||||
|
}
|
||||||
|
function save_json(string $file, array $data): void {
|
||||||
|
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- CSRF ---------- */
|
||||||
|
if (empty($_SESSION['csrf'])) {
|
||||||
|
$_SESSION['csrf'] = bin2hex(random_bytes(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
/* ---------- HANDLE RESET ---------- */
|
||||||
|
if ($clientIp === $ALLOWED_IP && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
|
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
|
||||||
|
http_response_code(400);
|
||||||
|
die('Invalid request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$username = strtolower(trim($_POST['username'] ?? ''));
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
$confirm = $_POST['confirm'] ?? '';
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-z0-9_]{3,32}$/', $username)) {
|
||||||
|
$error = 'Invalid username format.';
|
||||||
|
} elseif (strlen($password) < 8) {
|
||||||
|
$error = 'Password must be at least 8 characters.';
|
||||||
|
} elseif ($password !== $confirm) {
|
||||||
|
$error = 'Passwords do not match.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
$users = load_json($usersFile);
|
||||||
|
$users[$username] = [
|
||||||
|
'password' => password_hash($password, PASSWORD_DEFAULT)
|
||||||
|
];
|
||||||
|
save_json($usersFile, $users);
|
||||||
|
$success = 'Username and password reset successfully.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>URMIC powred by Shreebhattji</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-1: #0f172a;
|
||||||
|
--bg-2: #1d4ed8;
|
||||||
|
--bg-3: #22c55e;
|
||||||
|
--accent: #f97316;
|
||||||
|
--text-main: #f9fafb;
|
||||||
|
--text-muted: #cbd5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
sans-serif;
|
||||||
|
color: var(--text-main);
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, #22c55e33, transparent 60%),
|
||||||
|
radial-gradient(circle at bottom right, #f9731633, transparent 65%),
|
||||||
|
linear-gradient(135deg, var(--bg-1), var(--bg-2));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrap {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rain-container {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raindrop {
|
||||||
|
position: absolute;
|
||||||
|
width: 2px;
|
||||||
|
height: 70px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(255, 255, 255, 0.9),
|
||||||
|
rgba(255, 255, 255, 0)
|
||||||
|
);
|
||||||
|
opacity: 0.55;
|
||||||
|
border-radius: 999px;
|
||||||
|
filter: blur(0.3px);
|
||||||
|
animation-name: fall;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fall {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(0, -120px, 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 110vh, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 720px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2.5rem 2rem;
|
||||||
|
border-radius: 1.75rem;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.6);
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(15, 23, 42, 0.9),
|
||||||
|
rgba(15, 23, 42, 0.7)
|
||||||
|
)
|
||||||
|
border-box;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
box-shadow:
|
||||||
|
0 20px 60px rgba(15, 23, 42, 0.7),
|
||||||
|
0 0 0 1px rgba(15, 23, 42, 0.9);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0.25rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: var(--text-main);
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(59, 130, 246, 0.6),
|
||||||
|
rgba(34, 197, 94, 0.75)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-dot {
|
||||||
|
width: 0.35rem;
|
||||||
|
height: 0.35rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #bbf7d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(2.1rem, 4vw, 2.8rem);
|
||||||
|
line-height: 1.08;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 span.highlight {
|
||||||
|
font-size: clamp(1.1rem, 2vw, 1.8rem);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
#22c55e,
|
||||||
|
#a855f7,
|
||||||
|
#f97316
|
||||||
|
);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.subtitle {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
max-width: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.65rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
padding: 0.35rem 0.8rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.8);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at top left,
|
||||||
|
rgba(59, 130, 246, 0.22),
|
||||||
|
rgba(15, 23, 42, 0.7)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand span {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-bottom: 1px dashed rgba(148, 163, 184, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.card {
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.footer {
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="rain-container" id="rain"></div>
|
||||||
|
|
||||||
|
<div class="page-wrap">
|
||||||
|
<main class="card">
|
||||||
|
|
||||||
|
<div class="badge">
|
||||||
|
<span class="badge-dot"></span>
|
||||||
|
<span>Password Recovery</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Universal Encoder / Decoder
|
||||||
|
<span class="highlight">powred by Shreebhattji</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<?php if ($clientIp !== $ALLOWED_IP): ?>
|
||||||
|
|
||||||
|
<p class="subtitle">
|
||||||
|
Set you computer ip to <strong>172.16.111.112</strong> then
|
||||||
|
Connect USB dongle to encoder and visit
|
||||||
|
<strong>172.16.111.111</strong> for password reset
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<p style="color:#fca5a5"><?= htmlspecialchars($error) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($success): ?>
|
||||||
|
<p style="color:#86efac"><?= htmlspecialchars($success) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form method="post" autocomplete="off" style="display:flex;flex-direction:column;gap:0.75rem">
|
||||||
|
|
||||||
|
<input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
placeholder="New Username"
|
||||||
|
required
|
||||||
|
style="padding:0.7rem;border-radius:0.5rem;border:none"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
placeholder="New Password"
|
||||||
|
required
|
||||||
|
style="padding:0.7rem;border-radius:0.5rem;border:none"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="confirm"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
required
|
||||||
|
style="padding:0.7rem;border-radius:0.5rem;border:none"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
style="padding:0.75rem;border-radius:0.6rem;border:none;
|
||||||
|
background:#22c55e;color:#000;font-weight:600">
|
||||||
|
Reset Credentials
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== YOUR RAIN SCRIPT (UNCHANGED) ===== -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const container = document.getElementById("rain");
|
||||||
|
|
||||||
|
function generateRain() {
|
||||||
|
if (!container) return;
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
const width = window.innerWidth;
|
||||||
|
const height = window.innerHeight;
|
||||||
|
let drops = Math.floor(width * 0.16);
|
||||||
|
|
||||||
|
if (window.innerWidth < 600) drops = Math.floor(width * 0.10);
|
||||||
|
else if (window.innerWidth > 1400) drops = Math.floor(width * 0.18);
|
||||||
|
|
||||||
|
for (let i = 0; i < drops; i++) {
|
||||||
|
const drop = document.createElement("span");
|
||||||
|
drop.className = "raindrop";
|
||||||
|
drop.style.left = Math.random() * 100 + "vw";
|
||||||
|
drop.style.top = -120 - Math.random() * height * 0.3 + "px";
|
||||||
|
drop.style.animationDuration = (0.7 + Math.random() * 1.2) + "s";
|
||||||
|
drop.style.animationDelay = (Math.random() * -3) + "s";
|
||||||
|
drop.style.opacity = (0.35 + Math.random() * 0.55).toFixed(2);
|
||||||
|
container.appendChild(drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resizeTimer;
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
clearTimeout(resizeTimer);
|
||||||
|
resizeTimer = setTimeout(generateRain, 180);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", generateRain);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,459 @@
|
||||||
|
<?php
|
||||||
|
require 'require_login.php';
|
||||||
|
include 'static.php';
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>ShreeBhattJi</title>
|
||||||
|
<script src="chart.js"></script>
|
||||||
|
<style>
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--header-h: 64px;
|
||||||
|
--header-bg: linear-gradient(90deg, #1e293b, #0f172a);
|
||||||
|
--header-color: #e6eef8;
|
||||||
|
--footer-h: 52px;
|
||||||
|
--footer-bg: linear-gradient(90deg, #1e293b, #0f172a);
|
||||||
|
--footer-color: #e6eef8;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
height: calc(100vh - var(--header-h) - var(--footer-h));
|
||||||
|
overflow: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
padding: 16px;
|
||||||
|
padding-bottom: calc(var(--footer-h) + 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 12px auto;
|
||||||
|
padding: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 24px rgba(2, 6, 23, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.containerindex {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 12px auto;
|
||||||
|
padding: 12px;
|
||||||
|
padding-top: 160px;
|
||||||
|
/* Adjusted for multiple headers */
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 24px rgba(2, 6, 23, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
flex: 1 1 43%;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.02));
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.wide {
|
||||||
|
flex-basis: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card h3 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .chart-wrap {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 180px;
|
||||||
|
height: 247px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row {
|
||||||
|
margin-top: 12px;
|
||||||
|
color: #9fb2d6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
:root {
|
||||||
|
--header-h: 56px;
|
||||||
|
--footer-h: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .chart-wrap {
|
||||||
|
height: 220px;
|
||||||
|
min-height: 160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-footer {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: var(--footer-h);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 32px;
|
||||||
|
background: var(--footer-bg);
|
||||||
|
color: var(--footer-color);
|
||||||
|
z-index: 999;
|
||||||
|
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.18);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === MULTIPLE TOP HEADERS === */
|
||||||
|
.top-header-1 {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #e6eef8;
|
||||||
|
font-size: 17px;
|
||||||
|
z-index: 1001;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-header-2 {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #e6eef8;
|
||||||
|
font-size: 14px;
|
||||||
|
z-index: 1001;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-header-1 {
|
||||||
|
top: 0;
|
||||||
|
background: #0f172a;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-header-2 {
|
||||||
|
position: fixed;
|
||||||
|
top: 50px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: var(--footer-h, 73px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 48px;
|
||||||
|
margin-bottom: 57px;
|
||||||
|
background: linear-gradient(90deg, #0f172a, #1e293b);
|
||||||
|
color: #e6eef8;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
z-index: 999;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-header-2 nav a {
|
||||||
|
margin-left: 28px;
|
||||||
|
color: #e6eef8;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === MAIN NAV HEADER === */
|
||||||
|
.site-header {
|
||||||
|
position: fixed;
|
||||||
|
top: 90px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: var(--footer-h, 73px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 48px;
|
||||||
|
margin-bottom: 57px;
|
||||||
|
background: linear-gradient(90deg, #0f172a, #1e293b);
|
||||||
|
color: #e6eef8;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
z-index: 999;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header nav a {
|
||||||
|
margin-left: 28px;
|
||||||
|
color: #e6eef8;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header nav a:hover {
|
||||||
|
color: #38bdf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown select {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
color: black;
|
||||||
|
padding: 12px 40px 12px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown select:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown::after {
|
||||||
|
content: "▼";
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
pointer-events: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown select option {
|
||||||
|
background: #ffffff;
|
||||||
|
color: #1e293b;
|
||||||
|
padding: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
position: relative;
|
||||||
|
width: auto;
|
||||||
|
min-width: 333px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 11px 11px;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 8px;
|
||||||
|
outline: none;
|
||||||
|
background: white;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus {
|
||||||
|
border-color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group label {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 13px;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: 0.3s ease all;
|
||||||
|
background: white;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus+label,
|
||||||
|
.input-group input:not(:placeholder-shown)+label {
|
||||||
|
top: -6px;
|
||||||
|
left: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group input[type="checkbox"] {
|
||||||
|
accent-color: #3b82f6;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1e293b;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green-btn {
|
||||||
|
background-color: green;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
width: 33%;
|
||||||
|
border-radius: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-btn {
|
||||||
|
background-color: red;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
width: 33%;
|
||||||
|
border-radius: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-btn:hover {
|
||||||
|
background-color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.social-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
.social-btn {
|
||||||
|
width: 67px;
|
||||||
|
height: 67px;
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: transform .12s, box-shadow .12s;
|
||||||
|
}
|
||||||
|
.social-btn:hover { transform: translateY(-3px); box-shadow: 0 6px 18px rgba(0,0,0,.08); }
|
||||||
|
.social-btn svg { width: 22px; height: 22px; display: block; }
|
||||||
|
.sr-only { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Three stacked headers -->
|
||||||
|
<header class="top-header-1"><a href="index.php" style="color:white; text-decoration:none;">URMI Universal Digital Encoder / Decoder</a></header>
|
||||||
|
<header class="top-header-2">
|
||||||
|
<nav aria-label="Top navigation">
|
||||||
|
<a href="https://learn.urmic.org/" target="_blank">Tutorials</a>
|
||||||
|
<a href="about_us.php">About Us</a>
|
||||||
|
<a href="contact_us.php">Contact Us ( Free Service )</a>
|
||||||
|
<a href="premium_service.php">Premium Service</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Main navigation header -->
|
||||||
|
<header class="site-header">
|
||||||
|
<nav aria-label="Top navigation">
|
||||||
|
<a href="status.php">Status</a>
|
||||||
|
<a href="index.php">Monitor</a>
|
||||||
|
<a href="firewall.php">Firewall</a>
|
||||||
|
<a href="firmware.php">Firmware</a>
|
||||||
|
<a href="password.php">Password</a>
|
||||||
|
<a href="logout.php">Logout</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,337 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>URMIC powred by Shreebhattji</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-1: #0f172a;
|
||||||
|
--bg-2: #1d4ed8;
|
||||||
|
--bg-3: #22c55e;
|
||||||
|
--accent: #f97316;
|
||||||
|
--text-main: #f9fafb;
|
||||||
|
--text-muted: #cbd5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
sans-serif;
|
||||||
|
color: var(--text-main);
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, #22c55e33, transparent 60%),
|
||||||
|
radial-gradient(circle at bottom right, #f9731633, transparent 65%),
|
||||||
|
linear-gradient(135deg, var(--bg-1), var(--bg-2));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrap {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rain-container {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raindrop {
|
||||||
|
position: absolute;
|
||||||
|
width: 2px;
|
||||||
|
height: 70px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(255, 255, 255, 0.9),
|
||||||
|
rgba(255, 255, 255, 0)
|
||||||
|
);
|
||||||
|
opacity: 0.55;
|
||||||
|
border-radius: 999px;
|
||||||
|
filter: blur(0.3px);
|
||||||
|
animation-name: fall;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fall {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(0, -120px, 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 110vh, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 720px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2.5rem 2rem;
|
||||||
|
border-radius: 1.75rem;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.6);
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(15, 23, 42, 0.9),
|
||||||
|
rgba(15, 23, 42, 0.7)
|
||||||
|
)
|
||||||
|
border-box;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
box-shadow:
|
||||||
|
0 20px 60px rgba(15, 23, 42, 0.7),
|
||||||
|
0 0 0 1px rgba(15, 23, 42, 0.9);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0.25rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: var(--text-main);
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(59, 130, 246, 0.6),
|
||||||
|
rgba(34, 197, 94, 0.75)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-dot {
|
||||||
|
width: 0.35rem;
|
||||||
|
height: 0.35rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #bbf7d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(2.1rem, 4vw, 2.8rem);
|
||||||
|
line-height: 1.08;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 span.highlight {
|
||||||
|
font-size: clamp(1.1rem, 2vw, 1.8rem);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
#22c55e,
|
||||||
|
#a855f7,
|
||||||
|
#f97316
|
||||||
|
);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.subtitle {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
max-width: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.65rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
padding: 0.35rem 0.8rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.8);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at top left,
|
||||||
|
rgba(59, 130, 246, 0.22),
|
||||||
|
rgba(15, 23, 42, 0.7)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand span {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-bottom: 1px dashed rgba(148, 163, 184, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.card {
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.footer {
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="rain-container" id="rain"></div>
|
||||||
|
|
||||||
|
<div class="page-wrap">
|
||||||
|
<main class="card">
|
||||||
|
<div class="badge">
|
||||||
|
<span class="badge-dot"></span>
|
||||||
|
<span>Any format to any format</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Universal Encoder / Decoder
|
||||||
|
<span class="highlight">powred by Shreebhattji</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="subtitle">
|
||||||
|
Full Free Taining
|
||||||
|
</p>
|
||||||
|
<p class="subtitle">
|
||||||
|
10 Year Long Term Software Support
|
||||||
|
</p>
|
||||||
|
<p class="subtitle">
|
||||||
|
Industry wide format support
|
||||||
|
</p>
|
||||||
|
<p class="subtitle">
|
||||||
|
Wordwide availibility of hardware via hardware partners
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="pill-row">
|
||||||
|
<span class="pill"><a style="color: #ffffff;" href="https://www.facebook.com/WorldwideDigitalAssociation/">Facebook</a></span>
|
||||||
|
<span class="pill"><a style="color: #ffffff;" href="https://www.linkedin.com/in/dbhatt-org/">Linkedin</a></span>
|
||||||
|
<span class="pill"><a style="color: #ffffff;" href="https://wa.me/+918000741919">What's app</a></span>
|
||||||
|
<span class="pill"><a style="color: #ffffff;" href="mailto:hello@urmic.org">Email</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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<div class="brand">
|
||||||
|
URMIC • <span>Shreebhattji</span>
|
||||||
|
</div>
|
||||||
|
<div class="links">
|
||||||
|
<a href="https://urmic.org/trusted-partners/" class="link">Meet Out Partners</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const container = document.getElementById("rain");
|
||||||
|
|
||||||
|
function generateRain() {
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
// Density: more width -> more raindrops
|
||||||
|
const width = window.innerWidth;
|
||||||
|
const height = window.innerHeight;
|
||||||
|
|
||||||
|
const baseDensity = 0.16; // drops per vw
|
||||||
|
let drops = Math.floor(width * baseDensity);
|
||||||
|
|
||||||
|
if (window.innerWidth < 600) {
|
||||||
|
drops = Math.floor(width * 0.10);
|
||||||
|
} else if (window.innerWidth > 1400) {
|
||||||
|
drops = Math.floor(width * 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < drops; i++) {
|
||||||
|
const drop = document.createElement("span");
|
||||||
|
drop.className = "raindrop";
|
||||||
|
|
||||||
|
const left = Math.random() * 100; // vw
|
||||||
|
const delay = Math.random() * -3; // negative so it’s already falling
|
||||||
|
const duration = 0.7 + Math.random() * 1.2; // seconds
|
||||||
|
const offsetY = Math.random() * height * 0.3;
|
||||||
|
|
||||||
|
drop.style.left = left + "vw";
|
||||||
|
drop.style.top = -120 - offsetY + "px";
|
||||||
|
drop.style.animationDuration = duration + "s";
|
||||||
|
drop.style.animationDelay = delay + "s";
|
||||||
|
drop.style.opacity = (0.35 + Math.random() * 0.55).toFixed(2);
|
||||||
|
|
||||||
|
container.appendChild(drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic debounce for resize
|
||||||
|
let resizeTimer = null;
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
clearTimeout(resizeTimer);
|
||||||
|
resizeTimer = setTimeout(generateRain, 180);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", generateRain);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card">
|
||||||
|
<h3>CPU (%)</h3>
|
||||||
|
<div class="chart-wrap"><canvas id="cpuChart"></canvas></div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>RAM (%)</h3>
|
||||||
|
<div class="chart-wrap"><canvas id="ramChart"></canvas></div>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Network (KB/s)</h3>
|
||||||
|
<div class="chart-wrap"><canvas id="netChart"></canvas></div>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Disk I/O (KB/s) & Disk %</h3>
|
||||||
|
<div class="chart-wrap"><canvas id="diskChart"></canvas></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:12px; color:#9fb2d6; display:flex; justify-content:space-between;">
|
||||||
|
<div>Last update: <span id="lastUpdate">—</span></div>
|
||||||
|
<div>CPU: <span id="lastCpu">—</span>% · RAM: <span id="lastRam">—</span>% · In: <span id="lastIn">—</span>KB/s ·
|
||||||
|
Out: <span id="lastOut">—</span>KB/s</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const POLL_MS = 1000;
|
||||||
|
const JSON_URL = "metrics.json";
|
||||||
|
|
||||||
|
function toKB(v) {
|
||||||
|
return Math.round(v / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cpuChart = new Chart(document.getElementById('cpuChart').getContext('2d'), {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
label: 'CPU %',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const ramChart = new Chart(document.getElementById('ramChart').getContext('2d'), {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
label: 'RAM %',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const netChart = new Chart(document.getElementById('netChart').getContext('2d'), {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
label: 'Net In (KB/s)',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Net Out (KB/s)',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const diskChart = new Chart(document.getElementById('diskChart').getContext('2d'), {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
label: 'Disk Read (KB/s)',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Disk Write (KB/s)',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Disk %',
|
||||||
|
data: [],
|
||||||
|
yAxisID: 'percent',
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
position: 'left',
|
||||||
|
beginAtZero: true
|
||||||
|
},
|
||||||
|
percent: {
|
||||||
|
position: 'right',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
callback: v => v + '%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function update() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(JSON_URL + "?_=" + Date.now(), {
|
||||||
|
cache: 'no-store'
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error('fetch fail ' + res.status);
|
||||||
|
const j = await res.json();
|
||||||
|
|
||||||
|
const labels = j.timestamps.map(t => new Date(t).toLocaleTimeString());
|
||||||
|
cpuChart.data.labels = labels;
|
||||||
|
cpuChart.data.datasets[0].data = j.cpu_percent;
|
||||||
|
|
||||||
|
ramChart.data.labels = labels;
|
||||||
|
ramChart.data.datasets[0].data = j.ram_percent;
|
||||||
|
|
||||||
|
netChart.data.labels = labels;
|
||||||
|
netChart.data.datasets[0].data = j.net_in_Bps.map(toKB);
|
||||||
|
netChart.data.datasets[1].data = j.net_out_Bps.map(toKB);
|
||||||
|
|
||||||
|
diskChart.data.labels = labels;
|
||||||
|
diskChart.data.datasets[0].data = j.disk_read_Bps.map(toKB);
|
||||||
|
diskChart.data.datasets[1].data = j.disk_write_Bps.map(toKB);
|
||||||
|
diskChart.data.datasets[2].data = j.disk_percent;
|
||||||
|
|
||||||
|
cpuChart.update();
|
||||||
|
ramChart.update();
|
||||||
|
netChart.update();
|
||||||
|
diskChart.update();
|
||||||
|
|
||||||
|
const last = labels.length - 1;
|
||||||
|
if (last >= 0) {
|
||||||
|
document.getElementById('lastUpdate').textContent = labels[last];
|
||||||
|
document.getElementById('lastCpu').textContent = j.cpu_percent[last];
|
||||||
|
document.getElementById('lastRam').textContent = j.ram_percent[last];
|
||||||
|
document.getElementById('lastIn').textContent = toKB(j.net_in_Bps[last]);
|
||||||
|
document.getElementById('lastOut').textContent = toKB(j.net_out_Bps[last]);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('update failed', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(update, POLL_MS);
|
||||||
|
update();
|
||||||
|
</script>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,441 @@
|
||||||
|
<?php
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
|
header('Expires: 0');
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
if (!empty($_SESSION['user'])) {
|
||||||
|
header('Location: /index.php', true, 302);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
/* ---------- CONFIG ---------- */
|
||||||
|
$usersFile = '/var/www/users.json';
|
||||||
|
$attemptsFile = '/var/www/attempts.json';
|
||||||
|
|
||||||
|
$MAX_ATTEMPTS = 3;
|
||||||
|
$LOCK_TIME = 3600;
|
||||||
|
|
||||||
|
/* ---------- HELPERS ---------- */
|
||||||
|
function client_ip(): string
|
||||||
|
{
|
||||||
|
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_json($file): array
|
||||||
|
{
|
||||||
|
return is_file($file) ? json_decode(file_get_contents($file), true) ?: [] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_json($file, $data): void
|
||||||
|
{
|
||||||
|
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- CSRF ---------- */
|
||||||
|
if (empty($_SESSION['csrf'])) {
|
||||||
|
$_SESSION['csrf'] = bin2hex(random_bytes(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- RATE LIMIT ---------- */
|
||||||
|
$ip = client_ip();
|
||||||
|
$attempts = load_json($attemptsFile);
|
||||||
|
|
||||||
|
if (isset($attempts[$ip])) {
|
||||||
|
if (
|
||||||
|
$attempts[$ip]['count'] >= $MAX_ATTEMPTS &&
|
||||||
|
time() - $attempts[$ip]['last'] < $LOCK_TIME
|
||||||
|
) {
|
||||||
|
http_response_code(429);
|
||||||
|
die("Too many attempts. Try again later.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- LOGIN ---------- */
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
|
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
|
||||||
|
http_response_code(400);
|
||||||
|
die('Invalid request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$username = trim($_POST['username'] ?? '');
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
if (empty($_POST['agree'])) {
|
||||||
|
|
||||||
|
$error = 'You must agree to the Privacy Policy and Terms & Conditions.';
|
||||||
|
echo '<script>alert("'
|
||||||
|
. htmlspecialchars($error, ENT_QUOTES)
|
||||||
|
. '");</script>';
|
||||||
|
}
|
||||||
|
$users = load_json($usersFile);
|
||||||
|
|
||||||
|
$valid = isset($users[$username]) &&
|
||||||
|
password_verify($password, $users[$username]['password']);
|
||||||
|
|
||||||
|
if ($valid) {
|
||||||
|
session_regenerate_id(true);
|
||||||
|
unset($attempts[$ip]);
|
||||||
|
save_json($attemptsFile, $attempts);
|
||||||
|
$_SESSION['user'] = $username;
|
||||||
|
header('Location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed login
|
||||||
|
$attempts[$ip]['count'] = ($attempts[$ip]['count'] ?? 0) + 1;
|
||||||
|
$attempts[$ip]['last'] = time();
|
||||||
|
save_json($attemptsFile, $attempts);
|
||||||
|
|
||||||
|
$error = 'Invalid username or password';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>URMIC powred by Shreebhattji</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-1: #0f172a;
|
||||||
|
--bg-2: #1d4ed8;
|
||||||
|
--bg-3: #22c55e;
|
||||||
|
--accent: #f97316;
|
||||||
|
--text-main: #f9fafb;
|
||||||
|
--text-muted: #cbd5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
sans-serif;
|
||||||
|
color: var(--text-main);
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, #22c55e33, transparent 60%),
|
||||||
|
radial-gradient(circle at bottom right, #f9731633, transparent 65%),
|
||||||
|
linear-gradient(135deg, var(--bg-1), var(--bg-2));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrap {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rain-container {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raindrop {
|
||||||
|
position: absolute;
|
||||||
|
width: 2px;
|
||||||
|
height: 70px;
|
||||||
|
background: linear-gradient(to bottom,
|
||||||
|
rgba(255, 255, 255, 0.9),
|
||||||
|
rgba(255, 255, 255, 0));
|
||||||
|
opacity: 0.55;
|
||||||
|
border-radius: 999px;
|
||||||
|
filter: blur(0.3px);
|
||||||
|
animation-name: fall;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fall {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(0, -120px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 110vh, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 720px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2.5rem 2rem;
|
||||||
|
border-radius: 1.75rem;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.6);
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(15, 23, 42, 0.9),
|
||||||
|
rgba(15, 23, 42, 0.7)) border-box;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
box-shadow:
|
||||||
|
0 20px 60px rgba(15, 23, 42, 0.7),
|
||||||
|
0 0 0 1px rgba(15, 23, 42, 0.9);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 0.25rem 0.7rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: var(--text-main);
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
rgba(59, 130, 246, 0.6),
|
||||||
|
rgba(34, 197, 94, 0.75));
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-dot {
|
||||||
|
width: 0.35rem;
|
||||||
|
height: 0.35rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #bbf7d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(2.1rem, 4vw, 2.8rem);
|
||||||
|
line-height: 1.08;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 span.highlight {
|
||||||
|
font-size: clamp(1.1rem, 2vw, 1.8rem);
|
||||||
|
background-image: linear-gradient(120deg,
|
||||||
|
#22c55e,
|
||||||
|
#a855f7,
|
||||||
|
#f97316);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.subtitle {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
max-width: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.65rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
padding: 0.35rem 0.8rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.8);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #e5e7eb;
|
||||||
|
background: radial-gradient(circle at top left,
|
||||||
|
rgba(59, 130, 246, 0.22),
|
||||||
|
rgba(15, 23, 42, 0.7));
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand span {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-bottom: 1px dashed rgba(148, 163, 184, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.card {
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.footer {
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="rain-container" id="rain"></div>
|
||||||
|
|
||||||
|
<div class="page-wrap">
|
||||||
|
<main class="card">
|
||||||
|
|
||||||
|
<h1>Welcome</h1>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<p style="color:#fca5a5"><?= htmlspecialchars($error) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form method="post" autocomplete="off">
|
||||||
|
<input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
|
||||||
|
|
||||||
|
<div style="display:flex;flex-direction:column;gap:0.75rem">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
placeholder="Username"
|
||||||
|
required
|
||||||
|
style="padding:0.7rem;border-radius:0.5rem;border:none" />
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
placeholder="Password"
|
||||||
|
required
|
||||||
|
style="padding:0.7rem;border-radius:0.5rem;border:none" />
|
||||||
|
<label style="display:flex; gap:0.5rem; align-items:flex-start; font-size:0.8rem; color:#e5e7eb;">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="agree"
|
||||||
|
value="1"
|
||||||
|
required
|
||||||
|
style="margin-top:0.15rem">
|
||||||
|
<span>
|
||||||
|
I agree to the
|
||||||
|
<a href="https://urmic.org/2025/12/31/privacy-policy-and-terms-conditions-for-encoder/" target="_blank" class="link">Privacy Policy</a>
|
||||||
|
and
|
||||||
|
<a href="https://urmic.org/2025/12/31/privacy-policy-and-terms-conditions-for-encoder/" target="_blank" class="link">Terms & Conditions</a>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
style="padding:0.75rem;border-radius:0.6rem;border:none;
|
||||||
|
background:#22c55e;color:#000;font-weight:600">
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div style="margin-top:0.75rem">
|
||||||
|
<a href="forgot.php" class="link">Forgot password?</a>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="brand">
|
||||||
|
URMIC • <span>Shreebhattji</span>
|
||||||
|
</div>
|
||||||
|
<div class="links">
|
||||||
|
<a href="https://urmic.org/trusted-partners/" class="link">Meet Out Partners</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
const container = document.getElementById("rain");
|
||||||
|
|
||||||
|
function generateRain() {
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
// Density: more width -> more raindrops
|
||||||
|
const width = window.innerWidth;
|
||||||
|
const height = window.innerHeight;
|
||||||
|
|
||||||
|
const baseDensity = 0.16; // drops per vw
|
||||||
|
let drops = Math.floor(width * baseDensity);
|
||||||
|
|
||||||
|
if (window.innerWidth < 600) {
|
||||||
|
drops = Math.floor(width * 0.10);
|
||||||
|
} else if (window.innerWidth > 1400) {
|
||||||
|
drops = Math.floor(width * 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < drops; i++) {
|
||||||
|
const drop = document.createElement("span");
|
||||||
|
drop.className = "raindrop";
|
||||||
|
|
||||||
|
const left = Math.random() * 100; // vw
|
||||||
|
const delay = Math.random() * -3; // negative so it’s already falling
|
||||||
|
const duration = 0.7 + Math.random() * 1.2; // seconds
|
||||||
|
const offsetY = Math.random() * height * 0.3;
|
||||||
|
|
||||||
|
drop.style.left = left + "vw";
|
||||||
|
drop.style.top = -120 - offsetY + "px";
|
||||||
|
drop.style.animationDuration = duration + "s";
|
||||||
|
drop.style.animationDelay = delay + "s";
|
||||||
|
drop.style.opacity = (0.35 + Math.random() * 0.55).toFixed(2);
|
||||||
|
|
||||||
|
container.appendChild(drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic debounce for resize
|
||||||
|
let resizeTimer = null;
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
clearTimeout(resizeTimer);
|
||||||
|
resizeTimer = setTimeout(generateRain, 180);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", generateRain);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$_SESSION = [];
|
||||||
|
|
||||||
|
if (ini_get('session.use_cookies')) {
|
||||||
|
$p = session_get_cookie_params();
|
||||||
|
setcookie(
|
||||||
|
session_name(),
|
||||||
|
'',
|
||||||
|
time() - 42000,
|
||||||
|
$p['path'],
|
||||||
|
$p['domain'],
|
||||||
|
$p['secure'],
|
||||||
|
$p['httponly']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
session_destroy();
|
||||||
|
|
||||||
|
header('Location: /login.php');
|
||||||
|
exit;
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
include 'header.php';
|
||||||
|
?>
|
||||||
|
<?php
|
||||||
|
$usersFile = '/var/www/users.json';
|
||||||
|
function load_json(string $file): array
|
||||||
|
{
|
||||||
|
return is_file($file) ? json_decode(file_get_contents($file), true) ?: [] : [];
|
||||||
|
}
|
||||||
|
function save_json(string $file, array $data): void
|
||||||
|
{
|
||||||
|
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
|
||||||
|
}
|
||||||
|
if (empty($_SESSION['csrf'])) {
|
||||||
|
$_SESSION['csrf'] = bin2hex(random_bytes(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
$currentUser = $_SESSION['user'];
|
||||||
|
$users = load_json($usersFile);
|
||||||
|
|
||||||
|
if (!isset($users[$currentUser])) {
|
||||||
|
// Safety fallback
|
||||||
|
session_destroy();
|
||||||
|
header('Location: /login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- POST ---------- */
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
|
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
|
||||||
|
http_response_code(400);
|
||||||
|
die('Invalid request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$newUsername = strtolower(trim($_POST['new_username'] ?? ''));
|
||||||
|
$currentPass = $_POST['current_password'] ?? '';
|
||||||
|
$newPass = $_POST['new_password'] ?? '';
|
||||||
|
$confirmPass = $_POST['confirm_password'] ?? '';
|
||||||
|
|
||||||
|
// Verify current password
|
||||||
|
if (!password_verify($currentPass, $users[$currentUser]['password'])) {
|
||||||
|
$error = 'Current password is incorrect.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate new password if provided
|
||||||
|
if (!$error && $newPass !== '') {
|
||||||
|
if (strlen($newPass) < 8) {
|
||||||
|
$error = 'New password must be at least 8 characters.';
|
||||||
|
} elseif ($newPass !== $confirmPass) {
|
||||||
|
$error = 'New passwords do not match.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate new username if provided
|
||||||
|
if (!$error && $newUsername !== '' && $newUsername !== $currentUser) {
|
||||||
|
if (!preg_match('/^[a-z0-9_]{3,32}$/', $newUsername)) {
|
||||||
|
$error = 'Username must be 3–32 chars (a–z, 0–9, underscore).';
|
||||||
|
} elseif (isset($users[$newUsername])) {
|
||||||
|
$error = 'Username already exists.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
// Apply changes
|
||||||
|
$updatedUser = $currentUser;
|
||||||
|
|
||||||
|
if ($newPass !== '') {
|
||||||
|
$users[$currentUser]['password'] =
|
||||||
|
password_hash($newPass, PASSWORD_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($newUsername !== '' && $newUsername !== $currentUser) {
|
||||||
|
$users[$newUsername] = $users[$currentUser];
|
||||||
|
unset($users[$currentUser]);
|
||||||
|
$updatedUser = $newUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_json($usersFile, $users);
|
||||||
|
|
||||||
|
// Update session safely
|
||||||
|
session_regenerate_id(true);
|
||||||
|
$_SESSION['user'] = $updatedUser;
|
||||||
|
|
||||||
|
$success = 'Credentials updated successfully.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Change Username / Password</h3>
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<p style="color:#dc2626"><?= htmlspecialchars($error) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($success): ?>
|
||||||
|
<p style="color:#16a34a"><?= htmlspecialchars($success) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form method="post" autocomplete="off">
|
||||||
|
<input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label>New Username (optional)</label><br>
|
||||||
|
<input type="text" name="new_username" placeholder="leave blank to keep current">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label>Current Password (required)</label><br>
|
||||||
|
<input type="password" name="current_password" required>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label>New Password (optional)</label><br>
|
||||||
|
<input type="password" name="new_password">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label>Confirm New Password</label><br>
|
||||||
|
<input type="password" name="confirm_password">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button type="submit">Update</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,292 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--accent: #0b74de;
|
||||||
|
--muted: #6b7280;
|
||||||
|
--card: #ffffff;
|
||||||
|
--bg: #f3f4f6
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Inter, system-ui, Arial, Helvetica, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: #111;
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 16px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: var(--card);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.06);
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--accent)
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 8px
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #eef2f6;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background: transparent;
|
||||||
|
font-weight: 600
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature {
|
||||||
|
display: flex;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
display: inline-block;
|
||||||
|
background: #eef6ff;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-left: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-primary {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-ghost {
|
||||||
|
border: 1px solid #e6eefa;
|
||||||
|
color: var(--accent)
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefits {
|
||||||
|
margin-top: 18px
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #374151;
|
||||||
|
background: #fff;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 8px
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--muted)
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:600px) {
|
||||||
|
header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin-bottom: 8px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="wrap">
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<section class="benefits">
|
||||||
|
<div class="card">
|
||||||
|
<h3 style="margin-top:0">Why choose hosted streaming over just buying a static IP from your ISP ?</h3>
|
||||||
|
<ul style="margin:8px 0 0 18px">
|
||||||
|
<li><strong>DDoS & attack protection:</strong> Professional hosts run network-level DDoS mitigation and web application firewalls (WAF) that absorb and block large-scale attacks before they reach your origin server.</li>
|
||||||
|
<li><strong>Scalable bandwidth & CDN:</strong> Hosting + CDN provides globally distributed edge points and the ability to scale to many thousands of viewers without saturating a single home/office link.</li>
|
||||||
|
<li><strong>Higher availability & SLA:</strong> Providers operate redundant infrastructure and SLAs that keep streams online even when single links or hardware fail.</li>
|
||||||
|
<li><strong>Managed SSL, domain & DNS:</strong> Automated SSL issuance/renewal (Let's Encrypt), DNS features and a dedicated domain remove operational friction compared to configuring services on a raw ISP IP.</li>
|
||||||
|
<li><strong>Security isolation:</strong> Dedicated servers and hosting accounts isolate your traffic and services from other customers, reducing risks that come with shared consumer-grade network equipment.</li>
|
||||||
|
<li><strong>Monitoring & support:</strong> 24/7 monitoring, alerting and expert support are part of hosting plans — ISPs rarely provide application-level stream support.</li>
|
||||||
|
<li><strong>Optional reserved (static) IPs:</strong> If you still need a static IP for whitelisting, we can provision a reserved IP on a dedicated plan and keep it behind our mitigation/CDN layer.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="note" style="margin-top:12px">
|
||||||
|
<strong>Quick notes:</strong> "Unlimited data for links" refers to stream delivery (no per-GB charge on the plan level for the specified formats). Extremely large egress (multi-TB per month) or abusive usage may require a custom enterprise agreement. CDN bandwidth, archival storage and advanced security may be subject to fair-use or tiered pricing.
|
||||||
|
</div>
|
||||||
|
<div class="note" style="margin-top:12px">
|
||||||
|
<strong>Hosting :</strong> All servers are hosted with our CDN ISP partners. This project aims to transform ISPs into data-center service providers through a hybrid partnership model. All billing is handled directly by the ISP. We found this is lowest letency and stable solutions for broadcastors . Price includes GST and 2 month will be free on yearly payment .
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="cards">
|
||||||
|
<!-- Shared Streaming -->
|
||||||
|
<div class="card">
|
||||||
|
<div style="display:flex;align-items:center;gap:12px;margin-bottom:8px">
|
||||||
|
<div>
|
||||||
|
<div class="muted">Shared Streaming</div>
|
||||||
|
<div class="price">₹2,000 / month</div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-left:auto;text-align:right">
|
||||||
|
<div class="pill">Best for small producers</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Feature</th>
|
||||||
|
<th>Included</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Delivery formats</td>
|
||||||
|
<td>HLS (m3u8), RTMP, SRT, DASH — unlimited data for links</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Bandwidth</td>
|
||||||
|
<td>Shared pool — burst-capable (fair-usage policy)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Domain</td>
|
||||||
|
<td>Subdomain (example.customer.example.com)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSL</td>
|
||||||
|
<td>Let's Encrypt (shared certificate)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Support</td>
|
||||||
|
<td>Email & chat (business hours)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uptime SLA</td>
|
||||||
|
<td>99.5%</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="margin-top:12px;display:flex;gap:8px">
|
||||||
|
<a class="cta cta-primary" href="contact_us.php">Contact Us</a>
|
||||||
|
<a class="cta cta-ghost" href="https://urmic.org/trusted-partners/">Our ISP Partners</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Dedicated Streaming -->
|
||||||
|
<div class="card">
|
||||||
|
<div style="display:flex;align-items:center;gap:12px;margin-bottom:8px">
|
||||||
|
<div>
|
||||||
|
<div class="muted">Dedicated Streaming</div>
|
||||||
|
<div class="price">₹4,000 / month</div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-left:auto;text-align:right">
|
||||||
|
<div class="pill">Recommended for events & scale</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Feature</th>
|
||||||
|
<th>Included</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Delivery formats</td>
|
||||||
|
<td>HLS (m3u8), RTMP, SRT, DASH — unlimited data for links</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Bandwidth</td>
|
||||||
|
<td>Dedicated bandwidth allocation (higher sustained throughput up to 10gbe spike )</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Domain</td>
|
||||||
|
<td>Dedicated domain included (example: yourbrand.live)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SSL</td>
|
||||||
|
<td>Free SSL certificate (Let's Encrypt) + automated renewals</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>DDoS / Attack protection</td>
|
||||||
|
<td>Network-level mitigation & WAF</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Static IP</td>
|
||||||
|
<td>Dedicated ip ipv4 and ipv6 available (reserved IP) — useful for whitelisting</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uptime SLA</td>
|
||||||
|
<td>99.9% with priority support</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Support</td>
|
||||||
|
<td>24/7 priority support & onboarding</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="margin-top:12px;display:flex;gap:8px">
|
||||||
|
<a class="cta cta-primary" href="contact_us.php">Contact Us</a>
|
||||||
|
<a class="cta cta-ghost" href="https://urmic.org/trusted-partners/">Our ISP Partners</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<footer>
|
||||||
|
<div class="muted">Need an exportable copy of this pricing page or custom branding? Contact sales for a tailored quote and SLA.</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
<?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));
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
// auth/require_login.php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
/* ---------- SECURITY HEADERS (optional but recommended) ---------- */
|
||||||
|
header('X-Frame-Options: DENY');
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
header('Referrer-Policy: strict-origin-when-cross-origin');
|
||||||
|
|
||||||
|
/* ---------- LOGIN CHECK ---------- */
|
||||||
|
if (empty($_SESSION['user'])) {
|
||||||
|
|
||||||
|
// Prevent cache of protected pages
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
|
|
||||||
|
header('Location: /login.php', true, 302);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,684 @@
|
||||||
|
<?php include 'header.php'; ?>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$domain = "";
|
||||||
|
$https = false;
|
||||||
|
|
||||||
|
$jsonFile = __DIR__ . '/domain.json';
|
||||||
|
|
||||||
|
if (file_exists($jsonFile)) {
|
||||||
|
$raw = file_get_contents($jsonFile);
|
||||||
|
$data = json_decode($raw, true);
|
||||||
|
$domain = $data['domain'];
|
||||||
|
$https = $data['https'];
|
||||||
|
} else {
|
||||||
|
$domain = $_SERVER['SERVER_NAME'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$jsonFile = __DIR__ . '/output.json';
|
||||||
|
if (file_exists($jsonFile)) {
|
||||||
|
$raw = file_get_contents($jsonFile);
|
||||||
|
$data = json_decode($raw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$service_rtmp0_multiple = $data['service_rtmp0_multiple'];
|
||||||
|
$service_rtmp0_hls = $data['service_rtmp0_hls'];
|
||||||
|
$service_rtmp0_dash = $data['service_rtmp0_dash'];
|
||||||
|
$service_rtmp1_multiple = $data['service_rtmp1_multiple'];
|
||||||
|
$service_rtmp1_hls = $data['service_rtmp1_hls'];
|
||||||
|
$service_rtmp1_dash = $data['service_rtmp1_dash'];
|
||||||
|
$service_srt_multiple = $data['service_srt_multiple'];
|
||||||
|
|
||||||
|
$text = "<h3>Encoder</h3>";
|
||||||
|
$text .= "<h5>http://" . $domain;
|
||||||
|
if ($https) $text .= "<br>https://" . $domain;
|
||||||
|
$text .= "</h5>";
|
||||||
|
|
||||||
|
if ($service_rtmp0_multiple == 'enable') {
|
||||||
|
$text .= "<h5>rtmp://" . $domain . "/shree/bhattji<br>";
|
||||||
|
if ($service_rtmp0_dash == 'enable') {
|
||||||
|
$text .= "http://" . $domain . "/hls/shree/bhattji.m3u8<br>";
|
||||||
|
if ($https) {
|
||||||
|
$text .= "https://" . $domain . "/hls/shree/bhattji.m3u8<br><br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($service_rtmp0_dash == 'enable') {
|
||||||
|
$text .= "http://" . $domain . "/dash/shree/bhattji.mpd<br>";
|
||||||
|
if ($https) {
|
||||||
|
$text .= "https://" . $domain . "/dash/shree/bhattji.mpd<br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$text .= "</h5>";
|
||||||
|
}
|
||||||
|
if ($service_rtmp1_multiple == 'enable') {
|
||||||
|
$text .= "<h5>rtmp://" . $domain . "/shreeshree/bhattji<br>";
|
||||||
|
if ($service_rtmp1_dash == 'enable') {
|
||||||
|
$text .= "http://" . $domain . "/hls/shreeshree/bhattji.m3u8<br>";
|
||||||
|
if ($https) {
|
||||||
|
$text .= "https://" . $domain . "/hls/shreeshree/bhattji.m3u8<br><br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($service_rtmp1_dash == 'enable') {
|
||||||
|
$text .= "http://" . $domain . "/dash/shreeshree/bhattji.mpd<br>";
|
||||||
|
if ($https) {
|
||||||
|
$text .= "https://" . $domain . "/dash/shreeshree/bhattji.mpd<br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$text .= "</h5>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($service_srt_multiple){
|
||||||
|
$text .= "<h5>srt://" . $domain . ":1937?streamid=shree/bhatt/ji</h5><br><br>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
|
if (isset($_POST['action'])) {
|
||||||
|
$data = explode("_", $_POST['action']);
|
||||||
|
|
||||||
|
switch ($data[0]) {
|
||||||
|
case 'main':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl enable encoder-main');
|
||||||
|
exec('sudo systemctl restart encoder-main');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-main');
|
||||||
|
exec('sudo systemctl restart encoder-main');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-main');
|
||||||
|
exec('sudo systemctl disable encoder-main');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'rtmp0':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl enable encoder-rtmp0');
|
||||||
|
exec('sudo systemctl restart encoder-rtmp0');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-rtmp0');
|
||||||
|
exec('sudo systemctl restart encoder-rtmp0');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-rtmp0');
|
||||||
|
exec('sudo systemctl disable encoder-rtmp0');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'rtmp1':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl enable encoder-rtmp1');
|
||||||
|
exec('sudo systemctl restart encoder-rtmp1');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-rtmp1');
|
||||||
|
exec('sudo systemctl restart encoder-rtmp1');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-rtmp1');
|
||||||
|
exec('sudo systemctl disable encoder-rtmp1');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'srt':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl enable srt');
|
||||||
|
exec('sudo systemctl restart srt');
|
||||||
|
exec('sudo systemctl enable encoder-srt');
|
||||||
|
exec('sudo systemctl restart encoder-srt');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable srt');
|
||||||
|
exec('sudo systemctl restart srt');
|
||||||
|
exec('sudo systemctl enable encoder-srt');
|
||||||
|
exec('sudo systemctl restart encoder-srt');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-srt');
|
||||||
|
exec('sudo systemctl disable encoder-srt');
|
||||||
|
exec('sudo systemctl stop srt');
|
||||||
|
exec('sudo systemctl disable srt');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'udp0':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl restart encoder-udp0');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-udp0');
|
||||||
|
exec('sudo systemctl restart encoder-udp0');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-udp0');
|
||||||
|
exec('sudo systemctl disable encoder-udp0');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'udp1':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl restart encoder-udp1');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-udp1');
|
||||||
|
exec('sudo systemctl restart encoder-udp1');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-udp1');
|
||||||
|
exec('sudo systemctl disable encoder-udp1');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'udp2':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl restart encoder-udp2');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-udp2');
|
||||||
|
exec('sudo systemctl restart encoder-udp2');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-udp2');
|
||||||
|
exec('sudo systemctl disable encoder-udp2');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'custom':
|
||||||
|
switch ($data[1]) {
|
||||||
|
case 'restart':
|
||||||
|
exec('sudo systemctl restart encoder-custom');
|
||||||
|
break;
|
||||||
|
case 'enable':
|
||||||
|
exec('sudo systemctl enable encoder-custom');
|
||||||
|
exec('sudo systemctl restart encoder-custom');
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
exec('sudo systemctl stop encoder-custom');
|
||||||
|
exec('sudo systemctl disable encoder-custom');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.card-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-left,
|
||||||
|
.card-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-left {
|
||||||
|
flex: 1 1 55%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-right {
|
||||||
|
flex: 1 1 40%;
|
||||||
|
align-items: flex-end;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 40px 10px 12px;
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
outline: none;
|
||||||
|
background: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: #444;
|
||||||
|
pointer-events: none;
|
||||||
|
/* visual only */
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-enabled {
|
||||||
|
background: #16a34a22;
|
||||||
|
color: #15803d;
|
||||||
|
border: 1px solid #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-disabled {
|
||||||
|
background: #b91c1c22;
|
||||||
|
color: #b91c1c;
|
||||||
|
border: 1px solid #b91c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-buttons button {
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-restart {
|
||||||
|
border-color: #0f172a;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-enable {
|
||||||
|
border-color: #15803d;
|
||||||
|
background: #15803d;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-disable {
|
||||||
|
border-color: #b91c1c;
|
||||||
|
background: #b91c1c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hls-player-wrapper {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #121212;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hls-video {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 70vh;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #000;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hls-video:focus-visible {
|
||||||
|
outline: 2px solid #1e88e5;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.card-right {
|
||||||
|
align-items: flex-start;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="containerindex">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Input Service</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-main 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="main_restart" class="btn-restart">
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="main_disable" class="btn-disable">
|
||||||
|
Disable
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="main_enable" class="btn-enable">
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>RTMP0 Server</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-rtmp0 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="card-right">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="rtmp0_restart" class="btn-restart">Restart</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="rtmp0_disable" class="btn-disable">Disable</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="rtmp0_enable" class="btn-enable">Enable</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>RTMP1 Server</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-rtmp1 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="card-right">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="rtmp1_restart" class="btn-restart">Restart</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="rtmp1_disable" class="btn-disable">Disable</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="rtmp1_enable" class="btn-enable">Enable</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>SRT Server</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-srt 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="card-right">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="srt_restart" class="btn-restart">Restart</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="srt_disable" class="btn-disable">Disable</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="srt_enable" class="btn-enable">Enable</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>Udp0 Service</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-udp0 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="udp0_restart" class="btn-restart">
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="udp0_disable" class="btn-disable">
|
||||||
|
Disable
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="udp0_enable" class="btn-enable">
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>Udp1 Service</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-udp1 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="udp1_restart" class="btn-restart">
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="udp1_disable" class="btn-disable">
|
||||||
|
Disable
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="udp1_enable" class="btn-enable">
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>Udp2 Service</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-udp2 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="udp_restart" class="btn-restart">
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="udp_disable" class="btn-disable">
|
||||||
|
Disable
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="udp_enable" class="btn-enable">
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>Custom Output Service</h3>
|
||||||
|
<?php
|
||||||
|
$status = shell_exec("sudo systemctl is-active encoder-custom 2>&1");
|
||||||
|
$status = trim($status);
|
||||||
|
|
||||||
|
if ($status === "active")
|
||||||
|
$serviceEnabled = true;
|
||||||
|
else
|
||||||
|
$serviceEnabled = false;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="card-row">
|
||||||
|
<div class="service-label">
|
||||||
|
<strong>Service</strong>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<span class="badge badge-enabled">Enabled</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-disabled">Disabled</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="service-buttons">
|
||||||
|
<button type="submit" name="action" value="custom_restart" class="btn-restart">
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<?php if ($serviceEnabled): ?>
|
||||||
|
<button type="submit" name="action" value="custom_disable" class="btn-disable">
|
||||||
|
Disable
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="submit" name="action" value="custom_enable" class="btn-enable">
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card wide">
|
||||||
|
<h3>Output Links</h3>
|
||||||
|
<?php echo $text; ?>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y apache2 php libapache2-mod-php vainfo ufw intel-media-va-driver-non-free libavcodec-extra mesa-utils i965-va-driver libmfx1 intel-gpu-tools ffmpeg v4l-utils python3-pip mpv alsa-utils vlan git zlib1g-dev php-zip php-curl
|
||||||
|
sudo pip3 install psutil --break-system-packages
|
||||||
|
|
||||||
|
cat > /etc/sudoers.d/www-data << 'EOL'
|
||||||
|
www-data ALL=(ALL) NOPASSWD: ALL
|
||||||
|
EOL
|
||||||
|
|
||||||
|
|
||||||
|
cat > /usr/local/bin/nginx_system_monitor_sampler.py<< 'EOL'
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Lightweight sampler for nginx static frontend.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time, json, os
|
||||||
|
from collections import deque
|
||||||
|
from datetime import datetime
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
OUT_FILE = "/var/www/encoder/metrics.json"
|
||||||
|
TMP_FILE = OUT_FILE + ".tmp"
|
||||||
|
SAMPLE_INTERVAL = 10.0 # seconds between samples
|
||||||
|
HISTORY_SECONDS = 15 * 60 # 15 minutes
|
||||||
|
MAX_SAMPLES = int(HISTORY_SECONDS / SAMPLE_INTERVAL)
|
||||||
|
|
||||||
|
# circular buffers
|
||||||
|
timestamps = deque(maxlen=MAX_SAMPLES)
|
||||||
|
cpu_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
ram_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
net_in_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
net_out_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
disk_read_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
disk_write_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
disk_percent_hist = deque(maxlen=MAX_SAMPLES)
|
||||||
|
|
||||||
|
_prev_net = psutil.net_io_counters()
|
||||||
|
_prev_disk = psutil.disk_io_counters()
|
||||||
|
_prev_time = time.time()
|
||||||
|
|
||||||
|
def sample_once():
|
||||||
|
global _prev_net, _prev_disk, _prev_time
|
||||||
|
now = time.time()
|
||||||
|
iso = datetime.fromtimestamp(now).isoformat(timespec='seconds')
|
||||||
|
cpu = psutil.cpu_percent(interval=None)
|
||||||
|
ram = psutil.virtual_memory().percent
|
||||||
|
|
||||||
|
net = psutil.net_io_counters()
|
||||||
|
disk = psutil.disk_io_counters()
|
||||||
|
try:
|
||||||
|
disk_percent = psutil.disk_usage("/").percent
|
||||||
|
except Exception:
|
||||||
|
disk_percent = 0.0
|
||||||
|
|
||||||
|
elapsed = now - _prev_time if _prev_time else SAMPLE_INTERVAL
|
||||||
|
if elapsed <= 0:
|
||||||
|
elapsed = SAMPLE_INTERVAL
|
||||||
|
|
||||||
|
in_rate = int(((net.bytes_recv - _prev_net.bytes_recv) / elapsed) * 8)
|
||||||
|
out_rate = int(((net.bytes_sent - _prev_net.bytes_sent) / elapsed) * 8)
|
||||||
|
|
||||||
|
read_rate = (disk.read_bytes - _prev_disk.read_bytes) / elapsed
|
||||||
|
write_rate = (disk.write_bytes - _prev_disk.write_bytes) / elapsed
|
||||||
|
|
||||||
|
timestamps.append(iso)
|
||||||
|
cpu_hist.append(round(cpu, 2))
|
||||||
|
ram_hist.append(round(ram, 2))
|
||||||
|
net_in_hist.append(int(in_rate))
|
||||||
|
net_out_hist.append(int(out_rate))
|
||||||
|
disk_read_hist.append(int(read_rate))
|
||||||
|
disk_write_hist.append(int(write_rate))
|
||||||
|
disk_percent_hist.append(round(disk_percent, 2))
|
||||||
|
|
||||||
|
_prev_net = net
|
||||||
|
_prev_disk = disk
|
||||||
|
_prev_time = now
|
||||||
|
|
||||||
|
def write_json_atomic():
|
||||||
|
payload = {
|
||||||
|
"timestamps": list(timestamps),
|
||||||
|
"cpu_percent": list(cpu_hist),
|
||||||
|
"ram_percent": list(ram_hist),
|
||||||
|
"net_in_Bps": list(net_in_hist),
|
||||||
|
"net_out_Bps": list(net_out_hist),
|
||||||
|
"disk_read_Bps": list(disk_read_hist),
|
||||||
|
"disk_write_Bps": list(disk_write_hist),
|
||||||
|
"disk_percent": list(disk_percent_hist),
|
||||||
|
"sample_interval": SAMPLE_INTERVAL,
|
||||||
|
"generated_at": datetime.utcnow().isoformat(timespec='seconds') + "Z"
|
||||||
|
}
|
||||||
|
with open(TMP_FILE, "w") as f:
|
||||||
|
json.dump(payload, f)
|
||||||
|
os.replace(TMP_FILE, OUT_FILE)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global _prev_net, _prev_disk, _prev_time
|
||||||
|
_prev_net = psutil.net_io_counters()
|
||||||
|
_prev_disk = psutil.disk_io_counters()
|
||||||
|
_prev_time = time.time()
|
||||||
|
time.sleep(0.2) # warm-up
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
sample_once()
|
||||||
|
write_json_atomic()
|
||||||
|
except Exception as e:
|
||||||
|
# systemd journal will capture prints
|
||||||
|
print("Sampler error:", e)
|
||||||
|
time.sleep(SAMPLE_INTERVAL)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
EOL
|
||||||
|
|
||||||
|
|
||||||
|
cat >/etc/netplan/00-stream.yaml<< 'EOL'
|
||||||
|
network:
|
||||||
|
version: 2
|
||||||
|
renderer: networkd
|
||||||
|
ethernets:
|
||||||
|
eth:
|
||||||
|
match:
|
||||||
|
name: enx*
|
||||||
|
addresses:
|
||||||
|
- 172.16.111.111/24
|
||||||
|
EOL
|
||||||
|
|
||||||
|
sudo cp -r html/* /var/www/html/
|
||||||
|
sudo cp backup_private.pem /var/www/
|
||||||
|
sudo cp backup_public.pem /var/www/
|
||||||
|
sudo cp 00-stream.yaml /var/www/
|
||||||
|
sudo cp attempts.json /var/www/
|
||||||
|
sudo cp users.json /var/www/
|
||||||
|
|
||||||
|
sudo a2enmod ssl
|
||||||
|
sudo systemctl enable apache2
|
||||||
|
sudo systemctl restart apache2
|
||||||
|
sudo a2ensite default-ssl
|
||||||
|
sudo chmod +x /usr/local/bin/nginx_system_monitor_sampler.py
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
sudo chmod 777 -R /var/www
|
||||||
|
sudo chown -R www-data:www-data /var/www
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
sudo chmod 444 /sys/class/dmi/id/product_uuid
|
||||||
|
sudo systemctl disable systemd-networkd-wait-online.service
|
||||||
|
sudo systemctl mask systemd-networkd-wait-online.service
|
||||||
|
|
||||||
|
sudo ufw default allow outgoing
|
||||||
|
sudo ufw default deny incoming
|
||||||
|
sudo ufw allow 80
|
||||||
|
sudo ufw allow 443
|
||||||
|
sudo ufw allow proto udp to 224.0.0.0/4
|
||||||
|
sudo ufw route allow proto udp to 224.0.0.0/4
|
||||||
|
sudo ufw deny out to 239.255.254.254 port 39000 proto udp
|
||||||
|
sudo ufw allow from 172.16.111.112 to 172.16.111.111 port 80
|
||||||
|
sudo ufw allow from 172.16.111.112 to 172.16.111.111 port 443
|
||||||
|
sudo ufw --force enable
|
||||||
|
DEVICE_ID="$(sudo cat /sys/class/dmi/id/product_uuid | tr -d '\n')"
|
||||||
|
sudo sed -i 's/certificatecertificatecertificatecertificate/'$DEVICE_ID'/g' /var/www/html/certification.html
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"shreebhattji": {
|
||||||
|
"password": "$2y$10$BInKRv9mhK69VfYKIi4WVegAs9VWtLhfdZH4YoDk5aE2U61cmyT2a"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue