From 9432375bcbc8e32866ffa6468d0ed8d56b1b13ac Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Fri, 3 Oct 2025 09:46:20 -0400 Subject: [PATCH] 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 --- make_post_sell/lib/render.py | 2 ++ make_post_sell/lib/sanitize_html.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/make_post_sell/lib/render.py b/make_post_sell/lib/render.py index 58a7691..adb7f46 100644 --- a/make_post_sell/lib/render.py +++ b/make_post_sell/lib/render.py @@ -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") diff --git a/make_post_sell/lib/sanitize_html.py b/make_post_sell/lib/sanitize_html.py index 71b6792..9533178 100644 --- a/make_post_sell/lib/sanitize_html.py +++ b/make_post_sell/lib/sanitize_html.py @@ -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)