<?php require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/init.inc"; global $title; global $isLoggedIn; global $isLowerLoggedIn; global $lang; global $pages; require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc'; global $_PROFILE; $verified = [ dns_get_record("zephyrheights.equestria.dev", DNS_A)[0]["ip"], dns_get_record("maretimebay.equestria.dev", DNS_A)[0]["ip"], dns_get_record("bridlewood.equestria.dev", DNS_A)[0]["ip"], dns_get_record("cloudsdale.equestria.dev", DNS_A)[0]["ip"], dns_get_record("manehattan.equestria.dev", DNS_A)[0]["ip"], ]; $verifiedNames = [ "Raindrops System", "Raindrops System", "Equestria.dev bridlewood", "Cloudburst System", "Equestria.dev manehattan" ]; ?> <br> <div class="container"> <h1>Sessions</h1> <script>window.devices = {};</script> <p>Here are all the currently open sessions for your account. Clicking on a session will delete it, meaning the device using this session will be logged out.</p> <?php $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])), true); if (isset($data["profile"])): ?> <div class="list-group"> <?php $list = array_filter([...scandir($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens"), ...scandir($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens")], function ($token) { if ($token === "." || $token === "..") return false; $session = file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token) ? json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token), true) : json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . $token), true); return isset($session["last"]) && isset($session["profile"]); }); usort($list, function ($token1, $token2) { $session1 = file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token1) ? json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token1), true) : json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . $token1), true); $session2 = file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token2) ? json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token2), true) : json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . $token2), true); if (isset($session1["last"]) && isset($session2["last"])) { return $session2["last"] - $session1["last"]; } else { return INF; } }); $addressFetchIndex = 0; foreach ($list as $token): $session = file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token) ? json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . $token), true) : json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . $token), true); if (isset($session["profile"]) && isset($session["name"]) && ($session["profile"]["id"] ?? "") === ($_PROFILE["id"] ?? "")): uasort($session["addresses"], function ($a, $b) { return $b - $a; }); ?> <a class="list-group-item list-group-item-action" onclick="logOut("<?= sha1($token) . md5($token) ?>");"> <b><?= $session["name"] ?></b><?php if ($token === $_COOKIE["PEH2_SESSION_TOKEN"]): ?><span style="margin-left: 10px;" class="badge bg-primary">This device</span><?php endif; ?><script>window.devices["<?= sha1($token) . md5($token) ?>"]=JSON.parse(`<?= json_encode([ "name" => trim($session["name"]), "lastIP" => array_keys($session["addresses"])[count(array_keys($session["addresses"])) > 0 ? count(array_keys($session["addresses"])) - 1 : 0] ?? "-", "lastSeen" => timeAgo($session["last"]), "currentDevice" => $token === $_COOKIE["PEH2_SESSION_TOKEN"] ]) ?>`);</script><br> Logged in <?= timeAgo($session["created"]) ?>, last activity <?= timeAgo($session["last"]) ?> <blockquote class="session-bq"> <?php foreach ($session["addresses"] as $address => $last): ?> <?= $address ?><?php if (in_array($address, $verified)): ?><span class="text-success" style="filter: invert(1) hue-rotate(180deg);"> (verified: <?= $verifiedNames[array_search($address, $verified)] ?? "-" ?>)</span><?php else: ?> <span class="text-muted" style="filter: invert(1) hue-rotate(180deg);" id="aft-<?= $addressFetchIndex ?>">(unverified: …)<script> setTimeout(async () => { let json = JSON.parse(await (await fetch("https://api.iplocation.net/?ip=<?= $address ?>")).text()); if ( (json['country_code2'] !== "FR" && json['country_code2'] !== "GB") || (json['isp'] === "Academie Orleans-Tours" && json['isp'] === "Free Mobile SAS" && json['isp'] === "Google One Services" && json['isp'] === "Vodafone Ltd" && json['isp'] === "Telefonica UK Limited") ) { document.getElementById("aft-<?= $addressFetchIndex ?>").classList.remove("text-muted"); document.getElementById("aft-<?= $addressFetchIndex ?>").classList.add("text-danger"); document.getElementById("aft-<?= $addressFetchIndex ?>").innerText = `(unsafe: ${json['isp']}, ${json['country_code2'] === "GB" ? "UK" : json['country_code2']})`; } else { document.getElementById("aft-<?= $addressFetchIndex ?>").innerText = `(unverified: ${json['isp']}, ${json['country_code2'] === "GB" ? "UK" : json['country_code2']})`; } }, 500 * <?= $addressFetchIndex ?>); </script></span><?php $addressFetchIndex++; endif; ?> · <?= timeAgo($last) ?><br> <?php endforeach; ?> </blockquote> </a> <?php endif; endforeach; ?> </div> <?php else: ?> <div class="alert alert-danger"> <b>Error:</b> You cannot use the session manager because your current session is using the old authentication system. Please log out and log in again to continue. </div> <?php endif; ?> </div> <div class="modal fade" id="confirm"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">Log out this device?</h4> <button type="button" class="btn-close" data-bs-toggle="modal"></button> </div> <div class="modal-body"> <p>You are about to log out the following device from your Cold Haze account:</p> <blockquote id="device-bq"> <div> <b>Name:</b> <span id="device-name">-</span><br> <b>Last address:</b> <span id="device-address">-</span><br> <b>Last activity:</b> <span id="device-activity">-</span> </div> </blockquote> <p class="text-danger" id="device-current" style="display: none;">This is the device you are currently using, which means you will get logged out as soon as you click on confirm.</p> <p id="device-normal"></p> <span class="btn btn-success" id="modal-button" style="margin-right: 5px;" onclick="confirm();">Confirm</span><span class="btn btn-outline-secondary" data-bs-toggle="modal">Cancel</span> </div> </div> </div> </div> <script> window.currentSession = null; window.currentDevice = null; window.modal = new bootstrap.Modal(document.getElementById("confirm")); async function confirm() { await fetch("/api/disconnect?id=" + window.currentSession); if (currentDevice.currentDevice) { location.href = "/-/logout"; } else { location.reload(); } } function logOut(id) { window.currentSession = id; window.currentDevice = devices[id]; if (currentDevice.currentDevice) { document.getElementById("device-current").style.display = ""; document.getElementById("device-normal").style.display = "none"; } else { document.getElementById("device-current").style.display = "none"; document.getElementById("device-normal").style.display = ""; } document.getElementById("device-name").innerText = currentDevice.name; document.getElementById("device-address").innerText = currentDevice.lastIP; document.getElementById("device-activity").innerText = currentDevice.lastSeen; modal.show(); } </script> <style> .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); } .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; } .member-link, .list-group-item-action { cursor: pointer !important; } .alert-dismissible .btn-close { filter: none !important; } .session-bq { margin-bottom: 5px; margin-top: 10px; margin-left: 5px; padding-left: 10px; border-left: 3px solid rgba(255, 255, 255, .25); } #device-bq { margin-left: 5px; padding-left: 10px; border-left: 3px solid rgba(255, 255, 255, .25); } </style> <?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/footer.inc'; ?>