79 lines
2.7 KiB
PHP
79 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
/**
|
|
* Reads + validates the host-written status file run/wg-status.json (bind-mounted to
|
|
* storage/app/restart-signal). Single source for the WireGuard page + the /wg-status.json route.
|
|
* Contains NO secrets — the collector never writes a private key.
|
|
*/
|
|
class WgStatus
|
|
{
|
|
/** Status older than this (seconds) means the host collector is offline. */
|
|
private const STALE_AFTER = 20;
|
|
|
|
/** A peer with a handshake within this many seconds is considered online. */
|
|
private const ONLINE_WITHIN = 180;
|
|
|
|
private function path(): string
|
|
{
|
|
return storage_path('app/restart-signal/wg-status.json');
|
|
}
|
|
|
|
/**
|
|
* @return array{configured:bool, at:int, stale:bool, gate?:array, wg_quick?:string, server?:array, peers?:array}
|
|
*/
|
|
public function read(): array
|
|
{
|
|
$path = $this->path();
|
|
$data = is_file($path) ? json_decode((string) @file_get_contents($path), true) : null;
|
|
|
|
if (! is_array($data)) {
|
|
return ['configured' => false, 'at' => 0, 'stale' => true];
|
|
}
|
|
|
|
$at = (int) ($data['at'] ?? 0);
|
|
$stale = $at < (time() - self::STALE_AFTER);
|
|
|
|
if (empty($data['configured'])) {
|
|
return ['configured' => false, 'at' => $at, 'stale' => $stale];
|
|
}
|
|
|
|
$peers = [];
|
|
foreach ((array) ($data['peers'] ?? []) as $p) {
|
|
if (! is_array($p)) {
|
|
continue;
|
|
}
|
|
$hs = (int) ($p['latest_handshake'] ?? 0);
|
|
$peers[] = [
|
|
'name' => (string) ($p['name'] ?? ''),
|
|
'pubkey' => (string) ($p['pubkey'] ?? ''),
|
|
'endpoint' => (string) ($p['endpoint'] ?? ''),
|
|
'latest_handshake' => $hs,
|
|
'rx' => (int) ($p['rx'] ?? 0),
|
|
'tx' => (int) ($p['tx'] ?? 0),
|
|
'online' => $hs > (time() - self::ONLINE_WITHIN),
|
|
];
|
|
}
|
|
|
|
return [
|
|
'configured' => true,
|
|
'at' => $at,
|
|
'stale' => $stale,
|
|
'gate' => [
|
|
'marker' => (bool) ($data['gate']['marker'] ?? false),
|
|
'chain' => (bool) ($data['gate']['chain'] ?? false),
|
|
],
|
|
'wg_quick' => (string) ($data['wg_quick'] ?? 'inactive'),
|
|
'server' => [
|
|
'subnet' => (string) ($data['server']['subnet'] ?? ''),
|
|
'server_ip' => (string) ($data['server']['server_ip'] ?? ''),
|
|
'port' => (int) ($data['server']['port'] ?? 0),
|
|
'endpoint' => (string) ($data['server']['endpoint'] ?? ''),
|
|
'pubkey' => (string) ($data['server']['pubkey'] ?? ''),
|
|
],
|
|
'peers' => $peers,
|
|
];
|
|
}
|
|
}
|