Files
chatroom/tests/Feature/Feature/AdminChangelogControllerSecurityTest.php
T

83 lines
2.9 KiB
PHP
Raw Normal View History

2026-04-19 14:43:02 +08:00
<?php
/**
* 文件功能:后台更新日志安全测试
* 验证广播 payload 与系统消息在发布时会对危险标题进行转义。
*/
namespace Tests\Feature\Feature;
use App\Events\ChangelogPublished;
use App\Jobs\SaveMessageJob;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
/**
* 后台更新日志安全测试
* 负责回归标题进入广播和系统公告前会被安全处理。
*/
class AdminChangelogControllerSecurityTest extends TestCase
{
use RefreshDatabase;
/**
* 测试发布更新日志时会对广播字段与系统消息正文做 XSS 防护。
*/
public function test_published_changelog_escapes_title_for_broadcast_and_system_message(): void
{
Event::fake([ChangelogPublished::class]);
Queue::fake();
$admin = User::factory()->create([
'id' => 1,
'user_level' => 100,
]);
$dangerousTitle = '<img src=x onerror=alert(1)>';
$dangerousVersion = '2026-04-" onclick="alert(2)';
$response = $this->actingAs($admin)->post(route('admin.changelogs.store'), [
'version' => $dangerousVersion,
'title' => $dangerousTitle,
'type' => 'fix',
'content' => '修复说明',
'is_published' => '1',
'notify_chat' => '1',
]);
$response->assertRedirect(route('admin.changelogs.index'));
$this->assertDatabaseHas('dev_changelogs', [
'title' => $dangerousTitle,
'version' => $dangerousVersion,
'is_published' => true,
]);
Event::assertDispatched(ChangelogPublished::class, function (ChangelogPublished $event) use ($dangerousTitle, $dangerousVersion) {
$payload = $event->broadcastWith();
$this->assertSame($dangerousTitle, $payload['title']);
$this->assertSame(e($dangerousTitle), $payload['safe_title']);
$this->assertSame(e($dangerousVersion), $payload['safe_version']);
$this->assertStringContainsString(rawurlencode($dangerousVersion), $payload['url']);
$this->assertStringNotContainsString('" onclick="', $payload['url']);
return true;
});
Queue::assertPushed(SaveMessageJob::class, function (SaveMessageJob $job) use ($dangerousTitle, $dangerousVersion) {
$content = $job->messageData['content'] ?? '';
$this->assertStringContainsString(e($dangerousTitle), $content);
$this->assertStringContainsString(e($dangerousVersion), $content);
$this->assertStringContainsString('rel="noopener"', $content);
$this->assertStringContainsString(rawurlencode($dangerousVersion), $content);
$this->assertStringNotContainsString($dangerousTitle, $content);
return true;
});
}
}