/
mikopbx
/
ModuleRemoteSupport
Обзор
Документация
Войти
/
mikopbx
/
ModuleRemoteSupport
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
v1.1
Lib/LobbyProtocol.php
107 строк
3 KB
Nikolai Beketov
feat: add engineer web admin access via Warpgate (lobby v2)
25 июл 2026, 09:25
25 июл 2026, 09:25
16c0fc0
Код
Авторство
О чём код?
<?php declare(strict_types=1); namespace Modules\ModuleRemoteSupport\Lib; use Closure; use DateTimeImmutable; use Throwable; final class LobbyProtocol { /** @var Closure(): int */ private readonly Closure $clock; /** * @param null|Closure(): int $clock */ public function __construct(?Closure $clock = null) { $this->clock = $clock ?? time(...); } public function parse(string $output): LobbyAllocation { if ( strlen($output) > RemoteSupportConfig::LOBBY_MAX_BYTES || preg_match('/[\x00-\x09\x0B-\x1F\x7F]/', $output) === 1 ) { throw new LobbyProtocolException('Invalid lobby response'); } $expiresPattern = '([0-9]{4}-[0-9]{2}-[0-9]{2}T' . '[0-9]{2}:[0-9]{2}:[0-9]{2}(?:Z|[+-][0-9]{2}:[0-9]{2}))'; $patternV1 = '/\A' . 'MIKO-LOBBY: v1\n' . 'CODE: ([A-Z0-9]{3}-[A-Z0-9]{3})\n' . 'SLOT: ([0-9]{1,3})\n' . 'TUNNEL_PORT: ([0-9]{1,5})\n' . 'TUNNEL_USER: (lobbytun)\n' . 'EXPIRES: ' . $expiresPattern . '\n?\z/D'; $patternV2 = '/\A' . 'MIKO-LOBBY: v2\n' . 'CODE: ([A-Z0-9]{3}-[A-Z0-9]{3})\n' . 'SLOT: ([0-9]{1,3})\n' . 'TUNNEL_PORT: ([0-9]{1,5})\n' . 'WEB_TUNNEL_PORT: ([0-9]{1,5})\n' . 'TUNNEL_USER: (lobbytun)\n' . 'EXPIRES: ' . $expiresPattern . '\n?\z/D'; if (preg_match($patternV1, $output, $matches) === 1) { $webTunnelPort = null; [, $code, $slot, $tunnelPort, $tunnelUser, $expires] = $matches; } elseif (preg_match($patternV2, $output, $matches) === 1) { [, $code, $slot, $tunnelPort, $rawWebPort, $tunnelUser, $expires] = $matches; $webTunnelPort = (int)$rawWebPort; if ( $webTunnelPort < RemoteSupportConfig::WEB_TUNNEL_PORT_MIN || $webTunnelPort > RemoteSupportConfig::WEB_TUNNEL_PORT_MAX ) { throw new LobbyProtocolException('Lobby allocation is outside allowed ranges'); } } else { throw new LobbyProtocolException('Invalid lobby response'); } $slot = (int)$slot; $tunnelPort = (int)$tunnelPort; if ($slot < 0 || $slot > 999 || $tunnelPort < 22_000 || $tunnelPort > 22_999) { throw new LobbyProtocolException('Lobby allocation is outside allowed ranges'); } $expiresAt = $this->parseExpiry($expires); if ($expiresAt->getTimestamp() <= ($this->clock)()) { throw new LobbyProtocolException('Lobby allocation has expired'); } return new LobbyAllocation( code: $code, slot: $slot, tunnelPort: $tunnelPort, tunnelUser: $tunnelUser, expiresAt: $expiresAt, webTunnelPort: $webTunnelPort, ); } private function parseExpiry(string $value): DateTimeImmutable { try { $expiresAt = new DateTimeImmutable($value); } catch (Throwable $exception) { throw new LobbyProtocolException('Invalid lobby expiry', 0, $exception); } $normalizedInput = str_ends_with($value, 'Z') ? substr($value, 0, -1) . '+00:00' : $value; if ($expiresAt->format('Y-m-d\TH:i:sP') !== $normalizedInput) { throw new LobbyProtocolException('Invalid lobby expiry'); } return $expiresAt; } }