Из названий было не видно, какая панель лежит в основе. Теперь версия стоит в H1 всех документов и галерей, а в начале README (обоих) добавлена строка об оригинале: HostinPL 5.6, авторы Samir Shelenko и Alexander Zemlyanoy, писалась под Debian 9 / PHP 7.0. Нумерация версии оставлена от оригинала. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
246 lines
20 KiB
Markdown
246 lines
20 KiB
Markdown
**Русский** · [English](CHANGES.en.md)
|
||
|
||
# HostinPL 5.6 · Что изменено по сравнению с оригиналом
|
||
|
||
Оригинал: **HostinPL 5.6** в виде «nulled»-сборки (форк `Xopowblu-4EJlOBEK/HostinPL-5.6`),
|
||
написанной под Debian 9 и PHP 7.0.
|
||
|
||
Ниже — всё, что мы поменяли, с указанием файлов и строк. Правки в коде панели лежат в `panel/`.
|
||
|
||
**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.**
|
||
|
||
---
|
||
|
||
## 1. Панель запущена на современном PHP
|
||
|
||
Оригинал написан под PHP 7.0. На PHP 8 часть кода падала насмерть. Сейчас панель работает
|
||
на **PHP 8.4**: обход всех 21 раздела (главная, сервера, новости, статус, тикеты, веб-хостинг
|
||
и вся админка) даёт **200 на каждом и ноль ошибок в логе**.
|
||
|
||
| Файл | Было | Стало |
|
||
|------|------|-------|
|
||
| `engine/engine_ftp/elFinder.class.php:4497` | `utf8_encode()` — функция удалена в PHP 8.2, файловый менеджер падал с фатальной ошибкой | Обёрнута в `function_exists()`, фолбэк `mb_convert_encoding($str,'UTF-8','ISO-8859-1')` |
|
||
| `application/views/admin/checksys/index.php:22` | `apache_get_modules()` — существует только в Apache с mod_php, под nginx раздел «Проверка системы» отдавал 500 | Обёрнута в `function_exists()`, иначе проверка по `REQUEST_URI` |
|
||
| `application/views/admin/index.php:215` | `$item['invoice_ammount']` использовался после `foreach`, при пустом списке счетов — Undefined variable | Проверка `isset()` |
|
||
| `application/models/users.php:199-206` | `$city[1]`, `$country[1]`, `$countryCode[1]` без проверки совпадения регулярки | Проверки `isset()` |
|
||
| `application/controllers/common/loginheader.php:35` | `$_GET['ref']` без `isset` | `isset()` + приведение к `(int)` |
|
||
|
||
### Что оказалось ложной тревогой
|
||
|
||
Библиотека **phpseclib 1.x** в составе панели использует `create_function()`, удалённую в PHP 8.
|
||
Выглядело как блокирующая проблема, но проверка показала: **phpseclib не подключается ни одним
|
||
`include` во всей панели** — это мёртвый код. Связь с игровыми нодами идёт через нативное
|
||
расширение `php-ssh2` (`engine/libs/ssh2.php` → `ssh2_exec`). Ничего чинить не потребовалось.
|
||
|
||
Так же безопасен `get_magic_quotes_gpc()` в `elFinderConnector.class.php:320` — он закрыт
|
||
условием `version_compare(PHP_VERSION,'5.4','<') && ...`, и на PHP 8 до вызова дело не доходит.
|
||
|
||
---
|
||
|
||
## 2. Капча выключена и управляется из админки
|
||
|
||
Раньше капча была вшита жёстко: без валидных ключей Google **войти в панель было невозможно**,
|
||
на форме висело «ERROR for site owner: Invalid site key». Теперь появился флаг
|
||
`captcha_enable` в `application/config.php` (по умолчанию `0` — выключена).
|
||
|
||
**Бэкенд.** Во все четыре валидатора добавлена строка
|
||
`if($this->config->captcha_enable != '1') return $result;` перед проверкой капчи:
|
||
|
||
* `application/controllers/account/login.php` — вход
|
||
* `application/controllers/common/loginheader.php` — регистрация и форма обратной связи (2 места)
|
||
* `application/controllers/tickets/create.php` — создание тикета
|
||
|
||
**Вёрстка.** Пять виджетов капчи (4 в `views/common/loginheader.php`, 1 в `views/tickets/create.php`)
|
||
обёрнуты в `<?php if(@$captcha_enable == '1'): ?>`. Скрипт Google `api.js` подключается только при
|
||
включённой капче. Все вызовы `grecaptcha.reset(...)` заменены на
|
||
`window.grecaptcha && grecaptcha.reset(...)` — иначе при выключенной капче JavaScript падал
|
||
в обработчиках ошибок и формы переставали отвечать.
|
||
|
||
**Админка.** В `views/admin/settings.php`, вкладка «Прочие настройки», добавлен блок
|
||
«Защита от ботов (reCAPTCHA v2)»: переключатель Выключена/Включена и поля Site key и Secret key.
|
||
|
||
Проверено в обе стороны: при выключенной капче вход и регистрация проходят и пользователь реально
|
||
создаётся в базе; при включённой — свежая сессия получает «Подтвердите, что вы не робот!» и виджет
|
||
возвращается на страницу.
|
||
|
||
> **Осторожно при добавлении своих настроек.** Механизм сохранения настроек ищет строки конфига
|
||
> **по подстроке** (`strpos`). Поэтому флаг назван `captcha_enable`, а не `captcha`: строка
|
||
> `captcha` содержится в `recaptcha` и `secret_recaptcha`, и сохранение перезаписало бы не тот
|
||
> параметр. Новые ключи не должны быть подстрокой существующих.
|
||
|
||
---
|
||
|
||
## 3. Закрыты уязвимости
|
||
|
||
Кратко (подробно с кодом — в [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md)):
|
||
|
||
* **Две SQL-инъекции, доступные без авторизации** в `application/models/users.php`
|
||
(`createAuthLog()`): в журнал входов без экранирования попадали пароль из формы и IP из
|
||
заголовка `CF-Connecting-IP`, который вообще не проверялся. Все значения теперь проходят через
|
||
`$this->db->escape()` / `(int)`, заголовок проверяется `filter_var(..., FILTER_VALIDATE_IP)`.
|
||
* **Пароли в открытом виде**: `login.php` писал реальный пароль в таблицу `authlog` при каждой
|
||
попытке входа, включая неудачные. Убрано.
|
||
* **XSS** в скрытом поле `ref` формы регистрации — добавлен `htmlspecialchars()`.
|
||
* Запрос к геосервису `ip-api.com` выполняется только для валидного IP и с `urlencode()`.
|
||
|
||
---
|
||
|
||
## 4. Установщик переписан с нуля
|
||
|
||
Оригинальный `install` был опасен на любой современной системе:
|
||
|
||
* `echo "deb ... stretch main" > /etc/apt/sources.list` — **затирал список репозиториев**
|
||
и заменял его на Debian 9, после чего apt ломался
|
||
* ставил `php7.0` и жёстко правил `/etc/php/7.0/apache2/php.ini`
|
||
* переводил MariaDB на `bind-address = 0.0.0.0` без единого предупреждения
|
||
* работал только при `/etc/issue.net` == `Debian9`, иначе просто отказывался запускаться
|
||
* пароли и токены генерировал, но нигде не сохранял — их можно было только записать с экрана
|
||
* при любой ошибке продолжал работу: все команды заканчивались на `> /dev/null 2>&1`
|
||
|
||
Новые скрипты:
|
||
|
||
**`install-panel.sh`** — nginx, PHP 8.x (версия определяется автоматически), MariaDB, база со
|
||
случайным паролем, конфиг, планировщик, сторож автозапуска, создание администратора и финальная
|
||
проверка, что страница входа действительно отдаётся с формой. Идемпотентен: повторный запуск
|
||
не затирает уже загруженную базу. Креды пишутся в `/root/.redl-panel-credentials` (chmod 600).
|
||
`set -euo pipefail` — при ошибке скрипт останавливается, а не делает вид, что всё хорошо.
|
||
|
||
**`install-node.sh`** — Docker из официального репозитория, сборка образа, каталоги
|
||
`/home/cp/gameservers/files`, группа `gameservers`, MariaDB для баз игровых серверов, SteamCMD,
|
||
ProFTPD, настройка sshd с откатом конфига, если `sshd -t` не проходит. **Перед началом проверяет,
|
||
может ли Docker вообще работать на этой машине** (`unshare -Ur`), и честно предупреждает, если нет.
|
||
В конце печатает готовые данные для подключения локации и команды файрвола.
|
||
|
||
Ни один из скриптов не трогает `/etc/apt/sources.list`.
|
||
|
||
---
|
||
|
||
## 5. Образ игровых серверов пересобран
|
||
|
||
Оригинальный `docker/Dockerfile.original-stretch` собран на `debian:stretch`, а репозитории
|
||
Debian 9 отключены с 2023 года — **образ больше не собирается**, `apt-get update` внутри падает.
|
||
|
||
Новый `docker/Dockerfile` — на Debian 12 (bookworm), но **обязательно с тегом `debian:stretch`**:
|
||
это имя жёстко прописано в коде панели (`application/models/servers.php:642`,
|
||
`docker create ... debian:stretch`), менять его без правки панели нельзя.
|
||
|
||
Что внутри: 32-битные библиотеки (SA-MP, CRMP, MTA, старые CS собраны под i386), `screen` для
|
||
консолей, Java для Minecraft, Node.js 20 для RAGE:MP, `gdb` для разбора крашей.
|
||
Node.js берётся из NodeSource **по HTTPS с проверкой ключа**, а не как раньше.
|
||
|
||
---
|
||
|
||
## 6. Работа без systemd
|
||
|
||
Панель штатно рассчитана на systemd. В контейнерных VPS его нет, поэтому добавлены сторожа
|
||
на cron: `/usr/local/bin/hostinpl-guard` (панель) и `/usr/local/bin/gamenode-guard` (нода).
|
||
Раз в минуту (нода — раз в 2 минуты) они проверяют MariaDB, PHP-FPM, nginx, Docker и cron и
|
||
поднимают то, что упало; плюс задание `@reboot` для подъёма после перезагрузки.
|
||
|
||
Живость панели определяется **HTTP-запросом** к странице входа, а не поиском процесса по имени —
|
||
поиск по шаблону ловил бы собственную командную строку сторожа.
|
||
|
||
---
|
||
|
||
## 7. Планировщик
|
||
|
||
Оригинал прописывал 9 заданий на публичный домен панели. Теперь они ходят на `127.0.0.1`
|
||
(не зависит от DNS и внешней доступности) и получают таймауты `-m`, чтобы зависший запрос
|
||
не копился в процессах.
|
||
|
||
> **Грабля с токеном.** Токен планировщика нельзя выцеплять из конфига простым `grep "'token'"` —
|
||
> под это же условие попадает строка `'yk_password1' => 'token'`, и в URL уезжают два значения
|
||
> через перевод строки, после чего задания молча не работают. В установщике токен пишется
|
||
> напрямую при генерации конфига.
|
||
|
||
---
|
||
|
||
## 8. Языки интерфейса: русский и английский
|
||
|
||
Оригинал был только на русском, весь текст вшит в шаблоны. В сборке появился слой перевода:
|
||
|
||
* `engine/main/lang.php` — класс `Lang` и глобальный помощник `t()`
|
||
* `application/lang/ru.php`, `application/lang/en.php` — словари
|
||
* Порядок выбора языка: параметр `?lang=` → cookie `lang` → **заголовок браузера
|
||
`Accept-Language`** → значение по умолчанию из конфига
|
||
* Переключатель (RU / EN) в шапке кабинета, админки и в подвале страницы входа
|
||
* Фразы, которых нет в словаре, остаются на русском — из интерфейса ничего не может пропасть
|
||
|
||
Перевод применяется к готовому ответу через `ob_start()`, поэтому 200 файлов шаблонов
|
||
переписывать не понадобилось, и покрытие сразу распространяется на админку и письма.
|
||
Замена работает только на границах слов: без этого короткий ключ портил длинные слова
|
||
(«Мод» превращал «Модуль» в «Modуль», «день» делал из «деньги» «dayги»).
|
||
|
||
### Полнота перевода
|
||
|
||
В словаре **1304 фразы** — это весь текст, который панель показывает человеку: кабинет, заказ
|
||
сервера, управление сервером (консоль с описанием всех RCON-команд, FTP, базы MySQL, файрвол,
|
||
планировщик задач, автоустановка модов), тикеты, FAQ целиком, вся админка, письма и служебные
|
||
сообщения планировщика.
|
||
|
||
Покрытие считается не на глаз: скрипт повторяет логику замены прямо на исходниках и показывает
|
||
строки, которые останутся русскими. По нему непокрытых мест **четыре**, и все четыре такими и
|
||
должны быть:
|
||
|
||
* «Русский» — подпись самого переключателя языка;
|
||
* `rus => Pyccĸий` и `ukr => Українська` в FAQ — это коды языков игрового сервера, а не интерфейс;
|
||
* регулярное выражение проверки имени `/^([А-ЯЁ])([а-яё]{1,15})$/u` — код, а не текст.
|
||
|
||
Отдельно поправлены два подводных камня, которые давали мешанину языков:
|
||
|
||
* предлог «в» был отдельной записью словаря и подменялся внутри ещё не переведённых предложений —
|
||
получалось «at поле имя пользователя». Такие служебные слова переводятся только вместе с фразой;
|
||
* формат даты `d.m.Y в H:i` содержит русское «в» между датой и временем. Теперь он проходит через
|
||
`t()` (31 вызов `date()` в 20 файлах), и в английском режиме получается `30.07.2026 14:22`.
|
||
|
||
Проверено живым обходом 45 страниц в английском режиме, включая формы создания и скрытые вкладки
|
||
настроек. Подробности — в [ИНСТРУКЦИЯ.md](ИНСТРУКЦИЯ.md), раздел «Язык интерфейса».
|
||
|
||
---
|
||
|
||
## 9. Брендинг и даты
|
||
|
||
* Год в подвалах: `2020©` → `2026©` (`views/common/footer.php`, `views/common/loginheader.php`)
|
||
* Название и описание — REDL.IO: `application/config.php` (`description`, `keywords`,
|
||
`mail_sender`, `mail_from`), подвалы, раздел «Проверка системы»
|
||
* Ссылки на сторонние сайты прежнего владельца сборки (`hostinpl.ru`, `osmp.ga`) заменены на `redl.io`
|
||
* Ссылки «Сообщество VK» на чужое сообщество заменены на `redl.io` (`footer.php`,
|
||
`views/main/index.php`, `views/offline/index.php`)
|
||
* Все 15 шаблонов писем: шапка «REDL.IO / Хостинг с искусственным интеллектом», подпись
|
||
«С уважением, Администрация REDL.IO»
|
||
|
||
**Авторские копирайт-заголовки в коде не удалялись** — они остались во всех файлах,
|
||
где были изначально.
|
||
|
||
---
|
||
|
||
## 10. phpMyAdmin
|
||
|
||
Панель ссылается на `/phpmyadmin` из админки. Оригинальный установщик ставил phpMyAdmin через
|
||
Apache, что на nginx не работало. Теперь он ставится из репозитория дистрибутива и отдаётся
|
||
самим nginx.
|
||
|
||
> **Грабля за обратным прокси.** nginx на адрес `/phpmyadmin` (без слеша) отвечает редиректом
|
||
> и по умолчанию подставляет в него **собственный порт**, например
|
||
> `http://panel.example.com:8095/phpmyadmin/`. Если панель стоит за обратным прокси, такой адрес
|
||
> снаружи недоступен и ссылка из админки не открывается. Лечится
|
||
> `absolute_redirect off; port_in_redirect off;` — это уже прописано в конфиге, который создаёт
|
||
> установщик.
|
||
|
||
---
|
||
|
||
## Чего мы НЕ делали
|
||
|
||
* Не переписывали хеширование паролей. Панель хранит пароли как **MD5 без соли**
|
||
(`md5($password)`, колонка `varchar(32)`). Переход на `password_hash()` затрагивает вход,
|
||
регистрацию, восстановление, смену пароля и требует миграции существующих пользователей.
|
||
* Не переводили создание игровых серверов с Docker на что-то другое.
|
||
* Не удаляли `panel/application/public/js/proxy/proxy.php` — файл обезврежен, но оставлен как
|
||
свидетельство (см. [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md)).
|
||
* Не тестировали платёжные шлюзы живыми платежами и VK-авторизацию.
|
||
* Не проверяли работу самих игровых серверов: для этого нужна нода с Docker.
|
||
|
||
---
|
||
|
||
**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.**
|