diff --git a/tests/unit/test_filters.py b/tests/unit/test_filters.py index b7c7a2ce04b9..e78ca40918f0 100644 --- a/tests/unit/test_filters.py +++ b/tests/unit/test_filters.py @@ -301,3 +301,36 @@ def test_remove_invalid_xml_unicode(inp, expected): Test that invalid XML unicode characters are removed. """ assert filters.remove_invalid_xml_unicode(inp) == expected + + +def test_show_share_image(): + # Missing user-agent header + assert filters.show_share_image(None) is True + # Empty user-agent header + assert filters.show_share_image("") is True + + # Twitter/X - shows image + # https://developer.x.com/en/docs/x-for-websites/cards/guides/troubleshooting-cards#validate_twitterbot + assert filters.show_share_image("Twitterbot/1.0") is True + + # Facebook - shows image + # https://developers.facebook.com/docs/sharing/webmasters/web-crawlers + assert ( + filters.show_share_image( + "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" + ) + is True + ) + assert filters.show_share_image("facebookexternalhit/1.1") is True + assert filters.show_share_image("facebookcatalog/1.0") is True + + # LinkedIn - shows image (https://www.linkedin.com/robots.txt) + assert filters.show_share_image("LinkedInBot") is True + + # Slack - don't show image (https://api.slack.com/robots) + assert ( + filters.show_share_image( + "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" + ) + is False + ) diff --git a/warehouse/config.py b/warehouse/config.py index 1014a1ca6dbe..2e025e2b2350 100644 --- a/warehouse/config.py +++ b/warehouse/config.py @@ -683,6 +683,7 @@ def configure(settings=None): filters.setdefault( "remove_invalid_xml_unicode", "warehouse.filters:remove_invalid_xml_unicode" ) + filters.setdefault("show_share_image", "warehouse.filters:show_share_image") # We also want to register some global functions for Jinja jglobals = config.get_settings().setdefault("jinja2.globals", {}) diff --git a/warehouse/filters.py b/warehouse/filters.py index 68364adfc6d3..43f2125b519e 100644 --- a/warehouse/filters.py +++ b/warehouse/filters.py @@ -201,3 +201,22 @@ def remove_invalid_xml_unicode(value: str | None) -> str | None: def includeme(config): config.add_request_method(_camo_url, name="camo_url") + + +def show_share_image(user_agent: str | None) -> bool: + """ + Whether the og:image meta-tag should be included based on the user-agent + + Used to exclude the image from Slack link-expansion. + + """ + + # User agent header not included or empty + if not user_agent: + return True + + # Don't show the og:image for Slackbot link-expansion requests + if user_agent.strip().startswith("Slackbot-LinkExpanding"): + return False + + return True diff --git a/warehouse/templates/base.html b/warehouse/templates/base.html index bdd7f2054c5e..11b371cc18c8 100644 --- a/warehouse/templates/base.html +++ b/warehouse/templates/base.html @@ -113,9 +113,13 @@ + {% if request.user_agent | show_share_image %} + {% endif %} + + {% block extra_meta %}{% endblock %}