Skip to content

Commit

Permalink
Permalinks: look up from index if cache empty
Browse files Browse the repository at this point in the history
  • Loading branch information
distantnative committed Jul 24, 2024
1 parent 32d11a9 commit db11136
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 17 deletions.
17 changes: 12 additions & 5 deletions config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kirby\Panel\Plugins;
use Kirby\Toolkit\Str;
use Kirby\Uuid\Uuid;
use Kirby\Uuid\Uuids;

return function (App $kirby) {
$api = $kirby->option('api.slug', 'api');
Expand Down Expand Up @@ -135,11 +136,17 @@
'method' => 'ALL',
'env' => 'site',
'action' => function (string $type, string $id) use ($kirby) {
// try to resolve to model, but only from UUID cache;
// this ensures that only existing UUIDs can be queried
// and attackers can't force Kirby to go through the whole
// site index with a non-existing UUID
if ($model = Uuid::for($type . '://' . $id)?->model(true)) {
// try to resolve to model but if the UUID cache exists
// only allow lookup from the cache;
// only if the cache doesn't exist, use the index;
// this ensures that attackers can't force Kirby to go through
// the whole site index with a non-existing UUID
$lazy = Uuids::cache()->isEmpty() === false;

if ($model = Uuid::for($type . '://' . $id)?->model($lazy)) {
/**
* @var \Kirby\Cms\Page|\Kirby\Cms\File $model
*/
return $kirby
->response()
->redirect($model->url());
Expand Down
32 changes: 20 additions & 12 deletions tests/Uuid/PermalinksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,37 @@ public function testRoute()
[
'slug' => 'a',
'content' => ['uuid' => 'my-id']
],
[
'slug' => 'b',
'content' => ['uuid' => 'my-other-id']
]
]
]
]);

// not cached, should fail (redirect to error)
$response = $app->call('/@/page/my-id');
$this->assertFalse($response);
$this->assertTrue(Uuids::cache()->isEmpty());
$uuid = $app->page('a')->uuid();

// cached, should redirect to page A
$app->page('a')->uuid()->populate();
$response = $app->call('/@/page/my-id')->send();
// not cached, but cache is empty => using index to find it
$this->assertFalse($uuid->isCached());
$response = $app->call('/@/page/my-id');
$this->assertSame(302, $response->code());
$this->assertSame('https://getkirby.com/a', $response->header('Location'));

// check if ->url() populates cache
$uuid = $app->page('a')->uuid();
$uuid->clear();
// now cached, redirect from cache
$this->assertTrue($uuid->isCached());
$response = $app->call('/@/page/my-id');
$this->assertFalse($response);
$uuid->url();
$response = $app->call('/@/page/my-id')->send();
$this->assertSame(302, $response->code());
$this->assertSame('https://getkirby.com/a', $response->header('Location'));

// not cached but cache isn't empty => fail to prevent attacks
$uuid->clear();
$app->page('b')->uuid()->populate();
$this->assertFalse($uuid->isCached());
$this->assertFalse(Uuids::cache()->isEmpty());

$response = $app->call('/@/page/my-id');
$this->assertSame(false, $response);
}
}

0 comments on commit db11136

Please sign in to comment.