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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ This serves two purposes:
- Updated the scroll to top button to smooth scroll to the top of the page in https://github.com/hydephp/develop/pull/2458
- Fix build command trying to use Vite in site builds if server is running in https://github.com/hydephp/develop/issues/2483
- Fixed missing content type headers for JSON and XML in the realtime compiler in https://github.com/hydephp/develop/pull/2496
- Fixed dashboard links not resolving properly when there is a trailing slash in the URL in https://github.com/hydephp/develop/pull/2499

### Security
- in case of vulnerabilities.
Expand Down
6 changes: 3 additions & 3 deletions packages/realtime-compiler/resources/dashboard.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@
@endif
</form>
@endif
<a href="{{ $route->getLink() }}" class="btn btn-outline-primary btn-sm" title="Open this page preview in browser">View</a>
<a href="{{ $dashboard->getRoutePreviewLink($route) }}" class="btn btn-outline-primary btn-sm" title="Open this page preview in browser">View</a>
</div>
</td>
</tr>
Expand Down Expand Up @@ -300,7 +300,7 @@
<div class="col-lg-4 p-2 d-flex flex-grow-1">
<figure class="card w-100 p-2 mb-0">
@if(in_array($mediaFile->getExtension(), ['svg', 'png', 'jpg', 'jpeg', 'gif', 'ico']))
<img loading="lazy" src="media/{{ $mediaFile->getIdentifier() }}" alt="{{ $mediaFile->getName() }}" class="object-fit-cover w-100 rounded-2" style="height: 240px;">
<img loading="lazy" src="{{ $dashboard->getMediaPreviewLink($mediaFile) }}" alt="{{ $mediaFile->getName() }}" class="object-fit-cover w-100 rounded-2" style="height: 240px;">
@else
<code style="height: 240px; overflow: hidden; -webkit-mask-image: linear-gradient(180deg, white 60%, transparent);" role="presentation">
@if($dashboard::isMediaFileProbablyMinified($mediaFile->getContents()))
Expand All @@ -326,7 +326,7 @@
</div>
<div class="row small align-items-center">
<div class="w-auto pe-0">
<a href="media/{{ $mediaFile->getIdentifier() }}" title="Open this image in the browser" target="_blank">Fullscreen</a>
<a href="{{ $dashboard->getMediaPreviewLink($mediaFile) }}" title="Open this image in the browser" target="_blank">Fullscreen</a>
</div>
@if($dashboard->isInteractive())
<div class="w-auto ps-0">
Expand Down
26 changes: 26 additions & 0 deletions packages/realtime-compiler/src/Http/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Desilva\Microserve\JsonResponse;
use Desilva\Microserve\HtmlResponse;
use Hyde\Support\Filesystem\MediaFile;
use Hyde\Support\Models\Route;
use Illuminate\Support\Facades\Process;
use Hyde\Framework\Actions\StaticPageBuilder;
use Hyde\Framework\Actions\AnonymousViewCompiler;
Expand Down Expand Up @@ -135,6 +136,31 @@ public function getPageList(): array
return Hyde::routes()->all();
}

public function getRoutePreviewLink(Route $route): string
{
return $this->rootRelativeLink($route->getLink());
}

public function getMediaPreviewLink(MediaFile $mediaFile): string
{
return $this->rootRelativeLink('media/'.$mediaFile->getIdentifier());
}

protected function rootRelativeLink(string $link): string
{
if (str_starts_with($link, '#') || preg_match('/^[a-z][a-z0-9+.-]*:/i', $link) || str_starts_with($link, '//')) {
return $link;
}

if ($link === './') {
return '/';
}

$link = preg_replace('#^(\.\./)+#', '', $link) ?? $link;

return '/'.ltrim($link, '/');
}

/** @internal */
public static function bytesToHuman(int $bytes, int $precision = 2): string
{
Expand Down
27 changes: 27 additions & 0 deletions packages/realtime-compiler/tests/RealtimeCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,33 @@ public function testPingRouteReturnsPingResponse()
$this->assertSame('OK', $response->statusMessage);
}

public function testDashboardLinksAreRootRelativeWhenAccessedWithTrailingSlash()
{
$dashboardEnvironment = getenv('SERVER_DASHBOARD');
putenv('SERVER_DASHBOARD=true');
$this->mockCompilerRoute('dashboard/');

Filesystem::put('_pages/foo.md', '# Hello World!');
Filesystem::put('_media/test.css', 'body {}');

try {
$kernel = new HttpKernel();
$response = $kernel->handle(new Request());

$this->assertInstanceOf(HtmlResponse::class, $response);
$this->assertSame(200, $response->statusCode);
$this->assertSame('OK', $response->statusMessage);
$this->assertStringContainsString('href="/foo.html"', $response->body);
$this->assertStringContainsString('href="/media/test.css"', $response->body);
$this->assertStringNotContainsString('href="foo.html"', $response->body);
$this->assertStringNotContainsString('href="media/test.css"', $response->body);
} finally {
Filesystem::unlink('_pages/foo.md');
Filesystem::unlink('_media/test.css');
putenv($dashboardEnvironment === false ? 'SERVER_DASHBOARD' : "SERVER_DASHBOARD=$dashboardEnvironment");
}
}

public function testExceptionHandling()
{
$exception = new Exception('foo');
Expand Down
Loading