Skip to content

Commit

Permalink
Fix routing of plugins public PHP scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
cedric-anne authored and trasher committed Jan 22, 2025
1 parent 8f97759 commit 51387d7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
5 changes: 5 additions & 0 deletions phpunit/functional/Glpi/Http/FirewallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public function testComputeFallbackStrategy(): void
],
'foo.php' => '',
],
'public' => [
'css.php' => '',
],
'index.php' => '',
]
],
Expand Down Expand Up @@ -129,6 +132,8 @@ public function testComputeFallbackStrategy(): void
'/marketplace/myplugin/ajax/foo.php' => $default_for_plugins_legacy,
'/marketplace/myplugin/front/dir/bar.php' => $default_for_plugins_legacy,
'/marketplace/myplugin/front/foo.php' => $default_for_plugins_legacy,
'/marketplace/myplugin/public/css.php' => $default_for_plugins_legacy, // /public/css.php file accessed with its legacy path
'/marketplace/myplugin/css.php' => $default_for_plugins_legacy, // /public/css.php file accessed with the expected path
'/marketplace/myplugin/index.php' => $default_for_plugins_legacy,
'/marketplace/myplugin/PluginRoute' => $default_for_symfony_routes,

Expand Down
3 changes: 3 additions & 0 deletions src/Glpi/Http/Firewall.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ private function computeFallbackStrategyForPlugin(string $plugin_key, string $pl
foreach ($this->plugins_dirs as $plugin_dir) {
$expected_filenames = [
$plugin_dir . '/' . $plugin_key . $plugin_resource,

// A PHP script located in the `/public` directory of a plugin will not have the `/public` prefix in its URL
$plugin_dir . '/' . $plugin_key . '/public' . $plugin_resource,
];
$resource_matches = [];
if (\preg_match('#^(?<filename>.+\.php)(/.*)$#', $plugin_resource, $resource_matches)) {
Expand Down
14 changes: 14 additions & 0 deletions src/Glpi/Http/LegacyRouterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ protected function extractPathAndPrefix(Request $request): array
$path = $filepath;
break;
}

// All plugins public resources should now be accessed without explicitely using the `/public` path,
// e.g. `/plugins/myplugin/public/css.php` -> `/plugins/myplugin/css.php`.
$path_matches = [];
if (preg_match('#^/plugins/(?<plugin_key>[^\/]+)/public(?<plugin_resource>/.+)$#', $filepath, $path_matches) === 1) {
$new_path = sprintf('/plugins/%s%s', $path_matches['plugin_key'], $path_matches['plugin_resource']);
if ($this->getTargetFile($new_path) !== null) {
// To not break URLs than can be found in the wild (in e-mail, forums, external apps configuration, ...),
// please do not remove this behaviour before, at least, 2030 (about 5 years after GLPI 11.0.0 release).
Toolbox::deprecated('Plugins URLs containing the `/public` path are deprecated. You should remove the `/public` prefix from the URL.');
$path = $new_path;
break;
}
}
}

if ($path === '') {
Expand Down
47 changes: 47 additions & 0 deletions tests/functional/Glpi/Http/Listener/LegacyRouterListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ protected function fileProvider(): iterable
'file.test.php' => '<?php echo("/marketplace/myplugin/front/some.dir/file.test.php");',
],
],
'public' => [
'css.php' => '<?php echo("/marketplace/myplugin/public/css.php");',
],
],
],
'plugins' => [
Expand Down Expand Up @@ -198,6 +201,14 @@ protected function fileProvider(): iterable
'target_pathinfo' => null,
'included' => true,
];

// Path to a PHP script located in the `/public` dir of a plugin
yield '/plugins/myplugin/front/some.dir/file.test.php/path/to/item' => [
'path' => '/plugins/myplugin/css.php',
'target_path' => '/marketplace/myplugin/public/css.php',
'target_pathinfo' => null,
'included' => true,
];
}

/**
Expand Down Expand Up @@ -607,6 +618,42 @@ function () use ($event) {
$this->string($event->getRequest()->get('_glpi_file_to_load'))->isEqualTo(vfsStream::url('glpi/marketplace/myplugin/front/test.php'));
}

public function testRunLegacyRouterFromDeprecatedPublicPath(): void
{
$structure = [
'plugins' => [
'myplugin' => [
'public' => [
'test.php' => '<?php echo("/plugins/myplugin/public/test.php");',
],
],
],
];

vfsStream::setup('glpi', null, $structure);

$this->newTestedInstance(
vfsStream::url('glpi'),
[vfsStream::url('glpi/marketplace'), vfsStream::url('glpi/plugins')]
);

$event = $this->getRequestEvent('/plugins/myplugin/public/test.php');

$this->when(
function () use ($event) {
$reporting_level = \error_reporting(E_ALL); // be sure to report deprecations
$this->testedInstance->onKernelRequest($event);
\error_reporting($reporting_level); // restore previous level
}
)->error
->withMessage('Plugins URLs containing the `/public` path are deprecated. You should remove the `/public` prefix from the URL.')
->withType(E_USER_DEPRECATED)
->exists();

$this->string($event->getRequest()->attributes->get('_controller'))->isEqualTo(LegacyFileLoadController::class);
$this->string($event->getRequest()->get('_glpi_file_to_load'))->isEqualTo(vfsStream::url('glpi/plugins/myplugin/public/test.php'));
}

public function testRunLegacyRouterFromPluginInMultipleDirectories(): void
{
$structure = [
Expand Down

0 comments on commit 51387d7

Please sign in to comment.