Files
den-repo/src/den.php
2026-08-14 15:56:15 -04:00

53 lines
1.7 KiB
PHP

<?php
// presence endpoint for den.js
// counts client ids (js-running visitors), capped per ip to prevent inflation
// stores hmac'd fingerprints only, never raw ips or ids. entries expire after 5 min
// one line per active visitor: latest_timestamp|fingerprint|iphash
// change this secret, keep it private
define('DEN_SECRET', 'NowmIO4VXYYF6cmg6hJRw3P4ZEd4PIpylnmpKhj8QeW9fe7wfJ94lwTGw8PfwRgRB2MlZEqaIBftH9L3twsccucwq6gFKnmqLpXsTS0PqN1Glwi6tRYtH3hPKm0VD3U');
$f = __DIR__ . '/../owo_presence.txt';
$now = time();
$iph = substr(hash_hmac('sha1', $_SERVER['REMOTE_ADDR'], DEN_SECRET), 0, 12);
$id = isset($_GET['id']) ? $_GET['id'] : '';
if (preg_match('/^[a-f0-9]{16}$/', $id)) {
$me = substr(hash_hmac('sha1', 'id:' . $id, DEN_SECRET), 0, 12);
} else {
$me = $iph;
}
$roster = [];
if (file_exists($f)) {
foreach (file($f, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $l) {
$p = explode('|', $l, 3);
if (count($p) < 2) continue;
$ts = (int)$p[0];
if ($ts < $now - 300) continue;
$fp = $p[1];
$rih = isset($p[2]) ? $p[2] : '';
if (!isset($roster[$fp]) || $ts > $roster[$fp][0]) {
$roster[$fp] = [$ts, $rih];
}
}
}
$from_my_ip = 0;
foreach ($roster as $fp => $e) {
if ($e[1] === $iph && $fp !== $me) $from_my_ip++;
}
if (isset($roster[$me]) || $from_my_ip < 3) {
$roster[$me] = [$now, $iph];
}
$others = count($roster) - (isset($roster[$me]) ? 1 : 0);
$out = '';
foreach ($roster as $fp => $e) {
$out .= $e[0] . '|' . $fp . '|' . $e[1] . "\n";
}
@file_put_contents($f, $out, LOCK_EX);
header('Content-Type: application/json');
header('Cache-Control: no-store');
echo json_encode(['others' => $others]);