Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions plugins/sMultisitePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,15 @@ function ms_sso_current_session_id(): string {
* Enforces resource access per domain on the front-end:
* - Compares evo()->documentIdentifier against cached allowed resource IDs for the current site_key.
* - Whitelists SSO service endpoints to avoid accidental 404 / access blocks.
* - Leaves API entrypoints without an HTTP request binding outside page access checks.
*
* @return void
*/
Event::listen('evolution.OnWebPageInit', function () {
if (!app()->bound('request')) {
return;
}

$uri = strtok($_SERVER['REQUEST_URI'] ?? '/', '?');
$suffix = (string) evo()->getConfig('friendly_url_suffix', '');
$path = $uri;
Expand Down
34 changes: 34 additions & 0 deletions tests/runtime/api-request-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/** Isolated CMS container for API event regression tests. */
function evo() { return $GLOBALS['apiTestApp']; }
require __DIR__ . '/bootstrap.php';
use Illuminate\Container\Container;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\Facades\Facade;
/** Supply only the CMS configuration and access hooks used by this test. */
$app = new class extends Container {
public int $documentIdentifier = 1;
public int $denials = 0;
/** Return isolated configuration without bootstrapping a site. */
public function getConfig($name, $default = null) { return $default; }
/** Record an access denial without emitting a response. */
public function sendErrorPage(): void { $this->denials++; }
};
$GLOBALS['apiTestApp'] = $app;
$events = new Dispatcher($app);
$app->instance('events', $events);
Facade::setFacadeApplication($app);
if (!class_exists('Event', false)) { class_alias(Illuminate\Support\Facades\Event::class, 'Event'); }
require dirname(__DIR__, 2) . '/plugins/sMultisitePlugin.php';
$events->dispatch('evolution.OnWebPageInit', [[]]);
if ($app->bound('request') || $app->denials !== 0) { throw new RuntimeException('API event must not bind a request or deny access'); }

$app->instance('request', Illuminate\Http\Request::create('/private/'));
$app->instance('cache', new Illuminate\Cache\Repository(new Illuminate\Cache\ArrayStore()));
$_SERVER['REQUEST_URI'] = '/private/';
$events->dispatch('evolution.OnWebPageInit');
if ($app->denials !== 1) { throw new RuntimeException('Bound HTTP request must still deny a foreign resource'); }
$app['cache']->put('sMultisite-default-resources', [1]);
$events->dispatch('evolution.OnWebPageInit');
if ($app->denials !== 1) { throw new RuntimeException('Allowed HTTP resource must remain accessible'); }
echo "API and HTTP resource guards passed\n";
Loading