diff --git a/changelog.json b/changelog.json index 6db3a22b..817cbe48 100644 --- a/changelog.json +++ b/changelog.json @@ -1,56 +1,26 @@ { - "version": "2.5.2", + "version": "2.5.3", "changes": [ - "Added the new Player v2 web application with SPA frontend assets, styles, scripts and vendored libraries.", - "Added Player v2 access-code authentication, scope wiring, stream and subtitle token generation, and Active Code login.", - "Hardened Player v2 against IDOR and XSS vulnerabilities and added proper escaping for catalog poster URLs and category emoji.", - "Restored player resize authorization and changed channel ACL handling to fail closed when authorization cannot be validated.", - "Expanded the Smart Activation Codes system with the complete code lifecycle and integration into admin, reseller, line and MAG workflows.", - "Added Category Templates with admin/reseller management and custom_data application.", - "Integrated category-template custom_data into Active Codes and restricted applyToAll operations according to template visibility.", - "Improved Active Code tables, localization, voucher-detail rendering, package/bouquet handling and reseller portal integration.", - "Fixed device-locked activation codes so they can only be used by their assigned device and only one concurrent request can activate a code.", - "Fixed Active Code information disclosure that could reveal the MAC address bound to a locked code.", - "Added a unique per-install OPENSSL_EXTRA secret for installation-specific cryptographic operations.", - "Added tamper-proof stream tokens using AES-256-GCM with per-panel configuration.", - "Hardened authentication with constant-time shared-secret and HMAC comparisons, fresh admin/reseller sessions and improved session cookies.", - "Restored login flood protection and improved access-control handling.", - "Hardened image resizing against SSRF and DNS rebinding, including vetted IP handling and TLS verification for outbound requests.", - "Removed credentialed reflected-Origin CORS behavior from the Player API.", - "Fixed reseller API authentication caused by operator-precedence issues.", - "Replaced the monolithic XC_Bootstrap flow with an injectable BootKernel pipeline.", - "Added PSR-4 ConstantsInitializer and ErrorResponder components and consolidated legacy bootstrap prelude shims.", - "Routed Web API database initialization through shared bootstrap stages and removed redundant streaming-path includes.", - "Added bootstrap tests covering stage skip paths, side effects and initialization behavior.", - "Centralized STATUS_* initialization and improved bootstrap documentation.", - "Moved frequently edited release constants to top-of-file define() declarations.", - "Added a dedicated Rector refactoring infrastructure with configuration, documentation and Make targets.", - "Applied reviewed Rector transformations across core, streaming, Public Controllers and Ministra code.", - "Performed multiple refactoring and convergence passes to simplify control flow, remove dead code and improve maintainability.", - "Decomposed RadioService processing and mass-edit logic into smaller tested helpers.", - "Converted inline XcVm fully-qualified references to PSR-4 imports.", - "Reworked database access to use DatabaseAware::db() instead of threading the global database object through call chains.", - "Expanded strict typing and corrected nullable parameter and PID handling across multiple components.", - "Restored security guards and include paths affected by unsafe automated refactoring.", - "Adopted K&R and tab formatting and expanded parameter type-hint requirements across the codebase.", - "Resolved PHPCS and PHPStan issues introduced during the refactoring process and updated the PHPStan dependency.", - "Added a dual-backend SQLite and MariaDB test database and improved test-environment guards.", - "Expanded core test coverage for database, cache, authorization, brute-force protection, settings, HTTP requests, update channels and module registries.", - "Added tests for ChannelService mass-edit and ordering behavior.", - "Moved phpunit.phar into tests/ and updated test references.", - "Added per-panel Responsive Tables configuration and profile appearance/customizer options.", - "Added bouquet sort controls for moving entries up, down, to the top or to the bottom.", - "Restored Users navigation tabs and fixed multiple new UI navigation and form submission issues.", - "Fixed stream creation without an icon, deletion of unpaired MAG/Enigma2 devices and missing Streams page Resources data.", - "Fixed CPU resource reporting so stream resource information is populated correctly and retained.", - "Added MediaAnalyzedEvent dispatch after successful VOD analysis.", - "Fixed VOD Range workers being terminated during concurrent requests.", - "Exposed bouquet ID, name and order in bouquet listing output.", - "Added FileCache safeguards and static deletion helpers.", - "Pinned database connections to utf8mb4 and restored nullable database-host support for CLI boot.", - "Fixed transactional database operations so Errors trigger rollback as well as Exceptions.", - "Fixed simultaneous on-demand viewer requests so a stopped stream is started only once.", - "Fixed live connection filtering and additional authentication, process-management and null-safety edge cases.", - "Updated bootstrap and contributor documentation and removed obsolete references to the old prelude architecture." + "Expanded the reseller dashboard with media panels for recently added streams, movies and episodes, live connections, expiring lines and a geographic connection map.", + "Added richer dashboard cards with contextual Tabler icons, live media counters, category badges, artwork fallbacks and active viewer indicators.", + "Added reseller trial deep-links and a voucher balance dashboard card, while reorganizing the reseller sidebar into clearer sections.", + "Introduced a complete licensing and activation UI with license status, self-service key entry, activation banners and documentation covering the activation model and transmitted data.", + "Added licensing gates for load-balancer installation and fanout integration, plus per-build RELEASE_ID/XC_VM_BUILD_ID watermarking and attribution integrity protection.", + "Implemented Encrypt Playlists support across Live and VOD streams.", + "Hardened player API authentication, activation-code login, token handling, CORS, image-resize SSRF protections, DNS rebinding defenses and TLS trusted-server handling.", + "Expanded Category Templates to Lines, MAG, Enigma2 devices and reseller vouchers, including inherited template visibility and voucher custom_data integration.", + "Added fanout operational controls including live debug-category selection, daemon memory reporting, bulk node draining and improved Redis/fanout reliability.", + "Improved player API stability and correctness for active connection counts, missing icons, null bouquets, VOD paging, ratings, short EPG limits and content scoping.", + "Overhauled the ticket lifecycle and admin interactions, while simplifying many mass-delete, picker and DataTable workflows.", + "Added RTL interface support with Arabic translation and made text direction strictly follow the active language.", + "Consolidated the admin bootstrap, removed legacy session.php/functions.php dependencies, modernized module administration and continued migration away from procedural compatibility layers.", + "Removed the final goto statements and continued the Rector modernization program with expanded rules, cache fixes and convergence cleanup.", + "Expanded automated tests across admin, player API, playback, calendars, database backends, authorization, caching, settings, HTTP and module registries.", + "Added dual-backend SQLite/MariaDB coverage and improved bootstrap and test harness behavior.", + "Improved module lifecycle handling so disabled modules stay disabled after reinstall and lifecycle failures are contained safely.", + "Enhanced sync-dev.sh for Docker deployment and fixed ownership handling for generated parent directories.", + "Improved CLI build/version resolution, Composer dependencies, PHPCS configuration and general code-quality tooling.", + "Fixed numerous stability issues involving Redis, fanout configuration, nullable data, controller crashes, streaming resources, admin forms and player API edge cases.", + "Updated authentication, licensing and UI translation documentation." ] } diff --git a/docs/_media/player-api.openapi.yaml b/docs/_media/player-api.openapi.yaml index ff875f6c..62618528 100644 --- a/docs/_media/player-api.openapi.yaml +++ b/docs/_media/player-api.openapi.yaml @@ -14,6 +14,8 @@ info: ``` {protocol}://{host}:{port}/player_api?username={username}&password={password}&action={action} ``` + The legacy XtreamCodes `/player_api.php?…` spelling and the path-style + `/player_api/{username}/{password}[/{action}]` form hit the same handler. ## Media access (direct links) After authorization, media is served from: diff --git a/docs/en/builds/updates_checklist.md b/docs/en/builds/updates_checklist.md index 42a5580b..ec2a63c1 100644 --- a/docs/en/builds/updates_checklist.md +++ b/docs/en/builds/updates_checklist.md @@ -20,11 +20,8 @@ git log --pretty=format:"- %s (%h)" "$PREV_TAG"..main > dist/changes.md ```json { - "version": "X.Y.Z", - "changes": [ - "Description of change 1", - "Description of change 2" - ] + "version": "X.Y.Z", + "changes": ["Description of change 1", "Description of change 2"] } ``` @@ -41,7 +38,10 @@ Before publishing, verify the build works: **Quality checks** (CI runs the same set on the tag — confirm it is green): ```bash -make dev-tools && make phpstan && make cs && make gates +make dev-tools +make phpstan +make cs +make gates php tests/phpunit.phar -c tests/phpunit.xml.dist make dev-clean # remove the dev tools afterwards, restoring the prod-only vendor/ ``` @@ -134,7 +134,6 @@ Edit the version constant, disable the phpMiniAdmin access flag, and clear its p > anyone who reaches the panel. This step is a security hardening gate — a release must never > go out with it on. - ```text src/Core/Config/ConstantsInitializer.php ``` @@ -178,12 +177,12 @@ make main After building, `dist/` should contain: -| File | Description | -| --- | --- | -| `XC_VM.zip` | MAIN installer (install script + xc_vm.tar.gz) | -| `xc_vm.tar.gz` | MAIN archive (install & update) | -| `loadbalancer.tar.gz` | LB archive (install & update) | -| `hashes.md5` | MD5 checksums | +| File | Description | +| --------------------- | ---------------------------------------------- | +| `XC_VM.zip` | MAIN installer (install script + xc_vm.tar.gz) | +| `xc_vm.tar.gz` | MAIN archive (install & update) | +| `loadbalancer.tar.gz` | LB archive (install & update) | +| `hashes.md5` | MD5 checksums | > The same archive is used for both clean installation and updates. > The update script (`src/update`) filters out binary/config directories at runtime using the hardcoded `UPDATE_EXCLUDE_DIRS` list inside the Python script itself. @@ -233,7 +232,6 @@ After publishing, the workflow will automatically: > on the **same version** — LBs read MAIN's database and a schema/behaviour skew can break > streaming. Don't leave LBs a release behind. - - [ ] Verify all 4 assets are attached to the release - [ ] Run `md5sum -c hashes.md5` on downloaded files - [ ] Check Telegram notification was sent @@ -251,7 +249,7 @@ After publishing, the workflow will automatically: a published one; clients pin to a tag. - **A bad release already reached servers** — operators can downgrade per-server from the panel (**Servers → Rollback Version**, see [Update Mechanism → Rollback](../administration/update-system.md#rollback-downgrade)); on MAIN a DB backup is taken automatically first. Migrations are - forward-only, so prefer a roll-*forward* hotfix when the fix is small. + forward-only, so prefer a roll-_forward_ hotfix when the fix is small. --- @@ -261,32 +259,32 @@ Every `make` target used during release prep, in one place. **Quality checks** — run `make dev-tools` first, `make dev-clean` when done: -| Command | Purpose | -| --- | --- | -| `make dev-tools` | Install dev tooling (PHPStan, phpcs) via `composer install` | -| `make phpstan` | Static analysis (also catches syntax errors) | -| `make phpstan-baseline` | Regenerate the PHPStan baseline | -| `make cs` | Code-style check — import/namespace hygiene (phpcs + Slevomat) | -| `make cs-fix` | Apply code-style fixes in place | -| `make gates` | PSR-4 regression gates (procedural-use, LB-archive, vendor-prod-only) | -| `make dev-clean` | Remove the dev tools again, restoring the production-only `vendor/` | -| `php tests/phpunit.phar -c tests/phpunit.xml.dist` | Unit tests | +| Command | Purpose | +| -------------------------------------------------- | --------------------------------------------------------------------- | +| `make dev-tools` | Install dev tooling (PHPStan, phpcs) via `composer install` | +| `make phpstan` | Static analysis (also catches syntax errors) | +| `make phpstan-baseline` | Regenerate the PHPStan baseline | +| `make cs` | Code-style check — import/namespace hygiene (phpcs + Slevomat) | +| `make cs-fix` | Apply code-style fixes in place | +| `make gates` | PSR-4 regression gates (procedural-use, LB-archive, vendor-prod-only) | +| `make dev-clean` | Remove the dev tools again, restoring the production-only `vendor/` | +| `php tests/phpunit.phar -c tests/phpunit.xml.dist` | Unit tests | **Release prep & build:** -| Command | Purpose | -| --- | --- | -| `make generate_deleted_files` | Regenerate `src/migrations/deleted_files.txt` | -| `make new` | Wipe + recreate `dist/` — run ONCE at the start (step 1), before writing `dist/changes.md`; never again before building | -| `make lb` | Build the LoadBalancer archive into `dist/` | -| `make main` | Build the MAIN archive into `dist/` | -| `bash tools/test-install/test_release.sh` | Docker install test of the built release | +| Command | Purpose | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `make generate_deleted_files` | Regenerate `src/migrations/deleted_files.txt` | +| `make new` | Wipe + recreate `dist/` — run ONCE at the start (step 1), before writing `dist/changes.md`; never again before building | +| `make lb` | Build the LoadBalancer archive into `dist/` | +| `make main` | Build the MAIN archive into `dist/` | +| `bash tools/test-install/test_release.sh` | Docker install test of the built release | **Documentation** (English source in `docs/en`; `docs/ru` is generated + committed): -| Command | Purpose | -| --- | --- | -| `make docs-venv` | One-time: local venv (build + translation deps) | +| Command | Purpose | +| --------------------- | ------------------------------------------------------ | +| `make docs-venv` | One-time: local venv (build + translation deps) | | `make docs-translate` | Regenerate `docs/ru` from `docs/en` (before a release) | -| `make docs-build` | Strict MkDocs build into `./build/site` (what CI runs) | -| `make docs-serve` | Live docs preview at `http://127.0.0.1:8000` | +| `make docs-build` | Strict MkDocs build into `./build/site` (what CI runs) | +| `make docs-serve` | Live docs preview at `http://127.0.0.1:8000` | diff --git a/docs/ru/guides/authentication-and-sessions.md b/docs/ru/guides/authentication-and-sessions.md index cc93277a..4fbb4286 100644 --- a/docs/ru/guides/authentication-and-sessions.md +++ b/docs/ru/guides/authentication-and-sessions.md @@ -64,12 +64,12 @@ $_SESSION['verify'] = md5($rUserInfo['username'] . '||' . $rCrypt); // Verificat ### `Authenticator::resellerLogin(array $data): array` -Способ входа в систему реселлера. Структура, идентичная `login()`, с этими различиями: +Метод входа в систему торгового посредника. Структура идентична `login()` с этими отличиями: - Повторная проверка всегда проверяется, когда она включена (параметр обхода отсутствует). - Для проверки разрешений требуется `is_reseller` вместо `is_admin`. - Возвращает `STATUS_NOT_RESELLER`, если у пользователя нет разрешения торгового посредника. -- Логи входа в систему записываются с типом `RESELLER` вместо `ADMIN`. +- Журналы входа в систему записываются с типом `RESELLER` вместо `ADMIN`. Значения сеанса, записанные в зависимости от успеха: @@ -91,7 +91,7 @@ $_SESSION['rverify'] = md5($rUserInfo['username'] . '||' . $rCrypt); // Verific | `STATUS_DISABLED` |5|Учетная запись отключена| | `STATUS_NOT_ADMIN` |6|У пользователя нет прав администратора| | `STATUS_INVALID_CAPTCHA` |12|Не удалось выполнить проверку reCAPTCHA| -| `STATUS_INVALID_CODE` |13|Несоответствие кода доступа и группы| +| `STATUS_INVALID_CODE` |13|Несоответствие кода доступа/ группы| | `STATUS_NOT_RESELLER` |35|У пользователя нет разрешения торгового посредника| ### Хэширование паролей @@ -100,13 +100,13 @@ $_SESSION['rverify'] = md5($rUserInfo['username'] . '||' . $rCrypt); // Verific Authenticator::hashPassword(string $password, ?string $salt = null, int $rounds = 20000): string ``` -Использует `crypt()` с SHA-512 (`$6$`). Используется формат `$6$rounds=20000$$`, где `` - это 16 шестнадцатеричных символов, полученных из `openssl_random_pseudo_bytes(16)`. Пароли повторно хэшируются при каждом успешном входе в систему, что приводит к перераспределению ресурсов. +Использует `crypt()` с SHA-512 (`$6$`). Формат salt равен `$6$rounds=20000$$`, где `` - это 16 шестнадцатеричных символов, полученных из `openssl_random_pseudo_bytes(16)`. Пароли повторно хэшируются при каждом успешном входе в систему, что приводит к замене значения salt. ```php Authenticator::checkPassword(string $password, string $storedHash): bool ``` -Проверяет открытый текстовый пароль на соответствие сохраненному хэшу, используя `crypt($password, $storedHash)`, с безопасным по времени сравнением с помощью `hash_equals()`. Сохраненный хэш содержит алгоритм, раунды и соль, поэтому `crypt()` воспроизводит правильный хэш для сравнения. +Проверяет пароль в виде открытого текста на соответствие сохраненному хэшу, используя `crypt($password, $storedHash)`, с возможностью сравнения по времени с помощью `hash_equals()`. Сохраненный хэш содержит алгоритм, раунды и соль, поэтому `crypt()` воспроизводит правильный хэш для сравнения. --- @@ -127,7 +127,7 @@ Authenticator::checkPassword(string $password, string $storedHash): bool 5. **Проверка, включенная пользователем** -- `enabled == 0` возвращает `CLIENT_DISABLED`. 6. **Список разрешенных IP-адресов** -- Если для пользователя задано значение `allowed_ips`, IP-адрес клиента должен совпадать (решается с помощью `gethostbyname`). 7. **Ограничение по стране** - Два режима: - - Для каждого пользователя: если задано значение `forced_country`, а не `ALL`, страна GeoIP должна совпадать. + - Для каждого пользователя: если задано значение `forced_country`, а не `ALL`, то страна GeoIP должна совпадать. - Глобальный: если нет переопределения для каждого пользователя, устанавливается глобальный параметр `allow_countries` (если только он не содержит `ALL`). 8. **Проверка агента пользователя** -- Если для пользователя задано значение `allowed_ua`, то пользовательский агент HTTP должен соответствовать. 9. флаг **Проверка интернет-провайдера** -- `isp_violate` отклоняет соединение. @@ -165,20 +165,18 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' ### Проверка сеанса администратора -Файл: `src/Public/Views/admin/functions.php` +Точка входа: `AdminScopeBootstrap::hydrateAdminContext()` (`src/Infrastructure/Bootstrap/AdminScopeBootstrap.php`). Он запускается по пути администратора фронт-контроллера (через `boot()`) и вызывается непосредственно сценариями просмотра `$noBootstrapPages` (`login`, `setup`, `database`, `logout`, `player`, `post`) — заменяя прежний `admin/functions.php` include. -Если установлено значение `$_SESSION['hash']`, при каждой загрузке страницы выполняются следующие проверки: +Когда установлено значение `$_SESSION['hash']`, он определяет пользователя (`UserRepository::getRegisteredUserById($_SESSION['hash'])`) и права доступа (`AuthRepository::getPermissions()`), а затем проверяет целостность сеанса с помощью `SessionManager::adminSessionValid($rUserInfo, $rPermissions, $rSettings)`: -1. **Поиск пользователя** -- `UserRepository::getRegisteredUserById($_SESSION['hash'])`. Если пользователь больше не существует, сеанс завершается. -2. **Проверка прав доступа** -- `AuthRepository::getPermissions()` должен возвращать допустимый набор с `is_admin == true`. -3. **Проверка IP-адреса** - Сравнивает текущий IP-адрес с `$_SESSION['ip']`: +1. **Пользователь и администратор** - существует строка пользователя и разрешения, и задано значение `is_admin`. +2. **Проверка IP-адреса** - Сравнивает текущий IP-адрес с `$_SESSION['ip']`: - Если параметр `ip_subnet_match` включен: сравниваются только первые три октета (например, `192.168.1.*` соответствует `192.168.1.*`). - Если параметр `ip_subnet_match` отключен: требуется точное совпадение IP-адресов. - - Если IP-адрес не совпадает и включена настройка `ip_logout`, сеанс завершается. - - Если IP-адрес не совпадает и `ip_logout` отключен, `$_SESSION['ip']` автоматически обновляется до нового IP-адреса. -4. **Проверить проверку хэша Verify** -- `$_SESSION['verify']` должно быть равно `md5($rUserInfo['username'] . '||' . $rUserInfo['password'])`. Это гарантирует, что сеанс будет аннулирован в случае изменения пароля. + - IP-адрес применяется только тогда, когда включено значение `ip_logout`; в противном случае допускается изменение IP-адреса (и в пути HTML значение `$_SESSION['ip']` обновляется до нового значения). +3. **Проверить проверку хэша Verify** -- `$_SESSION['verify']` должно быть равно `md5($rUserInfo['username'] . '||' . $rUserInfo['password'])`. Это гарантирует, что сеанс будет аннулирован в случае изменения пароля. -Если какая-либо проверка завершается неудачей, сеанс очищается с помощью `SessionManager::clearContext('admin')`, и пользователь перенаправляется на индексную страницу. +Если проверка завершается неудачно, сеанс очищается с помощью `SessionManager::clearContext('admin')`, и пользователь перенаправляется на индексную страницу. Конечная точка admin JSON DataTables (`Public\Controllers\Admin\TableController`) выполняет ту же проверку `SessionManager::adminSessionValid()` в своей ветви сеанса, но вместо перенаправления выдает JSON. ### Проверка сеанса работы с реселлером @@ -193,11 +191,9 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' Соответствие IP-подсети и поведение при выходе из системы по IP-адресу такое же, как у администратора. -### Тайм-аут сеанса администрирования +### Жизненный цикл сеанса администратора -Файл: `src/Public/Views/admin/session.php` - -Для сеансов администрирования выполняется отдельная проверка времени ожидания сеанса. Если заданы значения `$_SESSION['hash']` и `$_SESSION['last_activity']`, а с момента `last_activity` прошло более 60 минут, то сеансовые ключи (`hash`, `ip`, `code`, `verify`, `last_activity`) не заданы. При каждом действительном запросе обновляется `$_SESSION['last_activity']`, и сессия закрывается для записи. +Запуск сеанса и 60-минутный тайм-аут бездействия выполняются в `AdminScopeBootstrap::bootSession()` (путь к интерфейсу контроллера), а для устаревших сценариев просмотра — в `SessionManager::start('admin')` + `requireAuth()`, которые заменили прежний параметр `admin/session.php`. Если заданы значения `$_SESSION['hash']` и `$_SESSION['last_activity']`, а с момента `last_activity` прошло более 60 минут, ключи сеанса (`hash`, `ip`, `code`, `verify`, `last_activity`) не заданы. При каждом действительном запросе обновляется `$_SESSION['last_activity']`, и сеанс закрывается для записи. Конечная точка опроса AJAX-сессии (`{"result": true/false}`) обслуживается `Public\Controllers\Admin\SessionController` (маршрут `session`). ### Проверка сеанса игрока @@ -209,7 +205,7 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' Файл: `src/Core/Auth/SessionManager.php` -Унифицированный сеансовый API, который абстрагирует различные имена сеансовых ключей в разных контекстах. Предназначен для замены устаревших файлов `admin/session.php` и `reseller/session.php`. +Унифицированный сеансовый API, который абстрагирует различные имена сеансовых ключей в разных контекстах. Он заменяет устаревший admin `session.php` / `functions.php` includes (теперь удален); области реселлеров и игроков загружаются с помощью своих собственных классов `*ScopeBootstrap`. ### Контекстная ключевая карта @@ -231,7 +227,7 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' **`requireAuth(?string $loginUrl = null): void`** -Проверяет наличие аутентифицированного сеанса. Если запрос направлен напрямую на `session.php`, возвращает ответ в формате JSON `{"result": true/false}` (используется для опроса сеанса AJAX). В противном случае перенаправляет не прошедших проверку пользователей на страницу входа в систему. В случае успеха вызывает `touch()` для обновления временной метки действия. +Перенаправляет пользователей, не прошедших проверку подлинности, на страницу входа в систему; в случае успеха вызывает `touch()` для обновления временной метки активности. Опрос выделенного сеанса AJAX теперь выполняется с помощью `SessionController` (маршрут `session`), а не с помощью этого метода. **`isAuthenticated(): bool`** @@ -267,7 +263,7 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' **`getContext(): ?string`** -Возвращает текущую контекстную строку (`'admin'`, `'reseller'`, `'player'`) или `null`, если она не задана. +Возвращает текущую строку контекста (`'admin'`, `'reseller'`, `'player'`) или `null`, если она не задана. ### Поведение по истечении времени ожидания @@ -312,7 +308,7 @@ $_SESSION['pverify'] = md5($rUserInfo['username'] . '||' . $rUserInfo['password' ### `truncateAttempts(array $attempts, int $frequency, bool $list = false): array` -Отфильтровывает просроченные попытки из массива отслеживания. Если значение `$list` равно `true`, массив обрабатывается как индексированный (для `checkAuthFlood`); в противном случае как ассоциативный, с ключом по термину (для `checkBruteforce`). +Отфильтровывает просроченные попытки из массива отслеживания. Если значение `$list` равно `true`, массив обрабатывается как индексированный (для `checkAuthFlood`); в противном случае как ассоциативный с ключом по термину (для `checkBruteforce`). ### Блокирующий механизм @@ -410,9 +406,9 @@ VALUES($type, $codeId, $userId, $status, $ip, $timestamp); Файл: `src/Core/Auth/PageAuthorization.php` -Управление доступом на уровне страницы. Определяет, разрешают ли групповые разрешения текущего пользователя доступ к определенной странице панели администратора или торгового посредника. +Управление доступом на уровне страницы. Определяет, разрешают ли групповые права текущего пользователя доступ к определенной странице панели администратора или торгового посредника. -- `PageAuthorization::checkResellerPermissions($page)` - сопоставляет названия страниц с флагами требуемых разрешений и возвращает, разрешен ли доступ. +- `PageAuthorization::checkResellerPermissions($page)` -- сопоставляет названия страниц с флагами требуемых разрешений и возвращает, разрешен ли доступ. --- @@ -426,8 +422,8 @@ VALUES($type, $codeId, $userId, $status, $ip, $timestamp); | `src/Core/Auth/Authorization.php` |Проверки авторизации на уровне объекта| | `src/Core/Auth/PageAuthorization.php` |Управление доступом на уровне страницы| | `src/Public/Controllers/Player/PlayerLoginController.php` |Процесс входа игрока в систему с проверкой безопасности| -| `src/Public/Views/admin/functions.php` |Проверка сеанса администратора при каждой загрузке страницы| -| `src/Public/Views/admin/session.php` |Тайм-аут сеанса администратора и проверка сеанса AJAX| +| `src/Infrastructure/Bootstrap/AdminScopeBootstrap.php` |Загрузка администратора: жизненный цикл сеанса, `$rUserInfo`/`$rPermissions`, защита целостности| +| `src/Public/Controllers/Admin/SessionController.php` |Опрос сессии администратора AJAX (маршрут `session`)| | `src/Infrastructure/Bootstrap/reseller_functions.php` |Проверка сеанса реселлера при каждой загрузке страницы| | `src/Domain/User/UserRepository.php` |Поиск учетных данных (`getAuthUserByCredentials`)| | `src/bootstrap.php` |Определения констант состояния, контексты начальной загрузки| diff --git a/docs/ru/info/licensing-and-activation.md b/docs/ru/info/licensing-and-activation.md new file mode 100644 index 00000000..967f59a8 --- /dev/null +++ b/docs/ru/info/licensing-and-activation.md @@ -0,0 +1,76 @@ +# Лицензирование и активация + +XC_VM находится под **бесплатный и с открытым исходным кодом** общей публичной лицензией **GNU Affero +версия 3.0 (AGPL-3.0)**. На этой странице полностью раскрывается порядок лицензирования панели, +проверка авторства и активация работают — включая именно то, что отправляет панель +на сервер лицензирования и когда. Здесь нет ничего скрытого. + +## Модель двойного лицензирования + +|Вы сохраняете уведомление об авторстве|Вы удаляете атрибуцию (белую метку)| +| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|**AGPL-3.0 — бесплатно.** Все работает, включая узлы балансировки нагрузки. Нет активации, нет контакта с сервером.|**Требуется активация.** Для запуска подсистемы балансировки нагрузки / узлов кластера необходим бесплатный ключ активации, привязанный к компьютеру. Панель по-прежнему работает локально на одном сервере без ключа.| + +Сохраняя _"Vateron Media · AGPL-3.0"_ кредит (явно как AGPL-3.0 **§7(b)** +требуются разрешения) - это все, что требуется для развертывания в сообществе. Путь активации +существует только для операторов, которые удаляют эту атрибуцию — это точка, в которой +Vateron Media, как единственный правообладатель, предлагает отдельное соглашение, а не +чем AGPL. + +!!! примечание "Ключи для активации предоставляются бесплатно" +Ключи выдаются **свободный** в режиме самообслуживания, по одному на каждый компьютер (HWID). Они не являются +продано. Их целью является подотчетность — доступная для отзыва информация о том, кто управляет +ребрендированная копия — не монетизация. + +## Атрибуция -проверка целостности (AGPL §7b) + +По каждому запросу комиссия проверяет, что уведомление о его присвоении все еще присутствует в +нижний колонтитул. Если он был удален, то **пользовательский интерфейс управления** (администратор /реселлер / игрок) +показывает уведомление `ATTRIBUTION_REMOVED` до тех пор, пока оно не будет восстановлено. Проверка завершена. +**обратимый и неразрушающий**: данные не изменяются, интерфейс командной строки продолжает работать, и +восстановление уведомления разблокирует панель при следующем запросе. **Потоковая передача для конечного пользователя +эта проверка не влияет на**. + +## Какие ворота активации + +Для установки **белая этикетка** (атрибуция удалена) без действительного ключа: + +- **Не удается подготовить узлы балансировщика нагрузки / кластера** — скомпилированное ядро +отказывается предоставить удаленному узлу доступ к базе данных панели. +- **Оперативная доставка большой емкости (демон разветвления) отключена**, таким образом, доставка +возвращается к устаревшему способу. Панель с одним сервером остается доступной. + +Установка **сообщество** (атрибуция не изменена) никогда не закрывается и никогда не связывается с +сервер лицензирования. + +## Как активировать + +1. Найдите свой **ВИД**, указанный в **Настройки → Информация** и на баннере панели мониторинга. +(`XC_VM::install_id()`). +2. Отправьте его на странице активации и получите ключ, привязанный к этому HWID. +3. Введите ключ в панели управления (баннер активации панели управления). Панель подтвердит его +**не в сети** по открытому ключу, скомпилированному в расширении — обратный переход невозможен. +требуется для того, чтобы начать им пользоваться. + +## Данные, которые отправляет панель, — полное раскрытие + +A **установка сообществом (авторство не изменено) ничего не отправляет** — он никогда не связывается с +сервер лицензирования. + +A **установка белой этикетки** устанавливает связь с сервером лицензирования +(`https://www.xcvm.tech`) + +**То, что никогда не отправлялось:** нет потоковых данных, нет данных о зрителе/подписчике, нет учетной записи +учетные данные, нет содержимого базы данных, нет содержимого файла. Удаленная команда отсутствует +канал — сервер никогда не приказывает панели что-либо делать; она только +считывает подписанный вердикт _valid / revoked_ для своего собственного ключа. + +## Происхождение + +Каждой сборке присваивается уникальный идентификатор (`XC_VM_BUILD_ID`), поэтому утечка или +переименованную копию можно проследить до сборки, из которой она была создана. + +--- + +> ❗️ Вы несете единоличную ответственность за то, как используется XC_VM. Vateron Media не требует +> ответственность за неправильное использование или незаконное развертывание. diff --git a/lb_configs/nginx.conf b/lb_configs/nginx.conf index 2c8196a0..f104258f 100644 --- a/lb_configs/nginx.conf +++ b/lb_configs/nginx.conf @@ -240,7 +240,7 @@ http { fastcgi_param XC_API $1; } - location ~ ^/(player_api|enigma2|xplugin|epg|playlist)\.php$ { + location ~ ^/(player_api|enigma2|xplugin|epg|playlist)(?:\.php)?$ { limit_req zone=one burst=8; include limit_queue.conf; fastcgi_index index.php; diff --git a/src/Cli/Commands/XcvmCoreCommand.php b/src/Cli/Commands/XcvmCoreCommand.php index f96b0bd2..6b4a2deb 100644 --- a/src/Cli/Commands/XcvmCoreCommand.php +++ b/src/Cli/Commands/XcvmCoreCommand.php @@ -271,8 +271,8 @@ class XcvmCoreCommand implements CommandInterface { return (is_string($rBody) && $rCode >= 200 && $rCode < 300) ? $rBody : null; } - /** Download a URL to a file (following redirects). */ /** + * Download a URL to a file (following redirects). * Fetch $rUrl to $rDest. A transient failure is reported, not retried — the * command is idempotent, so re-running it is the recovery. */ diff --git a/src/Core/Config/ConstantsInitializer.php b/src/Core/Config/ConstantsInitializer.php index 8a8efa91..e705b741 100644 --- a/src/Core/Config/ConstantsInitializer.php +++ b/src/Core/Config/ConstantsInitializer.php @@ -11,7 +11,7 @@ use RuntimeException; defined('DB_ACCESS_ENABLED') || define('DB_ACCESS_ENABLED', false); defined('DB_ACCESS_PWD') || define('DB_ACCESS_PWD', ''); defined('DEV_MODE') || define('DEV_MODE', false); -defined('XC_VM_VERSION') || define('XC_VM_VERSION', '2.5.2'); +defined('XC_VM_VERSION') || define('XC_VM_VERSION', '2.5.3'); // Per-build watermark stamped into the deploy root by `make main` (see the // Makefile stamp_release_id target). A source/dev checkout is never stamped, so // runtime and the licence activation call report 'dev'. Unique per build, so a diff --git a/src/bin/nginx/conf/nginx.conf b/src/bin/nginx/conf/nginx.conf index 3416a73a..e54ba565 100644 --- a/src/bin/nginx/conf/nginx.conf +++ b/src/bin/nginx/conf/nginx.conf @@ -107,7 +107,7 @@ http { rewrite ^ /api/playlist last; } - location = /panel_api.php { + location ~ ^/panel_api(?:\.php)?$ { rewrite ^ /api/player_api last; } @@ -304,8 +304,10 @@ http { fastcgi_param XC_API $1; } - # ─── Streaming API → Front Controller (legacy *.php) ────── - location ~ ^/(player_api|enigma2|xplugin|epg|playlist|active_code)\.php$ { + # ─── Streaming API → Front Controller (.php optional) ─── + # Clients send both the XtreamCodes legacy /player_api.php?… and + # the bare /player_api?… — the suffix is optional so neither 404s. + location ~ ^/(player_api|enigma2|xplugin|epg|playlist|active_code)(?:\.php)?$ { limit_req zone=one burst=8; include limit_queue.conf; fastcgi_index index.php; diff --git a/src/migrations/deleted_files.txt b/src/migrations/deleted_files.txt index 3cf4347d..d5330d7e 100644 --- a/src/migrations/deleted_files.txt +++ b/src/migrations/deleted_files.txt @@ -18,8 +18,11 @@ Modules/ministra_85a7d/MinistraModule.php Modules/ministra_85a7d/PortalHandler.php Modules/ministra_85a7d/PortalHelpers.php Modules/ministra_85a7d/module.json +Public/Controllers/Reseller/TableController.php Public/Views/admin/api.php +Public/Views/admin/functions.php Public/Views/admin/modals.php +Public/Views/admin/session.php Public/Views/layouts/reseller/modals.php Public/Views/reseller/topbar.php Public/assets/admin/css/app.css