# Sanitizer for rich text that a human authored in the admin panel and that the # panel later renders with `dangerouslySetInnerHTML` (BlogReviewPage). # # آدیت ۲۰۲۶-۰۸-۰۷: بدنهٔ مقاله همان‌طور که می‌آمد ذخیره و رندر می‌شد. CSP فعلی # (`script-src 'self'`) اسکریپت تزریقی را اجرا نمی‌کند، ولی هندلرهای inline و # `javascript:` را کامل نمی‌بندد — و CSP لایهٔ دوم است، نه اولین دفاع. پاک‌سازی # هنگام **ذخیره** انجام می‌شود نه هنگام نمایش، چون یک نقطهٔ ورود دارد و هر # مصرف‌کنندهٔ بعدی (پنل، سایت عمومی، فید) خودبه‌خود امن می‌شود. # # فهرست عناصر = چیزی که CKEditor 5 واقعاً تولید می‌کند. عنصری که اینجا نیست حذف # می‌شود ولی متنش می‌ماند، پس محتوای قدیمی نامفهوم نمی‌شود. framework: html_sanitizer: sanitizers: blog.body: allow_safe_elements: true allow_elements: p: [] br: [] hr: [] strong: [] b: [] em: [] i: [] u: [] s: [] sub: [] sup: [] mark: [] h1: [] h2: [] h3: [] h4: [] h5: [] h6: [] ul: [] ol: ['start', 'reversed'] li: [] blockquote: [] pre: [] code: [] figure: ['class'] figcaption: [] span: [] div: [] a: ['href', 'title', 'target', 'rel'] img: ['src', 'alt', 'title', 'width', 'height'] # سه attributeِ ظاهریِ قدیمیِ جدول عمداً مجازند. هیچ‌کدام # نمی‌توانند حاملِ اسکریپت یا URL باشند — مقدارشان عدد است — و # بدونشان جدولِ صدها مقالهٔ موجود حاشیه و فاصله‌اش را از دست # می‌داد. `style` همچنان ممنوع است: تنها attributeِ ظاهریِ این # جمع که می‌تواند بارِ اجرایی حمل کند. table: ['border', 'cellpadding', 'cellspacing'] thead: [] tbody: [] tfoot: [] tr: [] td: ['colspan', 'rowspan'] th: ['colspan', 'rowspan', 'scope'] # فقط طرح‌های امن. `javascript:` عمداً نیست. allowed_link_schemes: ['http', 'https', 'mailto'] allowed_media_schemes: ['http', 'https', 'data'] allow_relative_links: true # لینک بیرونی در تب جدید باز می‌شود؛ بدون این‌ها tabnabbing باز است. force_attributes: a: rel: 'noopener noreferrer' # `drop` نه `block`: block فقط تگ را برمی‌دارد و متنِ داخلش را نگه # می‌دارد، یعنی `` به متنِ `alert(1)` تبدیل # می‌شد. برای این عناصر، خودِ محتوا هم باید برود. drop_elements: ['script', 'style', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'noscript'] max_input_length: 500000