feat: add BlogBodySanitizer for HTML sanitization on article save

- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks.
- Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content.
- Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
This commit is contained in:
hamed
2026-08-07 21:13:38 +03:30
parent a4a24c51af
commit 6876135a53
114 changed files with 2067 additions and 269 deletions
@@ -35,6 +35,7 @@ class RepresentationBlogController extends BaseController
private readonly CityRepository $cityRepo,
private readonly BlogWriter $writer,
private readonly BlogCacheInvalidator $cacheInvalidator,
private readonly \App\Blog\Service\BlogBodySanitizer $bodySanitizer,
) {}
private function currentRepresentation(User $user): Representation
@@ -106,7 +107,9 @@ class RepresentationBlogController extends BaseController
$data = json_decode($request->getContent(), true) ?? [];
$title = trim((string) ($data['title'] ?? ''));
$body = trim((string) ($data['body'] ?? ''));
// پاک‌سازی پیش از سنجشِ خالی‌بودن — بدنه‌ای که چیزی جز markup ناامن ندارد
// باید ۴۲۲ بگیرد نه اینکه خالی ذخیره شود.
$body = $this->bodySanitizer->clean(trim((string) ($data['body'] ?? '')));
if ($title === '' || $body === '') {
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'title و body الزامی است', 422);
}
@@ -140,7 +143,7 @@ class RepresentationBlogController extends BaseController
$data = json_decode($request->getContent(), true) ?? [];
if (array_key_exists('title', $data)) $blog->setTitle((string) $data['title']);
if (array_key_exists('body', $data)) $blog->setBody((string) $data['body']);
if (array_key_exists('body', $data)) $blog->setBody($this->bodySanitizer->clean((string) $data['body']));
if (array_key_exists('summary', $data)) $blog->setSummary($data['summary']);
if (array_key_exists('tags', $data)) $blog->setTags((array) $data['tags']);
if (array_key_exists('image_url', $data)) $blog->setImageUrl($data['image_url'] ?: null);