Enhance ValidatingEmbedBlock with strict host validation and update ArticlePage fields in migration
This commit is contained in:
parent
ee6eb0db17
commit
7c9fe7f6f9
@ -2,6 +2,8 @@ from django.core.exceptions import ValidationError
|
|||||||
from wagtail.embeds.blocks import EmbedBlock
|
from wagtail.embeds.blocks import EmbedBlock
|
||||||
from wagtail.embeds import embeds as wagtail_embeds
|
from wagtail.embeds import embeds as wagtail_embeds
|
||||||
from wagtail import blocks
|
from wagtail import blocks
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class ValidatingEmbedBlock(EmbedBlock):
|
class ValidatingEmbedBlock(EmbedBlock):
|
||||||
@ -13,13 +15,32 @@ class ValidatingEmbedBlock(EmbedBlock):
|
|||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
value = super().clean(value)
|
value = super().clean(value)
|
||||||
if value:
|
if value:
|
||||||
try:
|
# Inherit base validation (already run via super().clean), and add
|
||||||
# Attempt to resolve and cache embed; will raise on failure
|
# optional network validation for selected providers.
|
||||||
wagtail_embeds.get_embed(value)
|
url_str = value if isinstance(value, str) else getattr(value, "url", None)
|
||||||
except Exception:
|
if not url_str:
|
||||||
raise ValidationError(
|
return value
|
||||||
"嵌入連結無法驗證,請確認為公開且可嵌入的 URL。"
|
host = (urlparse(url_str).hostname or "").lower()
|
||||||
)
|
|
||||||
|
strict_hosts = getattr(
|
||||||
|
settings,
|
||||||
|
"EMBED_STRICT_HOSTS",
|
||||||
|
("instagram.com", "facebook.com"),
|
||||||
|
)
|
||||||
|
validate_all = getattr(settings, "EMBED_STRICT_VALIDATE_ALL", False)
|
||||||
|
|
||||||
|
def _matches(h: str) -> bool:
|
||||||
|
return host == h or host.endswith("." + h)
|
||||||
|
|
||||||
|
must_validate = bool(validate_all or any(_matches(h) for h in strict_hosts))
|
||||||
|
if must_validate:
|
||||||
|
try:
|
||||||
|
# Attempt to resolve and cache embed; will raise on failure
|
||||||
|
wagtail_embeds.get_embed(url_str)
|
||||||
|
except Exception:
|
||||||
|
raise ValidationError(
|
||||||
|
"嵌入連結無法驗證(需公開且有權杖)。請確認 URL 與設定。"
|
||||||
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-29 09:33
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import wagtail.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0007_articlepage_banner_image_alter_articlepage_body'),
|
||||||
|
('wagtailimages', '0027_image_description'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='articlepage',
|
||||||
|
name='banner_image',
|
||||||
|
field=models.ForeignKey(blank=True, help_text='文章內文橫幅圖片', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='articlepage',
|
||||||
|
name='body',
|
||||||
|
field=wagtail.fields.StreamField([('heading', 0), ('paragraph', 1), ('image', 2), ('embed', 3), ('hr', 4), ('html', 5)], block_lookup={0: ('home.blocks.H2HeadingBlock', (), {'form_classname': 'full title'}), 1: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'italic', 'link']}), 2: ('wagtail.images.blocks.ImageChooserBlock', (), {}), 3: ('home.blocks.ValidatingEmbedBlock', (), {}), 4: ('home.blocks.HorizontalRuleBlock', (), {}), 5: ('wagtail.blocks.RawHTMLBlock', (), {'help_text': '僅限信任來源的 blockquote/iframe 原始碼'})}),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='articlepage',
|
||||||
|
name='cover_image',
|
||||||
|
field=models.ForeignKey(blank=True, help_text='列表封面圖', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='articlepage',
|
||||||
|
name='recommended',
|
||||||
|
field=models.BooleanField(default=False, help_text='在推薦區塊顯示'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Loading…
x
Reference in New Issue
Block a user