87 lines
3.1 KiB
PHP
87 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Security\Authorization;
|
|
|
|
use App\Http\Livewire\WireChat\Chat\Chat;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Livewire\Features\SupportFileUploads\FileUploadConfiguration;
|
|
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* WireChat overrides Livewire's _finishUpload(). Since Livewire 3.8 the upload references it
|
|
* receives are signed ("token:path"); the override must verify and strip the signature.
|
|
*
|
|
* @group security
|
|
*/
|
|
class WireChatUploadTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function openChat(): \Livewire\Features\SupportTesting\Testable
|
|
{
|
|
$user = User::factory()->create();
|
|
$recipient = User::factory()->create();
|
|
$this->actingAs($user, 'web');
|
|
session(['activeProfileType' => User::class, 'activeProfileId' => $user->id, 'active_guard' => 'web']);
|
|
|
|
$conversation = $user->sendMessageTo($recipient, 'Hello')->conversation;
|
|
|
|
return Livewire::test(Chat::class, ['conversation' => $conversation->id]);
|
|
}
|
|
|
|
/** A temporary upload as Livewire's upload endpoint stores it */
|
|
private function storeTemporaryUpload(): string
|
|
{
|
|
$name = TemporaryUploadedFile::generateHashNameWithOriginalNameEmbedded(UploadedFile::fake()->image('photo.jpg', 40, 40));
|
|
Storage::disk(FileUploadConfiguration::disk())->putFileAs(
|
|
FileUploadConfiguration::path(), UploadedFile::fake()->image('photo.jpg', 40, 40), $name
|
|
);
|
|
|
|
return $name;
|
|
}
|
|
|
|
/** @test */
|
|
public function a_signed_upload_reference_becomes_a_usable_file(): void
|
|
{
|
|
$name = $this->storeTemporaryUpload();
|
|
|
|
$chat = $this->openChat()
|
|
->call('_finishUpload', 'media', [TemporaryUploadedFile::signPath('/' . $name)], false);
|
|
|
|
$media = $chat->instance()->media;
|
|
$this->assertCount(1, $media);
|
|
$this->assertSame($name, $media[0]->getFilename());
|
|
// The file must resolve to the stored upload (sending in the same request reads its size)
|
|
$this->assertTrue($media[0]->exists());
|
|
$this->assertGreaterThan(0, $media[0]->getSize());
|
|
}
|
|
|
|
/** @test */
|
|
public function uploads_are_appended_like_wirechat_expects(): void
|
|
{
|
|
$first = $this->storeTemporaryUpload();
|
|
$second = $this->storeTemporaryUpload();
|
|
|
|
$chat = $this->openChat()
|
|
->call('_finishUpload', 'media', [TemporaryUploadedFile::signPath('/' . $first)], false)
|
|
->call('_finishUpload', 'media', [TemporaryUploadedFile::signPath('/' . $second)], false);
|
|
|
|
$this->assertSame([$first, $second], collect($chat->instance()->media)->map->getFilename()->all());
|
|
}
|
|
|
|
/** @test */
|
|
public function a_tampered_upload_reference_is_refused(): void
|
|
{
|
|
$name = $this->storeTemporaryUpload();
|
|
|
|
$this->openChat()
|
|
->call('_finishUpload', 'media', ['deadbeef:/' . $name], false)
|
|
->assertForbidden();
|
|
}
|
|
}
|