Сборка REDL: панель на PHP 8, капча-тумблер, закрытые уязвимости, установщики в один клик

- панель работает на PHP 8.4 (оригинал под PHP 7.0): elFinder utf8_encode, apache_get_modules, warnings
- капча выключена и управляется из админки (флаг captcha_enable + блок настроек)
- закрыты две SQL-инъекции без авторизации (createAuthLog: пароль из POST и CF-Connecting-IP)
- убрано хранение паролей в открытом виде в authlog, XSS в поле ref
- установщики install-panel.sh и install-node.sh (оригинальный затирал sources.list репозиториями Debian 9)
- современный Dockerfile (оригинальный на debian:stretch больше не собирается)
- планировщик и автозапуск работают без systemd
- брендинг REDL.IO, год 2026, ссылки на redl.io
- документация на русском: ИЗМЕНЕНИЯ, БЕЗОПАСНОСТЬ, ИНСТРУКЦИЯ
This commit is contained in:
2026-07-30 02:00:01 +00:00
commit 6ee2744e3a
492 changed files with 354172 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Action {
private $registry;
private $folder;
private $controller;
private $method;
private $args;
public function __construct($registry)
{
$this->registry = $registry;
}
public function make($action) {
$this->folder = null;
$this->controller = null;
$this->method = null;
$this->args = null;
$action = preg_replace("/[^\w\d\s\/]/", '', $action);
$parts = explode('/', $action);
$parts = array_filter($parts);
foreach($parts as $item) {
$fullpath = APPLICATION_DIR . 'controllers' . $this->folder . '/' . $item;
if(is_dir($fullpath)) {
$this->folder .= '/' . $item;
array_shift($parts);
continue;
}
elseif(is_file($fullpath . '.php')) {
$this->controller = $item;
array_shift($parts);
break;
} else break;
}
// Проверка папки
if(empty($this->folder)) {
$this->folder = 'errore';
}
// Проверка контроллера
if(empty($this->controller)) {
$this->controller = 'index';
}
// Получения метода
if($c = array_shift($parts)) {
$this->method = $c;
} else {
$this->method = 'index';
}
// Получение аргументов
if(isset($parts[0])) {
$this->args = $parts;
}
}
public function go($commonEnable = false) {
$controllerFile = APPLICATION_DIR . 'controllers/' . $this->folder . '/' . $this->controller . '.php';
$controllerClass = $this->controller . 'Controller';
if($this->folder != "common" || $commonEnable == true) { // Защита папки "common"
if(is_readable($controllerFile)) {
require_once($controllerFile);
$controller = new $controllerClass($this->registry);
if(is_callable(array($controller, $this->method))) {
$this->method = $this->method;
} else {
$this->method = 'index';
}
if(empty($this->args)) {
return call_user_func(array($controller, $this->method));
} else {
return call_user_func_array(array($controller, $this->method), $this->args);
}
}
}
$error = 'Ошибка: Не удалось загрузить контроллер ' . $this->controller . '!';
require_once("application/views/main/error.php");
exit();
}
}
?>
+29
View File
@@ -0,0 +1,29 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Config {
private $data = array();
public function __construct() {
if(is_readable(APPLICATION_DIR . 'config.php')) {
require_once(APPLICATION_DIR . 'config.php');
$this->data = array_merge($this->data, $config);
return true;
}
exit('Ошибка: Не удалось загрузить файл конфигурации!');
}
public function __set($key, $val){
$this->data[$key] = $val;
}
public function __get($key){
if(isset($this->data[$key])){
return $this->data[$key];
}
return false;
}
}
?>
+29
View File
@@ -0,0 +1,29 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
abstract class Controller {
private $registry;
protected $data = array();
public function __construct($registry) {
$this->registry = $registry;
}
public function __get($key) {
return $this->registry->$key;
}
public function __set($key, $value) {
$this->registry->$key = $value;
}
public function getChild($child = array()) {
foreach($child as $item) {
$this->action->make($item);
$this->data[basename($item)] = $this->action->go(true);
}
}
}
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Cookie {
public $data = array();
public function __construct() {
$this->data = $_COOKIE;
}
public function set($key, $value) {
setcookie($key, $value, time() + 60 * 60 * 24 * 30 * 12, "/");
}
public function remove($key) {
setcookie($key, null, time() - 3600, "/");
}
}
?>
+37
View File
@@ -0,0 +1,37 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class DB {
private $driver;
public function __construct($driver, $hostname, $username, $password, $database) {
$class = $driver . 'Driver';
if(is_readable(ENGINE_DIR . 'database/' . $driver . '.php')) {
require_once(ENGINE_DIR . 'database/' . $driver . '.php');
} else {
exit('Ошибка: Не удалось загрузить драйвер базы данных ' . $driver . '!');
}
$this->driver = new $class($hostname, $username, $password, $database);
}
public function query($sql) {
return $this->driver->query($sql);
}
public function escape($value) {
return $this->driver->escape($value);
}
public function countAffected() {
return $this->driver->countAffected();
}
public function getLastId() {
return $this->driver->getLastId();
}
public function getCount() {
return $this->driver->getCount();
}
}
?>
+48
View File
@@ -0,0 +1,48 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Document {
private $title;
private $activeSection;
private $activeItem;
private $scripts = array();
/* Заголовок страницы */
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
/* Активный раздел меню */
public function setActiveSection($section) {
$this->activeSection = $section;
}
public function getActiveSection() {
return $this->activeSection;
}
/* Активный элемент меню */
public function setActiveItem($item) {
$this->activeItem = $item;
}
public function getActiveItem() {
return $this->activeItem;
}
/* Скрипты */
public function addScript($script) {
$this->scriptsarray[] = $script;
}
public function getScripts() {
return $this->scripts;
}
}
?>
+25
View File
@@ -0,0 +1,25 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Game_settings {
private $data = array();
public function __construct() {
if(is_readable(ENGINE_DIR . 'games/game_settings.php')) {
require_once(ENGINE_DIR . 'games/game_settings.php');
$this->data = array_merge($this->data, $game_settings);
return true;
}
exit('Ошибка: Не удалось загрузить файл конфигурации игр!');
}
public function __get($key){
if(isset($this->data[$key])){
return $this->data[$key];
}
return false;
}
}
?>
+64
View File
@@ -0,0 +1,64 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Load {
private $registry;
public function __construct($registry) {
$this->registry = $registry;
}
public function view($name, $vars = array()){
$file = APPLICATION_DIR . 'views/' . $name . '.php';
if(is_readable($file)){
extract($vars);
ob_start();
include($file);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
$error = 'Ошибка: Не удалось загрузить шаблон ' . $name . '!';
require_once("application/views/main/error.php");
exit();
}
public function model($name){
$modelClass = $name . 'Model';
$modelPath = APPLICATION_DIR . 'models/' . $name . '.php';
if(is_readable($modelPath)){
require_once($modelPath);
if(class_exists($modelClass)){
$this->registry->$modelClass = new $modelClass($this->registry);
return true;
}
}
$error = 'Ошибка: Не удалось загрузить модель ' . $name . '!';
require_once("application/views/main/error.php");
exit();
}
public function library($name){
$libClass = $name . 'Library';
$libPath = ENGINE_DIR . 'libs/' . $name . '.php';
if(is_readable($libPath)){
require_once($libPath);
return true;
}
$error = 'Ошибка: Не удалось загрузить библиотеку ' . $name . '!';
require_once("application/views/main/error.php");
exit();
}
public function genpass($length) {
return substr(md5(microtime() . rand(0, 9999)), 0, $length);
}
}
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
abstract class Model {
private $registry;
public function __construct($registry) {
$this->registry = $registry;
}
public function __get($key) {
return $this->registry->$key;
}
public function __set($key, $value) {
$this->registry->$key = $value;
}
}
?>
+20
View File
@@ -0,0 +1,20 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Registry {
private $data = array();
public function __set($key, $val){
$this->data[$key] = $val;
}
public function __get($key){
if(isset($this->data[$key])){
return $this->data[$key];
}
return false;
}
}
?>
+41
View File
@@ -0,0 +1,41 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Request {
public $get = array();
public $post = array();
public $cookie = array();
public $files = array();
public $server = array();
public function __construct() {
$_GET = $this->clean($_GET);
$_POST = $this->clean($_POST);
$_REQUEST = $this->clean($_REQUEST);
$_COOKIE = $this->clean($_COOKIE);
$_FILES = $this->clean($_FILES);
$_SERVER = $this->clean($_SERVER);
$this->get = $_GET;
$this->post = $_POST;
$this->request = $_REQUEST;
$this->cookie = $_COOKIE;
$this->files = $_FILES;
$this->server = $_SERVER;
}
private function clean($data) {
if (is_array($data)) {
foreach ($data as $key => $value) {
unset($data[$key]);
$data[$this->clean($key)] = $this->clean($value);
}
} else {
$data = htmlspecialchars($data, ENT_COMPAT);
}
return $data;
}
}
?>
+29
View File
@@ -0,0 +1,29 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Response {
private $headers = array();
public function addHeader($header) {
$this->headersarray[] = $header;
}
public function redirect($url) {
header('Location: ' . $url);
exit;
}
public function output($content) {
if ($content) {
if (!headers_sent()) {
foreach($this->headers as $header) {
header($header, true);
}
}
echo $content;
}
}
}
?>
+14
View File
@@ -0,0 +1,14 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class Session {
public $data = array();
public function __construct() {
if(!session_id()) session_start();
$this->data = &$_SESSION;
}
}
?>
+176
View File
@@ -0,0 +1,176 @@
<?php
/*
Copyright (c) 2020 HOSTINPL (HOSTING-RUS) https://vk.com/hosting_rus
Developed by Samir Shelenko and Alexander Zemlyanoy (https://vk.com/id00v / https://vk.com/mrsasha082)
*/
class User {
private $registry;
private $user_id;
private $email;
private $firstname;
private $lastname;
private $balance;
private $access_level;
private $user_img;
private $test_server;
private $user_vk_id;
public function __construct($registry) {
$this->registry = $registry;
if(isset($this->registry->cookie->data['uid'])) {
$query = $this->registry->db->query("SELECT * FROM `users_auth` LEFT JOIN `users` ON users_auth.user_id=users.user_id WHERE `auth_key` = '" . $this->registry->db->escape(@$this->registry->cookie->data['uid']) . "'");
if ($query->num_rows) {
$this->user_id = $query->row['user_id'];
$this->email = $query->row['user_email'];
$this->firstname = $query->row['user_firstname'];
$this->lastname = $query->row['user_lastname'];
$this->balance = $query->row['user_balance'];
$this->access_level = $query->row['user_access_level'];
$this->user_img = $query->row['user_img'];
$this->test_server = $query->row['test_server'];
$this->user_vk_id = $query->row['user_vk_id'];
$this->registry->db->query("UPDATE `users_auth` SET `user_ip` = '" . $this->registry->db->escape($this->getRealIpAdress()) . "', `user_last_activity` = NOW() WHERE `auth_key` = '" . @$this->registry->db->escape($this->registry->cookie->data['uid']) . "'");
} else {
$this->logout();
}
}
}
public function login($email, $password) {
$query = $this->registry->db->query("SELECT * FROM users WHERE user_email = '" . $this->registry->db->escape($email) . "' AND user_password = '" . $this->registry->db->escape($password) . "' AND user_status = '1'");
if($query->num_rows) {
$key = sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . microtime()) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_password']) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_email']) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_id']);
$this->registry->cookie->set('uid', $key);
$this->user_id = $query->row['user_id'];
$this->email = $query->row['user_email'];
$this->firstname = $query->row['user_firstname'];
$this->lastname = $query->row['user_lastname'];
$this->balance = $query->row['user_balance'];
$this->access_level = $query->row['user_access_level'];
$this->user_img = $query->row['user_img'];
$this->test_server = $query->row['test_server'];
$this->registry->db->query("INSERT INTO `users_auth` SET `user_id` = '" . $query->row['user_id'] . "', `user_ip` = '" . $this->registry->db->escape($this->getRealIpAdress()) . "', `user_last_activity` = NOW(), `auth_user_email` = '" . $this->registry->db->escape($query->row['user_email']) . "', `auth_user_password` = '" . $this->registry->db->escape($query->row['user_password']) . "', `auth_key` = '" . $this->registry->db->escape($key) . "', `auth_type` = 'Password', `auth_date_add` = NOW()");
return true;
} else {
return false;
}
}
public function loginVk($vkid) {
$query = $this->registry->db->query("SELECT * FROM users WHERE user_vk_id = '" . (int)$vkid . "'");
if($query->num_rows) {
$key = sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . microtime()) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_password']) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_email']) . sha1(mt_rand(11111, 99999) . $this->GenerateHash(mt_rand(50, 200)) . $query->row['user_id']);
$this->registry->cookie->set('uid', $key);
$this->user_id = $query->row['user_id'];
$this->email = $query->row['user_email'];
$this->firstname = $query->row['user_firstname'];
$this->lastname = $query->row['user_lastname'];
$this->balance = $query->row['user_balance'];
$this->access_level = $query->row['user_access_level'];
$this->user_img = $query->row['user_img'];
$this->test_server = $query->row['test_server'];
$this->registry->db->query("INSERT INTO `users_auth` SET `user_id` = '" . $query->row['user_id'] . "', `user_ip` = '" . $this->registry->db->escape($this->getRealIpAdress()) . "', `user_last_activity` = NOW(), `auth_user_email` = '" . $this->registry->db->escape($query->row['user_email']) . "', `auth_user_password` = '" . $this->registry->db->escape($query->row['user_password']) . "', `auth_key` = '" . $this->registry->db->escape($key) . "', `auth_type` = 'Vk', `auth_date_add` = NOW()");
return true;
} else {
return false;
}
}
public function correctData() {
$query = $this->registry->db->query("SELECT * FROM `users_auth` LEFT JOIN `users` ON users_auth.user_id=users.user_id WHERE `auth_key` = '" . $this->registry->db->escape(@$this->registry->cookie->data['uid']) . "'");
if($query->num_rows) {
if($query->row['auth_user_email'] == $query->row['user_email'] && $query->row['auth_user_password'] == $query->row['user_password']) return true;
}
}
public function isLogged() {
if($this->correctData()) {
return $this->user_id;
} else {
$this->logout();
return false;
}
}
public function logout() {
$this->registry->db->query("DELETE FROM `users_auth` WHERE `auth_key` = '" . $this->registry->db->escape(@$this->registry->cookie->data['uid']) . "'");
$this->registry->cookie->remove('uid');
$this->user_id = null;
$this->email = null;
$this->firstname = null;
$this->lastname = null;
$this->balance = null;
$this->access_level = 0;
$this->user_vk_id = null;
}
public function getId() {
return $this->user_id;
}
public function getEmail() {
return $this->email;
}
public function getFirstname() {
return $this->firstname;
}
public function getLastname() {
return $this->lastname;
}
public function getUser_img() {
return $this->user_img;
}
public function getBalance() {
return $this->balance;
}
public function getUser_vk_id() {
return $this->user_vk_id;
}
public function getAccessLevel() {
return $this->access_level;
}
public function getTest_server() {
return $this->test_server;
}
public function getRealIpAdress() {
if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"]) && filter_var($_SERVER["HTTP_CF_CONNECTING_IP"], FILTER_VALIDATE_IP) !== false) {
return $_SERVER["HTTP_CF_CONNECTING_IP"];
}
foreach (array('REMOTE_ADDR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED') as $key) {
if (array_key_exists($key, $_SERVER) === true) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
$ip = trim($ip);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
return $ip;
}
}
}
}
return @$_SERVER['REMOTE_ADDR'];
}
private function GenerateHash($length = 12) {
$chars="qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP0!@#$%^&*()_+";
$size = strlen($chars) - 1;
$password = null;
while($length--) {
$password .= $chars[rand(0, $size)];
}
return $password;
}
}
?>