- ImageUploadService::store() now returns /assets/uploads/<token>/<file>
so the URL the upload handler emits matches the new GET route.
- public/index.php registers a dedicated GET /assets/uploads/{userToken}/{filename}
route; the legacy /assets/{kind}/{filename} is kept as a fallback.
- GetAssets reads the upload token from $request->server['__uploads_token']
(the front controller threads it that way) instead of the cookies bag.
- Adds GetAssets unit tests for the upload-token happy path and a
token-mismatch 404, plus a FullFlowTest step that uploads and re-fetches
the asset through the front controller.
128 lines
4.2 KiB
PHP
128 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace BattleForge\Tests\Integration;
|
|
|
|
use BattleForge\Http\Request;
|
|
use BattleForge\Http\Handlers\GetAssets;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class GetAssetsTest extends TestCase
|
|
{
|
|
private string $placeholderDir;
|
|
private string $uploadsDir;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->placeholderDir = sys_get_temp_dir() . '/bf-placeholders-' . bin2hex(random_bytes(4));
|
|
mkdir($this->placeholderDir, 0755, true);
|
|
// 1x1 red PNG
|
|
$png = base64_decode(
|
|
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==',
|
|
true,
|
|
);
|
|
file_put_contents($this->placeholderDir . '/defender.png', $png);
|
|
|
|
$this->uploadsDir = sys_get_temp_dir() . '/bf-assets-' . bin2hex(random_bytes(4));
|
|
mkdir($this->uploadsDir, 0700, true);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
if (is_dir($this->uploadsDir)) {
|
|
foreach (glob($this->uploadsDir . '/*/*') as $file) {
|
|
unlink($file);
|
|
}
|
|
foreach (glob($this->uploadsDir . '/*') as $dir) {
|
|
rmdir($dir);
|
|
}
|
|
rmdir($this->uploadsDir);
|
|
}
|
|
|
|
if (is_dir($this->placeholderDir)) {
|
|
foreach (glob($this->placeholderDir . '/*') as $file) {
|
|
unlink($file);
|
|
}
|
|
rmdir($this->placeholderDir);
|
|
}
|
|
}
|
|
|
|
public function testItServesAPlaceholderImageWithoutAuth(): void
|
|
{
|
|
$handler = new GetAssets($this->placeholderDir, $this->uploadsDir);
|
|
$request = new Request([], [], [], [], [], '', 'GET', '/assets/placeholders/defender.png', null, '');
|
|
$response = $handler->handle($request, ['kind' => 'placeholders', 'filename' => 'defender.png']);
|
|
|
|
self::assertSame(200, $response->status);
|
|
self::assertSame('image/png', $response->headers['Content-Type'] ?? '');
|
|
self::assertGreaterThan(0, strlen($response->body));
|
|
}
|
|
|
|
public function testItReturns404ForAMissingFile(): void
|
|
{
|
|
$handler = new GetAssets($this->placeholderDir, $this->uploadsDir);
|
|
$request = new Request([], [], [], [], [], '', 'GET', '/assets/placeholders/missing.png', null, '');
|
|
$response = $handler->handle($request, ['kind' => 'placeholders', 'filename' => 'missing.png']);
|
|
|
|
self::assertSame(404, $response->status);
|
|
}
|
|
|
|
public function testItServesAnUploadedAssetWhenTheServerTokenMatches(): void
|
|
{
|
|
$userToken = str_repeat('a', 64);
|
|
$namespace = $this->uploadsDir . '/' . $userToken;
|
|
mkdir($namespace, 0700, true);
|
|
$payload = base64_decode(
|
|
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==',
|
|
true,
|
|
);
|
|
file_put_contents($namespace . '/demo.png', $payload);
|
|
|
|
$handler = new GetAssets($this->placeholderDir, $this->uploadsDir);
|
|
$request = new Request(
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
['__uploads_token' => $userToken],
|
|
'',
|
|
'GET',
|
|
'/assets/uploads/' . $userToken . '/demo.png',
|
|
null,
|
|
'',
|
|
);
|
|
$response = $handler->handle(
|
|
$request,
|
|
['kind' => 'uploads', 'userToken' => $userToken, 'filename' => 'demo.png'],
|
|
);
|
|
|
|
self::assertSame(200, $response->status);
|
|
self::assertSame('image/png', $response->headers['Content-Type'] ?? '');
|
|
self::assertSame($payload, $response->body);
|
|
}
|
|
|
|
public function testItRefusesAnUploadedAssetWhenTheServerTokenDiffers(): void
|
|
{
|
|
$handler = new GetAssets($this->placeholderDir, $this->uploadsDir);
|
|
$request = new Request(
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
['__uploads_token' => str_repeat('a', 64)],
|
|
'',
|
|
'GET',
|
|
'/assets/uploads/abc/def.png',
|
|
null,
|
|
'',
|
|
);
|
|
$response = $handler->handle(
|
|
$request,
|
|
['kind' => 'uploads', 'userToken' => str_repeat('b', 64), 'filename' => 'def.png'],
|
|
);
|
|
|
|
self::assertSame(404, $response->status);
|
|
}
|
|
}
|