Files
ave-cms/adminx/Support/SensitiveRoutes.php
T
2026-07-27 12:58:44 +03:00

155 lines
8.4 KiB
PHP

<?php
/*
|--------------------------------------------------------------------------------------
| AVE.cms
|--------------------------------------------------------------------------------------
| @package AVE.cms
| @file adminx/Support/SensitiveRoutes.php
| @author AVE.cms <support@ave-cms.ru>
| @copyright 2007-2026 (c) AVE.cms
| @link https://ave-cms.ru
| @version 3.3
*/
namespace App\Adminx\Support;
defined('BASEPATH') || die('Direct access to this location is not allowed.');
use InvalidArgumentException;
/** Metadata contract and runtime inventory for high-risk Adminx routes. */
class SensitiveRoutes
{
protected static $operations = array(
'module.code' => 'Установка или изменение исполняемого кода модуля',
'core.update' => 'Установка подписанного обновления ядра',
'stored_php.execute' => 'Выполнение сохранённого PHP-кода',
'stored_php.write' => 'Сохранение PHP-кода, исполняемого runtime',
'theme_assets.write' => 'Изменение исполняемых CSS/JavaScript и файлов публичной темы',
'legacy_migration.write' => 'Изменение реквизитов исходной системы',
'legacy_migration.execute' => 'Очистка стартовых данных и миграция старой AVE.cms',
'database.restore' => 'Полная замена рабочей схемы данными из резервной копии',
);
protected static $required = array(
'POST /modules/archive/install' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/install' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/update' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/reinstall' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/repair' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/uninstall' => array('module.code', 'install_module_code'),
'POST /modules/lifecycle/{code}/remove' => array('module.code', 'install_module_code'),
'POST /system/updates/settings' => array('core.update', 'install_core_updates'),
'POST /system/updates/upload' => array('core.update', 'install_core_updates'),
'POST /system/updates/download/{id}' => array('core.update', 'install_core_updates'),
'POST /system/updates/jobs/{id}/step' => array('core.update', 'install_core_updates'),
'POST /system/updates/jobs/{id}/rollback' => array('core.update', 'install_core_updates'),
'POST /system/console/execute' => array('stored_php.execute', 'execute_console'),
'POST /blocks' => array('stored_php.write', 'manage_blocks'),
'POST /blocks/{id}' => array('stored_php.write', 'manage_blocks'),
'POST /blocks/{id}/copy' => array('stored_php.write', 'manage_blocks'),
'POST /blocks/revisions/{revision}/restore' => array('stored_php.write', 'manage_blocks'),
'POST /templates' => array('stored_php.write', 'manage_templates'),
'POST /templates/{id}' => array('stored_php.write', 'manage_templates'),
'POST /templates/{id}/copy' => array('stored_php.write', 'manage_templates'),
'POST /templates/revisions/{revision}/restore' => array('stored_php.write', 'manage_templates'),
'POST /rubrics' => array('stored_php.write', 'manage_rubrics'),
'POST /rubrics/{id}' => array('stored_php.write', 'manage_rubrics'),
'POST /rubrics/{id}/templates/main' => array('stored_php.write', 'manage_rubrics'),
'POST /rubrics/{id}/templates' => array('stored_php.write', 'manage_rubrics'),
'POST /rubrics/templates/{template}' => array('stored_php.write', 'manage_rubrics'),
'POST /requests' => array('stored_php.write', 'manage_requests'),
'POST /requests/{id}' => array('stored_php.write', 'manage_requests'),
'POST /requests/{id}/copy' => array('stored_php.write', 'manage_requests'),
'POST /requests/{id}/conditions' => array('stored_php.write', 'manage_requests'),
'POST /navigation' => array('stored_php.write', 'manage_navigation'),
'POST /navigation/{id}' => array('stored_php.write', 'manage_navigation'),
'POST /navigation/{id}/copy' => array('stored_php.write', 'manage_navigation'),
'POST /modules/content-packages/import' => array('stored_php.write', 'import_content_packages'),
'POST /system/document-jobs' => array('stored_php.write', 'manage_document_jobs'),
'POST /system/document-jobs/{id}' => array('stored_php.write', 'manage_document_jobs'),
'POST /system/document-jobs/{id}/start' => array('stored_php.execute', 'execute_document_jobs'),
'POST /system/document-jobs/{id}/step' => array('stored_php.execute', 'execute_document_jobs'),
'POST /themes/file' => array('theme_assets.write', 'manage_themes'),
'POST /themes/files/create' => array('theme_assets.write', 'manage_themes'),
'POST /themes/upload' => array('theme_assets.write', 'manage_themes'),
'POST /themes/path/delete' => array('theme_assets.write', 'manage_themes'),
'POST /themes/manifest' => array('theme_assets.write', 'manage_themes'),
'POST /themes/create' => array('theme_assets.write', 'manage_themes'),
'POST /themes/activate' => array('theme_assets.write', 'manage_themes'),
'POST /themes/import' => array('theme_assets.write', 'manage_themes'),
'POST /themes/delete' => array('theme_assets.write', 'manage_themes'),
'POST /themes/revisions/{id}/restore' => array('theme_assets.write', 'manage_themes'),
'POST /modules/legacy-migration/profiles' => array('legacy_migration.write', 'manage_legacy_migration'),
'POST /modules/legacy-migration/profiles/{id}/delete' => array('legacy_migration.write', 'manage_legacy_migration'),
'POST /modules/legacy-migration/runs/{id}/start' => array('legacy_migration.execute', 'run_legacy_migration'),
'POST /modules/legacy-migration/runs/{id}/rollback' => array('legacy_migration.execute', 'run_legacy_migration'),
'POST /modules/legacy-migration/runs/{id}/files' => array('legacy_migration.execute', 'run_legacy_migration'),
'POST /database/backup/restore' => array('database.restore', 'manage_database'),
);
public static function validate(array $route)
{
$options = isset($route['options']) && is_array($route['options']) ? $route['options'] : array();
$operation = isset($options['sensitive']) ? trim((string) $options['sensitive']) : '';
$key = self::routeKey($route);
$required = isset(self::$required[$key]) ? self::$required[$key] : null;
if ($operation === '' && !$required) {
return;
}
if ($required && ($operation !== $required[0]
|| !isset($options['permission'])
|| (string) $options['permission'] !== $required[1])) {
throw new InvalidArgumentException('Нарушена политика чувствительного маршрута ' . $key);
}
if (!isset(self::$operations[$operation])) {
throw new InvalidArgumentException('Неизвестная чувствительная операция: ' . $operation);
}
$method = isset($route['method']) ? strtoupper((string) $route['method']) : '';
if (in_array($method, array('GET', 'HEAD', 'OPTIONS'), true)) {
throw new InvalidArgumentException('Чувствительный маршрут не может использовать безопасный HTTP-метод');
}
if (empty($options['permission']) || empty($options['reauth'])) {
throw new InvalidArgumentException('Чувствительный маршрут обязан объявить permission и reauth');
}
}
public static function inventory(array $routes)
{
$items = array();
foreach ($routes as $route) {
self::validate($route);
$options = isset($route['options']) && is_array($route['options']) ? $route['options'] : array();
if (empty($options['sensitive'])) {
continue;
}
$items[] = array(
'method' => isset($route['method']) ? (string) $route['method'] : '',
'pattern' => isset($route['pattern']) ? (string) $route['pattern'] : '',
'operation' => (string) $options['sensitive'],
'permission' => (string) $options['permission'],
'reauth' => $options['reauth'],
);
}
return $items;
}
public static function required()
{
return self::$required;
}
protected static function routeKey(array $route)
{
return strtoupper(isset($route['method']) ? (string) $route['method'] : '')
. ' '
. (isset($route['pattern']) ? (string) $route['pattern'] : '');
}
}