Fix plugin security, hooks system, and admin features
- Add plugin allowlist (enabled_plugins in config.json) - Add enable/disable toggle in admin (separate from visibility) - Add plugin hooks system (actions + filters with auto-registration) - Fix autoLinkPageTitles nested <a> tag vulnerability - Move MQTT credentials to environment variables - Preserve current page in language switcher - Fix ctime/birthtime for file creation date - Deduplicate getGuidePage() CommonMark setup - Simplify formatDisplayName() logic - Add admin activity log to dashboard - Add own password change with current password verification - Apply theme header_color to admin sidebar - Add content preview button in editor
This commit is contained in:
@@ -5,10 +5,14 @@ class PluginManager
|
||||
private array $plugins = [];
|
||||
private string $pluginsPath;
|
||||
private ?CMSAPI $api = null;
|
||||
private array $enabledPlugins = [];
|
||||
private array $actions = [];
|
||||
private array $filters = [];
|
||||
|
||||
public function __construct(string $pluginsPath)
|
||||
public function __construct(string $pluginsPath, array $enabledPlugins = [])
|
||||
{
|
||||
$this->pluginsPath = $pluginsPath;
|
||||
$this->enabledPlugins = $enabledPlugins;
|
||||
$this->loadPlugins();
|
||||
}
|
||||
|
||||
@@ -33,6 +37,11 @@ class PluginManager
|
||||
|
||||
foreach ($pluginDirs as $pluginDir) {
|
||||
$pluginName = basename($pluginDir);
|
||||
|
||||
if (!in_array($pluginName, $this->enabledPlugins, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pluginFile = $pluginDir . '/' . $pluginName . '.php';
|
||||
|
||||
if (file_exists($pluginFile)) {
|
||||
@@ -45,11 +54,60 @@ class PluginManager
|
||||
if ($this->api && method_exists($this->plugins[$pluginName], 'setAPI')) {
|
||||
$this->plugins[$pluginName]->setAPI($this->api);
|
||||
}
|
||||
|
||||
// Auto-register hooks from plugin methods
|
||||
$hookMethods = ['onPageLoad', 'onBeforeRender', 'onAfterRender', 'onSearch', 'onMenuBuild'];
|
||||
foreach ($hookMethods as $hook) {
|
||||
if (method_exists($this->plugins[$pluginName], $hook)) {
|
||||
$this->addAction($hook, [$this->plugins[$pluginName], $hook]);
|
||||
}
|
||||
}
|
||||
|
||||
// Register filter methods
|
||||
$filterMethods = ['onContentFilter', 'onTitleFilter', 'onMenuFilter'];
|
||||
foreach ($filterMethods as $filter) {
|
||||
if (method_exists($this->plugins[$pluginName], $filter)) {
|
||||
$this->addFilter($filter, [$this->plugins[$pluginName], $filter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addAction(string $hook, callable $callback, int $priority = 10): void
|
||||
{
|
||||
$this->actions[$hook][$priority][] = $callback;
|
||||
}
|
||||
|
||||
public function addFilter(string $hook, callable $callback, int $priority = 10): void
|
||||
{
|
||||
$this->filters[$hook][$priority][] = $callback;
|
||||
}
|
||||
|
||||
public function doAction(string $hook, ...$args): void
|
||||
{
|
||||
if (!isset($this->actions[$hook])) return;
|
||||
ksort($this->actions[$hook]);
|
||||
foreach ($this->actions[$hook] as $callbacks) {
|
||||
foreach ($callbacks as $callback) {
|
||||
$callback(...$args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function applyFilters(string $hook, $value, ...$args)
|
||||
{
|
||||
if (!isset($this->filters[$hook])) return $value;
|
||||
ksort($this->filters[$hook]);
|
||||
foreach ($this->filters[$hook] as $callbacks) {
|
||||
foreach ($callbacks as $callback) {
|
||||
$value = $callback($value, ...$args);
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getPlugin(string $name): ?object
|
||||
{
|
||||
return $this->plugins[$name] ?? null;
|
||||
@@ -60,6 +118,16 @@ class PluginManager
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
public function getEnabledPlugins(): array
|
||||
{
|
||||
return $this->enabledPlugins;
|
||||
}
|
||||
|
||||
public function isEnabled(string $pluginName): bool
|
||||
{
|
||||
return in_array($pluginName, $this->enabledPlugins, true);
|
||||
}
|
||||
|
||||
public function isPluginViewable(object $plugin): bool
|
||||
{
|
||||
if (method_exists($plugin, 'getConfig')) {
|
||||
@@ -78,7 +146,6 @@ class PluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter by allowed plugins for this page
|
||||
if ($allowedPlugins !== null && !in_array($pluginName, $allowedPlugins, true)) {
|
||||
continue;
|
||||
}
|
||||
@@ -107,4 +174,4 @@ class PluginManager
|
||||
|
||||
return $sidebarContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user