Add shop ribbon color styling to links in product and content descriptions

- Modify protect_links function to apply shop theme_link_color to all links
- Add custom CSS validation using regex patterns for security
- Support hex colors (#fff, #ffffff), rgb(), rgba(), hsl(), hsla(), and named colors
- Reject malicious inputs like javascript: schemes
- Add style attribute to allowed attributes for anchor tags
- Pass shop reference through cleaner object for color access
This commit is contained in:
Russell Ballestrini 2025-10-03 09:46:20 -04:00
parent 2657f982ec
commit 9432375bcb
2 changed files with 28 additions and 0 deletions

View file

@ -13,6 +13,8 @@ def make_cleaner_from_shop(shop):
"""Given a Shop return a bleach Cleaner object."""
cleaner = default_cleaner()
cleaner.link_protection = True
# Store shop reference for link color styling
cleaner.shop = shop
if shop.domain_name:
apex_domain_name = shop.domain_name.split(".")[-2:]
cleaner.whitelist_domains.append("makepostsell.com")

View file

@ -10,6 +10,8 @@ from bleach.callbacks import nofollow, target_blank
from bleach_allowlist import markdown_tags, markdown_attrs, all_styles
# We implement our own CSS validation in protect_links() for security
from bs4 import BeautifulSoup
import miniuri
@ -58,6 +60,11 @@ def default_cleaner(tag_acl=None):
attrs["img"].append("width")
attrs["img"].append("style")
attrs["span"] = ["class"]
# Allow style attribute on anchor tags for link color styling
if "a" not in attrs:
attrs["a"] = []
attrs["a"].append("style")
# Allow both whitelist and blacklist tag_name/attr/attr_value
# to get past bleach.
@ -78,6 +85,8 @@ def default_cleaner(tag_acl=None):
# attributes for the given tag_name.
attrs[tag_name].append(attr_name)
# We allow style attributes and validate CSS in protect_links function
# This provides targeted validation for the specific CSS we add (color property)
cleaner = Cleaner(tags=tags, attributes=attrs)
# doesn't do anything, but i used to be able to pass it via constructor.
@ -172,6 +181,23 @@ def protect_links(soup, cleaner):
for a_tag in soup.find_all("a"):
uri = miniuri.Uri(a_tag.attrs.get("href", ""))
# Add shop ribbon color styling to all links
if hasattr(cleaner, 'shop') and cleaner.shop:
link_color = cleaner.shop.theme_link_color
if link_color:
# Validate that the color looks like a valid CSS color
# Allow hex colors (#fff, #ffffff), rgb(), rgba(), hsl(), hsla(), and named colors
import re
color_pattern = r'^(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6}|rgb\([^)]+\)|rgba\([^)]+\)|hsl\([^)]+\)|hsla\([^)]+\)|[a-zA-Z]+)$'
if re.match(color_pattern, link_color.strip()):
# Get existing style or create new one
existing_style = a_tag.attrs.get("style", "")
if existing_style and not existing_style.endswith(";"):
existing_style += ";"
# Add color styling with validation
new_style = f"{existing_style}color:{link_color.strip()};"
a_tag.attrs["style"] = new_style
if uri.hostname in cleaner.whitelist_domains:
# domain in whitelist or relative URI so remove rel="nofollow".
a_tag.attrs.pop("rel", None)