<?php require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/init.inc"; global $title; global $isLoggedIn; global $lang; global $pages; global $pagename; $computer = []; $parts = explode("/", $pagename); if (isset($parts[1])) { if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/data/computers/metadata/" . $parts[1] . ".json")) { $computer = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/computers/metadata/" . $parts[1] . ".json"), true); $id = $parts[1]; $owner = explode("-", $id)[0]; if (count($parts) > 2) { $title = "Remote control · " . $computer["host"] . " · " . $title; } else { $title = $computer["host"] . " · " . $title; } } else { header("Location: /-/computers"); die(); } } if (isset($parts[2]) && $parts[2] !== "control") { header("Location: /-/computers/" . $parts[1]); die(); } require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.inc'; $parts = array_values(array_filter($parts, function ($i) { return $i !== "-"; })); if (count($parts) === 2 || count($parts) === 3) { array_unshift($parts, null); } ?> <br> <div class="container"> <?php if (isset($parts[2]) && !isset($parts[3])): $id = $parts[2]; ?> <div> <h2> <span style="vertical-align: middle;"><?= $computer["host"] ?></span> <a href="/-/computers" class="small btn btn-outline-light" style="float:right;margin-top:5px;vertical-align:middle;opacity:1 !important; color:white;">Back</a> </h2> <h4 style="margin-top: 20px;margin-bottom: 10px;">Overview</h4> <style> @media (max-width: 700px) { #g-0 { grid-template-columns: 1fr !important; } #g-0 img, #g-0 table { display: inline-block; margin-left: auto; margin-right: auto; } #g-0 table { margin-top: 20px; } } </style> <div style="display: grid; grid-template-columns: 256px 1fr; grid-column-gap: 30px;" id="g-0"> <div style="display: flex; align-items: center;"> <img style="width: 256px;" src="https://ponies.equestria.horse/api/data?f=computers/screens/<?= $id . "-" . $computer["screens"][0]["id"] ?>.jpg"> </div> <div style="display: flex; align-items: center;"> <table> <tbody> <tr> <td style="padding-right: 10px; text-align: right;"><b>Owner:</b></td> <td><?= $owner === "raindrops" ? "Raindrops System" : "Cloudburst System" ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Luna version:</b></td> <td><?= $computer["luna_version"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>System:</b></td> <td><?= $computer["os"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>OS kernel:</b></td> <td><?= $computer["kernel"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Serial:</b></td> <td><?= $computer["serial"] ?> (<?= $computer["serial_source"] === "hardware" ? "logic board" : "OS" ?>)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Last seen:</b></td> <td><?= date('j M, g:ia (T)', strtotime($computer["date"])) ?>, <?= timeAgo($computer["date"]) ?></td> </tr> </tbody> </table> </div> </div> <table><tbody> <tr> <td colspan="2"><h4 style="margin-top: 20px;margin-bottom: 10px;">Processors and graphics</h4></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Main processor:</b></td> <td><?= trim($computer["cpu"]["manufacturer"] . " " . $computer["cpu"]["brand"] . " " . $computer["cpu"]["model"]) ?> (<?= $computer["cpu"]["speed"] ?> GHz)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Processor threading:</b></td> <td> <?= $computer["cpu"]["processors"] ?> processor<?= $computer["cpu"]["processors"] > 1 ? "s" : "" ?>, <?= $computer["cpu"]["physicalCores"] ?> core<?= $computer["cpu"]["physicalCores"] > 1 ? "s" : "" ?><?= isset($computer["cpu"]["efficiencyCores"]) ? " (" . $computer["cpu"]["efficiencyCores"] . " efficiency, " . $computer["cpu"]["performanceCores"] . " performance)" : "" ?>, <?= $computer["cpu"]["cores"] ?> thread<?= $computer["cpu"]["cores"] > 1 ? "s" : "" ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Hardware virtualization:</b></td> <td><?= $computer["cpu"]["virtualization"] ? "Capable" : "Disabled" ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Level 1 cache:</b></td> <td><?= round($computer["cpu"]["cache"]["l1i"] / 1024, 2) ?> KiB (instruction), <?= round($computer["cpu"]["cache"]["l1d"] / 1024, 2) ?> KiB (data)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Level 2 cache:</b></td> <td><?= isset($computer["cpu"]["cache"]["l2"]) ? round($computer["cpu"]["cache"]["l2"] / 1024**2, 2) . " MiB" : "Not supported" ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Level 3 cache:</b></td> <td><?= isset($computer["cpu"]["cache"]["l3"]) ? round($computer["cpu"]["cache"]["l3"] / 1024**2, 2) . " MiB" : "Not supported" ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Graphics processor<?= count($computer["gpu"]["controllers"]) > 1 ? "s" : "" ?>:</b></td> <td> <?php $index = 0; foreach ($computer["gpu"]["controllers"] as $controller): ?> <?= $controller["bus"] ?> <?= $controller["model"] ?> (<?php if (isset($controller["cores"])): ?><?= $controller["cores"] ?> cores, <?php endif; ?><?= $controller["vramDynamic"] ? "dynamic graphics memory" : $controller["vram"] . " MiB" ?>) <?= $index < count($computer["gpu"]["controllers"]) - 1 ? "<br>" : "" ?> <?php $index++; endforeach; ?> </td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Display<?= count($computer["gpu"]["displays"]) > 1 ? "s" : "" ?>:</b></td> <td> <?php $index = 0; foreach ($computer["gpu"]["displays"] as $display): ?> <?= $display["connection"] ?> <?= $display["vendor"] ?> <?= $display["model"] ?> (<?= $display["currentResX"] ?>x<?= $display["currentResY"] ?><?= $display["currentResX"] !== $display["resolutionX"] ? ", native " . $display["resolutionX"] . "x" . $display["resolutionY"] : "" ?>, <?= $display["currentRefreshRate"] ?> Hz) <?= $index < count($computer["gpu"]["controllers"]) - 1 ? "<br>" : "" ?> <?php $index++; endforeach; ?> </td> </tr> <tr> <td colspan="2"><h4 style="margin-top: 20px;margin-bottom: 10px;">System memory</h4></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Physical memory:</b></td> <td><?= round($computer["ram"]["total"] / 1024**3, 2) ?> GiB (<?= round($computer["ram"]["used"] / 1024**2, 2) ?> MiB used, <?= round($computer["ram"]["free"] / 1024**2, 2) ?> MiB free)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Memory usage:</b></td> <td><?= round($computer["ram"]["active"] / 1024**2, 2) ?> MiB active, <?= round($computer["ram"]["available"] / 1024**2, 2) ?> MiB available, <?= round($computer["ram"]["buffcache"] / 1024**2, 2) ?> MiB cache</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Swap memory:</b></td> <td><?= round($computer["ram"]["swaptotal"] / 1024**3, 2) ?> GiB (<?= round($computer["ram"]["swapused"] / 1024**2, 2) ?> MiB used, <?= round($computer["ram"]["swapfree"] / 1024**2, 2) ?> MiB free)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>RAM chips:</b></td> <td> <?php $index = 0; foreach ($computer["ram_chips"] as $chip): ?> <?php if (isset($chip["manufacturer"])): ?><?= $chip["manufacturer"] ?> <?php endif; ?><?= round($chip["size"] / 1024**2, 2) ?> MiB <?= $chip["type"] ?> <?= $index < count($computer["ram_chips"]) - 1 ? "<br>" : "" ?> <?php $index++; endforeach; ?> </td> </tr> <tr> <td colspan="2"><h4 style="margin-top: 20px;margin-bottom: 10px;">Battery</h4></td> </tr> <?php if ($computer["battery"]["hasBattery"]): ?> <tr> <td style="padding-right: 10px; text-align: right;"><b>Battery model:</b></td> <td><?= preg_replace("/ +/", " ", trim($computer["battery"]["manufacturer"] . " " . $computer["battery"]["type"] . " " . $computer["battery"]["model"])) ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Charge level:</b></td> <td><?= $computer["battery"]["percent"] ?>%<?= $computer["battery"]["acConnected"] ? ", plugged in" : "" ?> (<?= round($computer["battery"]["voltage"], 2) ?> V)</td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Cycles:</b></td> <td><?= $computer["battery"]["cycleCount"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Remaining capacity:</b></td> <td><?= $computer["battery"]["currentCapacity"] ?>/<?= $computer["battery"]["maxCapacity"] ?> <?= $computer["battery"]["capacityUnit"] ?> (designed for <?= $computer["battery"]["designedCapacity"] ?> <?= $computer["battery"]["capacityUnit"] ?><?php if ($computer["battery"]["designedCapacity"] > 0): ?>, <?= round(($computer["battery"]["maxCapacity"] / $computer["battery"]["designedCapacity"]) * 100, 2) ?>% left<?php endif; ?>)</td> </tr> <?php else: ?><tr><td colspan="2">This computer does not contain a battery.</td></tr><?php endif; ?> <tr> <td colspan="2"><h4 style="margin-top: 20px;margin-bottom: 10px;">Operating system</h4></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>System:</b></td> <td><?= $computer["os_info"]["distro"] ?> <?= $computer["os_info"]["release"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>CPU architecture:</b></td> <td><?= $computer["os_info"]["arch"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Kernel version:</b></td> <td><?= $computer["os_info"]["kernel"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Code page:</b></td> <td><?= $computer["os_info"]["codepage"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Build number:</b></td> <td><?= $computer["os_info"]["build"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Serial number:</b></td> <td><?= $computer["os_info"]["serial"] ?></td> </tr> <tr> <td style="padding-right: 10px; text-align: right;"><b>Startup interface:</b></td> <td><?= $computer["os_info"]["uefi"] ? "UEFI" : "BIOS (legacy)" ?></td> </tr> <tr> <td colspan="2"><h4 style="margin-top: 20px;margin-bottom: 10px;">Software versions</h4></td> </tr> <?php foreach ($computer["versions"] as $software => $version): if (trim($version) !== "" && $software !== "systemOpensslLib" && $software !== "openssl" && $software !== "node" && $software !== "v8"): ?> <tr> <td style="padding-right: 10px; text-align: right;"><b><?= match ($software) { "kernel" => "OS kernel", "systemOpenssl" => $computer["versions"]["systemOpensslLib"], "npm" => "NPM", "yarn" => "Yarn", "gulp" => "Gulp", "grunt" => "Grunt", "git" => "Git", "tsc" => "TypeScript", "mysql" => "MySQL", "redis" => "Redis", "mongodb" => "MongoDB", "apache" => "Apache HTTPD", "php" => "PHP", "docker" => "Docker", "postfix" => "Postfix SMTP Server", "postgresql" => "PostgreSQL", "perl" => "Perl", "python" => "Python (legacy)", "python3" => "Python", "pip" => "PIP (legacy)", "pip3" => "PIP", "java" => "Java", "gcc" => "C compiler", "virtualbox" => "VirtualBox", "bash" => "Bash", "zsh" => "zsh", "fish" => "Fish", "powershell" => "PowerShell", "dotnet" => ".NET", default => $software, } ?>:</b></td> <td><?= $version ?></td> </tr> <?php endif; endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;" id="screens">Screens</h4> <p id="page-content"> You can remotely control this computer. <a href="./<?= $id ?>/control">Open remote control.</a> </p> <div style="display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px;"> <?php foreach ($computer["screens"] as $screen): ?> <div class="card"> <div class="card-body"> <img style="width: 100%;" src="https://ponies.equestria.horse/api/data?f=computers/screens/<?= $id . "-" . $screen["id"] ?>.jpg"> </div> </div> <?php endforeach; ?> </div> <h4 style="margin-top: 20px;margin-bottom: 10px;" id="windows">Windows</h4> <div style="display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px;"> <?php foreach ($computer["windows"] as $window): ?> <div class="card"> <div class="card-body" style="display: flex; align-items: center;"> <div style="width: 100%;"> <img style="max-width: 100%; max-height: 100%;" src="https://ponies.equestria.horse/api/data?f=computers/windows/<?= $id . "-" . sha1($window["gid"]) ?>.jpg"> <div style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width: 100%; text-align: center; margin-top: 7px; margin-bottom: -7px;"><?= $window["name"] ?></div> </div> </div> </div> <?php endforeach; ?> </div> <h4 style="margin-top: 20px;margin-bottom: 10px;">Sessions</h4> <table class="table"> <thead> <tr> <th scope="col">TTY</th> <th scope="col">Command</th> <th scope="col">User</th> <th scope="col">Open</th> <th scope="col">Type</th> </tr> </thead> <tbody> <?php foreach ($computer["users"] as $user): ?> <tr> <th scope="row"><?= $user["tty"] ?></th> <td><?= str_replace("�", "", $user["command"]) ?></td> <td><?= $user["user"] ?></td> <td><?= $user["date"] . " " . $user["time"] ?></td> <td><?= trim($user["ip"]) === "" || trim($user["ip"]) === ":1" || trim($user["ip"]) === "::1" ? "Local" : "Remote (" . $user["ip"] . ")" ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;">Filesystems</h4> <table class="table"> <thead> <tr> <th scope="col">Device</th> <th scope="col">Mount point</th> <th scope="col">Type</th> <th scope="col">Used</th> <th scope="col">Free</th> <th scope="col">Total</th> </tr> </thead> <tbody> <?php function prettySize($bytes) { if ($bytes > 1024) { if ($bytes > 1024**2) { if ($bytes > 1024**3) { return round($bytes / 1024**3, 1) . " GB"; } else { return round($bytes / 1024**2, 1) . " MB"; } } else { return round($bytes / 1024, 1) . " KB"; } } else { return $bytes . " B"; } } uasort($computer["filesystems"], function ($a, $b) { return $b["use"] - $a["use"]; }); foreach ($computer["filesystems"] as $fs): ?> <tr> <th scope="row"><?= $fs["fs"] ?></th> <td><?= $fs["mount"] ?></td> <td><?= $fs["type"] ?></td> <td><?= prettySize($fs["used"]) ?> (<?= $fs["use"] ?>%)</td> <td><?= prettySize($fs["available"]) ?></td> <td><?= prettySize($fs["size"]) ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;">Audio devices</h4> <table class="table"> <thead> <tr> <th scope="col">Type</th> <th scope="col">Manufacturer</th> <th scope="col">Name</th> <th scope="col">Default</th> <th scope="col">Connection</th> </tr> </thead> <tbody> <?php foreach ($computer["audio"] as $device): ?> <tr> <th scope="row"><?= trim($device["type"]) === "" ? "Device" : $device["type"] ?></th> <td><?= $device["manufacturer"] ?></td> <td><?= $device["name"] ?></td> <td><?= $device["default"] ? "Yes" : "" ?></td> <td><?= trim($device["channel"]) === "" ? "Virtual" : $device["channel"] ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;">Network cards</h4> <table class="table"> <thead> <tr> <th scope="col">Interface</th> <th scope="col">State</th> <th scope="col">IP addresses</th> <th scope="col">MAC address</th> <th scope="col">Type</th> <th scope="col">Internal</th> <th scope="col">Virtual</th> <th scope="col">DHCP</th> </tr> </thead> <tbody> <?php uasort($computer["network"], function ($a, $b) { $statA = match ($a["operstate"]) { "up" => 300, "down" => 200, default => 100 }; $statB = match ($b["operstate"]) { "up" => 300, "down" => 200, default => 100 }; return $statB - $statA; }); foreach ($computer["network"] as $iface): ?> <tr <?= $iface["operstate"] !== "up" ? 'style="opacity:.5;"' : "" ?>> <th scope="row"><?= $iface["ifaceName"] ?></th> <td><?= $iface["operstate"] === "up" ? "Active" : ($iface["operstate"] === "down" ? "Inactive" : "") ?></td> <td><?= trim($iface["ip4"] !== "") ? $iface["ip4"] : "" ?><?= trim($iface["ip6"] !== "") ? (trim($iface["ip4"] !== "") ? ", " : "") . $iface["ip6"] : "" ?></td> <td><?= trim($iface["mac"] !== "") ? $iface["mac"] : "" ?></td> <td><?= $iface["type"] === "wireless" ? "Wireless" : "Wired" ?></td> <td><?= isset($iface["internal"]) && $iface["internal"] ? "Yes" : "" ?></td> <td><?= $iface["virtual"] ? "Yes" : "" ?></td> <td><?= $iface["dhcp"] ? "Yes" : "" ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;">Network connections</h4> <table class="table"> <thead> <tr> <th scope="col">State</th> <th scope="col">Protocol</th> <th scope="col">Source</th> <th scope="col">Destination</th> <th scope="col">Process</th> </tr> </thead> <tbody> <?php foreach ($computer["connections"] as $connection): ?> <tr> <th scope="row"><?= match ($connection["state"]) { "ESTABLISHED" => "Connected", "LISTEN" => "Listening", "CLOSING" => "Terminating", "UNKNOWN" => "?", "LAST_ACK", "FIN_WAIT2" => "Waiting", "TIME_WAIT" => "Waiting", "FIN_WAIT1" => "Closing", "SYN_RECV" => "Received", "SYN_SENT" => "Attempting", default => $connection["state"], } ?></th> <td><?= match ($connection["protocol"]) { "tcp4" => "TCP over IPv4", "tcp6" => "TCP over IPv6", "tcp46" => "TCP over IPv4 and IPv6", "udp4" => "UDP over IPv4", "udp6" => "UDP over IPv6", "udp46" => "UDP over IPv4 and IPv6", default => $connection["protocol"], } ?></td> <td><?= $connection["localAddress"] === "*" ? "<all>" : match ($connection["localAddress"]) { "127.0.0.1" => "<local IPv4>", "::1" => "<local IPv6>", default => $connection["localAddress"], } ?> (port <?= $connection["localPort"] ?>)</td> <td><?php if ($connection["state"] !== "LISTEN"): ?><?= $connection["peerAddress"] === "*" ? "<all>" : match ($connection["peerAddress"]) { "127.0.0.1" => "<local IPv4>", "::1" => "<local IPv6>", default => $connection["localAddress"], } ?> (<?= $connection["peerPort"] ?>)<?php endif; ?></td> <td><?php $f = array_values(array_filter($computer["processes"], function ($i) use ($connection) { return $i["pid"] === $connection["pid"]; })); if (count($f) > 0) { echo($f[0]["name"] . " [" . $connection["pid"] . "]"); } else { echo($connection["pid"]); } ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h4 style="margin-top: 20px;margin-bottom: 10px;">Processes</h4> <table class="table"> <thead> <tr> <th scope="col">PID</th> <th scope="col">Name</th> <th scope="col">CPU</th> <th scope="col">RAM</th> <th scope="col">User</th> <th scope="col">Started</th> </tr> </thead> <tbody> <?php foreach ($computer["processes"] as $process): ?> <tr> <th scope="row"><?= $process["pid"] ?></th> <td><?= $process["name"] ?></td> <td><?= round($process["cpu"], 2) ?>%</td> <td><?= round($process["ram"], 2) ?>%</td> <td><?= $process["user"] ?></td> <td><?= timeAgo($process["date"]) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php elseif (isset($parts[3]) && $parts[3] === "control"): $id = $parts[2]; ?> <div> <h2> <span style="vertical-align: middle;">Remote controlling <?= $computer["host"] ?></span> <a href="/-/computers/<?= $id ?>" class="small btn btn-outline-light" style="float:right;margin-top:5px;vertical-align:middle;opacity:1 !important; color:white;">Back</a> </h2> <div style="display: flex; align-items: center;"> <img id="display" style="max-width: 100%; max-height: 100%; height: 100%; width: 100%; opacity: .5" src="https://ponies.equestria.horse/api/data?f=computers/screens/<?= $id . "-" . $computer["screens"][0]["id"] ?>.jpg"> </div> <div id="commands" style="background: #151515; border: 1px solid #333; margin-top: 10px; border-radius: 10px; font-family: 'JetBrains Mono', monospace; font-size: 14px;"> <div id="output" style="height: 200px; padding: 10px 20px; overflow: auto;"> <pre id="output-text"></pre> <div id="loader" style="display: none;"> <img src="/assets/editor/load.svg" style="width: 36px; vertical-align: middle; margin-left: -8px; margin-top: -8px;" id="loader-img" alt=""> <span id="loader-time" style="vertical-align: middle; opacity: .5; display: inline-block; margin-top: -8px; margin-left: -8px;"> <span id="loader-time-inner"></span> <span id="loader-time-stopper"> | <a id="loader-time-stopper-link" style="cursor: pointer; text-decoration: underline;" onclick="stopCommand();">Stop</a> </span> </span> </div> </div> <div id="entry" style="border-top: 1px solid #333;"> <input type="text" id="command-entry" placeholder="Enter a command" style="width: 100%; color: white; background: transparent; border: none; padding: 10px 20px; outline: none;"> </div> </div> <script> function stopCommand() { ws.send(JSON.stringify({ type: "halt" })); } function scrollToBottom() { document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight; } window.addEventListener("load", () => { document.getElementById("command-entry").value = ""; }); document.getElementById("command-entry").onkeydown = (event) => { if (event.key === "Enter") { event.preventDefault(); let command = document.getElementById("command-entry").value; document.getElementById("command-entry").value = ""; document.getElementById("command-entry").disabled = true; document.getElementById("loader-time").style.display = "none"; document.getElementById("loader").style.display = ""; document.getElementById("output-text").innerHTML += "\n$ " + command.replaceAll(">", ">").replaceAll("<", "<") + "\n"; scrollToBottom(); ws.send(JSON.stringify({ type: "command", value: btoa(command) })); } } document.getElementById("title-bar-action-1").style.display = "none"; window.controlling = false; window.commandRunInterval = null; function connect() { window.ws = new WebSocket("wss://ponies.equestria.horse/_Computers-RemoteControl-EntryPoint/socket"); window.baseLatency = null; ws.addEventListener('open', (data) => { console.log(data); ws.send(JSON.stringify({ type: "client", id: "<?= $id ?>", token: "<?= $_COOKIE['PEH2_SESSION_TOKEN'] ?>" })) }); ws.addEventListener('message', async (_data) => { let data = JSON.parse(await (_data.data.text())); if (data.type === "image") { document.getElementById("display").style.opacity = "1"; document.getElementById("display").src = data.url; if (baseLatency) { ws.send(JSON.stringify({ type: "set_latency", value: Math.abs((new Date().getTime() - data.time) - baseLatency) })); if (Math.abs((new Date().getTime() - data.time) - baseLatency) > 200) { ws.send(JSON.stringify({ type: "reduce_quality" })); } else if (Math.abs((new Date().getTime() - data.time) - baseLatency) < 150) { ws.send(JSON.stringify({ type: "increase_quality" })); } } else { window.baseLatency = Math.abs(new Date().getTime() - data.time); } } else if (data.type === "command_stop") { if (data.code !== 0) { if (data.signal) { if (data.code) { document.getElementById("output-text").innerHTML += "<span style='color: #ff8c8c;'>Command exited with code " + data.code.toString().replaceAll(">", ">").replaceAll("<", "<") + " (caused by " + data.signal.toString().replaceAll(">", ">").replaceAll("<", "<") + ")</span>"; } else { document.getElementById("output-text").innerHTML += "<span style='color: #ff8c8c;'>Command exited with signal " + data.signal.toString().replaceAll(">", ">").replaceAll("<", "<"); } } else { document.getElementById("output-text").innerHTML += "<span style='color: #ff8c8c;'>Command exited with code " + data.code.toString().replaceAll(">", ">").replaceAll("<", "<") + "</span>"; } } clearInterval(window.commandRunInterval); document.getElementById("command-entry").disabled = false; document.getElementById("loader").style.display = "none"; scrollToBottom(); } else if (data.type === "command_start") { document.getElementById("loader-time").style.display = "inline-block"; document.getElementById("loader-time-inner").innerText = ""; window.commandStartTime = new Date().getTime(); window.commandRunInterval = setInterval(() => { document.getElementById("loader-time-inner").innerText = ((new Date().getTime() - window.commandStartTime) / 1000).toFixed(2) + "s"; }, 10); scrollToBottom(); } else if (data.type === "command_stdout" || data.type === "command_stderr") { if (data.type === "command_stderr") { document.getElementById("output-text").innerHTML += "<span style='color: #ffec8c;'>" + atob(data.value).replaceAll(">", ">").replaceAll("<", "<") + "</span>"; } else { document.getElementById("output-text").innerHTML += atob(data.value).replaceAll(">", ">").replaceAll("<", "<"); } scrollToBottom(); } else { console.log(data); } }); ws.addEventListener('close', (data) => { document.getElementById("display").style.opacity = "0.5"; console.log(data); setTimeout(() => { connect(); }, 1000); }); } connect(); document.getElementById("display").addEventListener("mousemove", (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "move_cursor", x: event.offsetX / document.getElementById("display").width, y: event.offsetY / document.getElementById("display").height })); }); document.getElementById("display").addEventListener("click", (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "click", button: 0 })); }); document.getElementById("display").addEventListener("contextmenu", (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "click", button: 1 })); }); document.getElementById("display").addEventListener("auxclick", (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "click", button: 2 })); }); document.body.onkeydown = document.getElementById("display").onkeydown = (event) => { if (window.controlling) event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "keyboard", shift: event.shiftKey, ctrl: event.ctrlKey, meta: event.metaKey, alt: event.altKey, key: event.key })); } document.getElementById("display").ondragstart = (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "move_cursor", x: event.offsetX / document.getElementById("display").width, y: event.offsetY / document.getElementById("display").height })); if (window.controlling) ws.send(JSON.stringify({ type: "start_drag" })); } document.getElementById("display").ondragend = (event) => { event.preventDefault(); if (window.controlling) ws.send(JSON.stringify({ type: "move_cursor", x: event.offsetX / document.getElementById("display").width, y: event.offsetY / document.getElementById("display").height })); if (window.controlling) ws.send(JSON.stringify({ type: "stop_drag" })); } function enableControl() { document.getElementById("title-bar-action-1").style.display = "inline-block"; document.getElementById("title-bar-action-0").style.display = "none"; window.controlling = true; } function disableControl() { document.getElementById("title-bar-action-1").style.display = "none"; document.getElementById("title-bar-action-0").style.display = "inline-block"; window.controlling = false; } </script> <?php else: ?> <div> <h2>Computers</h2> <p>Click on a computer to view information about it (open windows, installed apps, ...).</p> <div class="alert alert-danger"> <b>Luna is not for production.</b> The Luna program version 1.0.0 is considered malware and must not be used on any computer other than a development machine. </div> <!-- <ul class="list-group"> <?php foreach (array_filter(scandir($_SERVER['DOCUMENT_ROOT'] . "/includes/data/computers/metadata"), function ($i) { return !str_starts_with($i, "."); }) as $file): $computer = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/computers/metadata/" . $file), true); $id = substr($file, 0, -5); $owner = explode("-", $id)[0]; ?> <a href="/-/computers/<?= $id ?>" class="list-group-item list-group-item-action" style="display: grid; grid-template-columns: 100px 1fr; grid-column-gap: 10px;"> <div style="display: flex; align-items: center;"> <img style="width: 100px;" src="https://ponies.equestria.horse/api/data?f=computers/screens/<?= $id . "-" . $computer["screens"][0]["id"] ?>.jpg"> </div> <div style="display: flex; align-items: center;"> <div> <b><?= $computer["host"] ?></b> · <?= $computer["os"] ?><br> Owned by <?= $owner === "raindrops" ? "Raindrops System" : "Cloudburst System"; ?><br> Last seen <?= timeAgo($computer["date"]) ?> </div> </div> </a> <?php endforeach; ?> </ul>--> </div> <?php endif; ?> </div> <style> .list-group-item { color: #fff; background-color: #222; border: 1px solid rgba(255, 255, 255, .125); } .list-group-item.disabled { color: #fff; background-color: #222; border-color: rgba(255, 255, 255, .125); opacity: .75; } .list-group-item:hover { background-color: #252525; color: #ddd; } .list-group-item:active, .list-group-item:focus { background-color: #272727; color: #bbb; } .modal-header { border-bottom: 1px solid #353738; } .modal-content { border: 1px solid rgba(255, 255, 255, .2); background-color: #111; } .btn-close { filter: invert(1); } .btn-outline-light:hover { color: black !important; } table { color: white !important; } table * { border-color: rgba(255, 255, 255, .25) !important; } </style> <?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/footer.inc'; ?>