This is an automated email from the ASF dual-hosted git repository. gcruz pushed a commit to branch gc/8596 in repository https://gitbox.apache.org/repos/asf/allura.git
commit 0e9324b3cff577c2f0445e4a89b283036f45445c Author: Guillermo Cruz <[email protected]> AuthorDate: Fri Feb 13 10:12:34 2026 -0700 [#8596] escape markdown and also html in notification email templates --- Allura/allura/config/app_cfg.py | 1 + Allura/allura/lib/helpers.py | 17 +++++++++++++++++ Allura/allura/model/notification.py | 2 ++ Allura/allura/tasks/mail_tasks.py | 1 - Allura/allura/templates/mail/Discussion.txt | 2 +- Allura/allura/templates/mail/MergeRequest.txt | 2 +- Allura/allura/templates/mail/Ticket.txt | 14 +++++++------- Allura/allura/templates/mail/bulk_export.html | 6 +++--- Allura/allura/templates/mail/claimed_existing_email.txt | 2 +- Allura/allura/templates/mail/commits.md | 4 ++-- Allura/allura/templates/mail/email_added.md | 4 ++-- Allura/allura/templates/mail/email_removed.md | 4 ++-- Allura/allura/templates/mail/footer.txt | 2 +- Allura/allura/templates/mail/monitor_email_footer.txt | 2 +- Allura/allura/templates/mail/password_changed.md | 4 ++-- Allura/allura/templates/mail/primary_email_changed.md | 4 ++-- Allura/allura/templates/mail/twofactor_disabled.md | 2 +- Allura/allura/templates/mail/twofactor_enabled.md | 2 +- Allura/allura/templates/mail/usermentions_email.md | 2 +- 19 files changed, 48 insertions(+), 29 deletions(-) diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py index 01df3da77..db663dbbf 100644 --- a/Allura/allura/config/app_cfg.py +++ b/Allura/allura/config/app_cfg.py @@ -190,6 +190,7 @@ def create(cls, config, app_globals): jinja2_env.filters['nl2br'] = helpers.nl2br_jinja_filter jinja2_env.filters['subrender'] = helpers.subrender_jinja_filter jinja2_env.filters['safe_html'] = helpers.clean_html + jinja2_env.filters['escape_markdown'] = helpers.escape_markdown jinja2_env.globals.update({ 'hasattr': hasattr, 'h': helpers, diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py index bc2f8cee2..8e1890168 100644 --- a/Allura/allura/lib/helpers.py +++ b/Allura/allura/lib/helpers.py @@ -74,6 +74,7 @@ import urllib.parse as urlparse from urllib.parse import urlencode import math +import markdown # import to make available to templates, don't delete: from .security import has_access, is_allowed_by_role, is_site_admin # noqa: F401 RUF100 @@ -1434,3 +1435,19 @@ def parse_fediverse_address(username: str): def clean_html(value: str) -> Markup: from allura.lib.markdown_extensions import HTMLSanitizer return Markup(HTMLSanitizer().run(value)) # noqa: S704 + + +def escape_markdown(content: str) -> str: + if content is None: + return '' + md = markdown.Markdown() + escaped_chars = md.ESCAPED_CHARS + if isinstance(escaped_chars, (list, tuple, set)): + escaped_chars = "".join(escaped_chars) + else: + escaped_chars = str(escaped_chars) + # escape html tag like <b> or <img> + html_escaped = html.escape(content, quote=True) + pattern = re.compile(rf"([{re.escape(escaped_chars)}])") + # Escape markdown special characters to prevent unintended formatting + return pattern.sub(r"\\\1", html_escaped) diff --git a/Allura/allura/model/notification.py b/Allura/allura/model/notification.py index 337411c3d..0cfe7ee93 100644 --- a/Allura/allura/model/notification.py +++ b/Allura/allura/model/notification.py @@ -111,6 +111,7 @@ class __mongometa__: loader=jinja2.PackageLoader('allura', 'templates'), auto_reload=asbool(config.get('auto_reload_templates', True)), ) + view.filters['escape_markdown'] = h.escape_markdown @classmethod def post(cls, artifact, topic, additional_artifacts_to_match_subscriptions=None, **kw): @@ -689,6 +690,7 @@ class MailFooter: loader=jinja2.PackageLoader('allura', 'templates'), auto_reload=asbool(config.get('auto_reload_templates', True)), ) + view.filters['escape_markdown'] = h.escape_markdown @classmethod def _render(cls, template, **kw): diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py index 75523b444..ea97f06b2 100644 --- a/Allura/allura/tasks/mail_tasks.py +++ b/Allura/allura/tasks/mail_tasks.py @@ -128,7 +128,6 @@ def replace_html(matchobj): ) plain_text = html.unescape(plain_text) # put literal HTML tags back into plaintext plain_msg = mail_util.encode_email_part(plain_text, 'plain') - html_text = ForgeMarkdown(email=True).convert(text) if metalink: html_text = html_text + mail_meta_content(metalink) diff --git a/Allura/allura/templates/mail/Discussion.txt b/Allura/allura/templates/mail/Discussion.txt index 21bfb51f2..f9e66b219 100644 --- a/Allura/allura/templates/mail/Discussion.txt +++ b/Allura/allura/templates/mail/Discussion.txt @@ -20,4 +20,4 @@ --- -[{{post.thread.subject|e}}]({{h.absurl(post.url_paginated())}}) +[{{post.thread.subject|escape_markdown}}]({{h.absurl(post.url_paginated())}}) diff --git a/Allura/allura/templates/mail/MergeRequest.txt b/Allura/allura/templates/mail/MergeRequest.txt index 3302abaa1..3ade1bdaa 100644 --- a/Allura/allura/templates/mail/MergeRequest.txt +++ b/Allura/allura/templates/mail/MergeRequest.txt @@ -20,6 +20,6 @@ --- -{{ data.creator_name }} has requested to merge changes from `{{ data.downstream_repo.clone_url_first(anon=False) }}` at commit `{{data.downstream_repo.shorthand_for_commit(data.downstream.commit_id)}}` into the branch `{{ data.target_branch }}` +{{ data.creator_name|escape_markdown }} has requested to merge changes from `{{ data.downstream_repo.clone_url_first(anon=False) }}` at commit `{{data.downstream_repo.shorthand_for_commit(data.downstream.commit_id)}}` into the branch `{{ data.target_branch|escape_markdown }}` {{ data.description }} diff --git a/Allura/allura/templates/mail/Ticket.txt b/Allura/allura/templates/mail/Ticket.txt index fc5b4ae30..e73d9e5cc 100644 --- a/Allura/allura/templates/mail/Ticket.txt +++ b/Allura/allura/templates/mail/Ticket.txt @@ -20,25 +20,25 @@ --- -**[{{data.app_config.options.mount_point}}:#{{data.ticket_num}}] {{data.summary|e}}** +**[{{data.app_config.options.mount_point}}:#{{data.ticket_num}}] {{data.summary|escape_markdown}}** -**Status:** {{data.status}} +**Status:** {{data.status|escape_markdown}} {% for f in data.globals.milestone_fields -%} - **{{ f.label }}:** {{ data.custom_fields.get(f.name, '') }} + **{{ f.label|escape_markdown }}:** {{ data.custom_fields.get(f.name, '')|escape_markdown }} {% endfor -%} {% if data.labels.__len__() -%} - **Labels:** {% for label in data.labels %}{{label}} {% else %}None{% endfor %} + **Labels:** {% for label in data.labels %}{{label|escape_markdown}} {% else %}None{% endfor %} {% endif -%} -**Created:** {{data.created_date.strftime('%a %b %d, %Y %I:%M %p UTC')}} by {{data.reported_by.display_name}} +**Created:** {{data.created_date.strftime('%a %b %d, %Y %I:%M %p UTC')}} by {{data.reported_by.display_name|escape_markdown}} {% if (data.mod_date - data.created_date).days >= 0 -%} **Last Updated:** {{data.mod_date.strftime('%a %b %d, %Y %I:%M %p UTC')}} {% endif -%} -**Owner:** {{data.assigned_to_name()}} +**Owner:** {{data.assigned_to_name()|escape_markdown}} {% if data.attachments -%} **Attachments:** {% for att in data.attachments -%} - - [{{att.filename}}]({{h.absurl(att.url())}}) ({{h.do_filesizeformat(att.length)}}; {{att.content_type}}) + - [{{att.filename|escape_markdown}}]({{h.absurl(att.url())}}) ({{h.do_filesizeformat(att.length)}}; {{att.content_type}}) {% endfor -%} {% endif %} diff --git a/Allura/allura/templates/mail/bulk_export.html b/Allura/allura/templates/mail/bulk_export.html index e8aded10f..b135041ac 100644 --- a/Allura/allura/templates/mail/bulk_export.html +++ b/Allura/allura/templates/mail/bulk_export.html @@ -17,19 +17,19 @@ under the License. #} -The bulk export for project {{ project.shortname }} is completed. +The bulk export for project {{ project.shortname|escape_markdown }} is completed. {% if tools %} The following tools were exported: {% for tool in tools -%} -- {{ tool }} +- {{ tool|escape_markdown }} {% endfor %} {% endif %} {% if not_exported_tools %} The following tools were not exported: {% for tool in not_exported_tools -%} -- {{ tool }} +- {{ tool|escape_markdown }} {% endfor %} {% endif %} diff --git a/Allura/allura/templates/mail/claimed_existing_email.txt b/Allura/allura/templates/mail/claimed_existing_email.txt index ead38a808..cda4ceca9 100644 --- a/Allura/allura/templates/mail/claimed_existing_email.txt +++ b/Allura/allura/templates/mail/claimed_existing_email.txt @@ -17,6 +17,6 @@ under the License. #} -You tried to add {{ email.email }} to your {{ config['site_name'] }} account, but it is already claimed by your {{ user.username }} account. +You tried to add {{ email.email }} to your {{ config['site_name'] }} account, but it is already claimed by your {{ user.username|escape_markdown }} account. You should use that account instead, or remove that address from that account. If this was not you who attempted this, you can safely ignore this email. diff --git a/Allura/allura/templates/mail/commits.md b/Allura/allura/templates/mail/commits.md index 1b1d043c4..e61b5b3a7 100644 --- a/Allura/allura/templates/mail/commits.md +++ b/Allura/allura/templates/mail/commits.md @@ -18,11 +18,11 @@ --> #} {%- for cm in commit_msgs[:max_num_commits] %} {%- if cm.branches and cm.show_branch_name|default %} -## Branch: {% for b in cm.branches %}{{ b }} {% endfor%} +## Branch: {% for b in cm.branches %}{{ b|escape_markdown }} {% endfor%} {% endif %} {{ cm.summary }} -By {{ cm.author }} on {{ cm.date }} +By {{ cm.author|escape_markdown }} on {{ cm.date }} [**View Changes**]({{ cm.commit_url }}) {% if not loop.last %}-----{% endif %} diff --git a/Allura/allura/templates/mail/email_added.md b/Allura/allura/templates/mail/email_added.md index eace71880..3090c43ff 100644 --- a/Allura/allura/templates/mail/email_added.md +++ b/Allura/allura/templates/mail/email_added.md @@ -17,9 +17,9 @@ under the License. -#} -Hello {{ user.display_name }}, +Hello {{ user.display_name|escape_markdown }}, -A new email address was added to your {{ config['site_name'] }} account "{{ user.username }}": +A new email address was added to your {{ config['site_name'] }} account "{{ user.username|escape_markdown }}": * {{ addr }} diff --git a/Allura/allura/templates/mail/email_removed.md b/Allura/allura/templates/mail/email_removed.md index 323ea17e2..2758eca70 100644 --- a/Allura/allura/templates/mail/email_removed.md +++ b/Allura/allura/templates/mail/email_removed.md @@ -17,9 +17,9 @@ under the License. -#} -Hello {{ user.display_name }}, +Hello {{ user.display_name|escape_markdown }}, -An email address was removed from your {{ config['site_name'] }} account "{{ user.username }}": +An email address was removed from your {{ config['site_name'] }} account "{{ user.username|escape_markdown }}": * {{ addr }} diff --git a/Allura/allura/templates/mail/footer.txt b/Allura/allura/templates/mail/footer.txt index 62de8623f..08a7e08b8 100644 --- a/Allura/allura/templates/mail/footer.txt +++ b/Allura/allura/templates/mail/footer.txt @@ -20,7 +20,7 @@ --- -Sent from {{domain}} because you indicated interest in <{{ prefix }}{{ notification.link }}> +Sent from {{domain|escape_markdown}} because you indicated interest in <{{ prefix }}{{ notification.link }}> {% if discussion_disabled %} Please do not reply to this message. Discussion is disabled for the <{{ prefix }}{{ notification.link }}> diff --git a/Allura/allura/templates/mail/monitor_email_footer.txt b/Allura/allura/templates/mail/monitor_email_footer.txt index d3492ca37..f2290e12c 100644 --- a/Allura/allura/templates/mail/monitor_email_footer.txt +++ b/Allura/allura/templates/mail/monitor_email_footer.txt @@ -20,6 +20,6 @@ --- -Sent from {{domain}} because {{email}} is subscribed to {{app_url}} +Sent from {{domain}} because {{email|escape_markdown}} is subscribed to {{app_url}} To unsubscribe from further messages, a project admin can change settings at {{setting_url}}. Or, if this is a mailing list, you can unsubscribe from the mailing list. diff --git a/Allura/allura/templates/mail/password_changed.md b/Allura/allura/templates/mail/password_changed.md index 10e062ff0..db6cc4059 100644 --- a/Allura/allura/templates/mail/password_changed.md +++ b/Allura/allura/templates/mail/password_changed.md @@ -17,9 +17,9 @@ under the License. -#} -Hello {{ user.display_name }}, +Hello {{ user.display_name|escape_markdown }}, -The password for your {{ config['site_name'] }} account "{{ user.username }}" has been changed. This is a confirmation email, you are all set. +The password for your {{ config['site_name'] }} account "{{ user.username|escape_markdown }}" has been changed. This is a confirmation email, you are all set. {% block footer %} If you did not do this, please contact us immediately. diff --git a/Allura/allura/templates/mail/primary_email_changed.md b/Allura/allura/templates/mail/primary_email_changed.md index 2830b1c2f..fd6dec35b 100644 --- a/Allura/allura/templates/mail/primary_email_changed.md +++ b/Allura/allura/templates/mail/primary_email_changed.md @@ -17,9 +17,9 @@ under the License. -#} -Hello {{ user.display_name }}, +Hello {{ user.display_name|escape_markdown }}, -The primary email address on your {{ config['site_name'] }} account "{{ user.username }}" was changed to: +The primary email address on your {{ config['site_name'] }} account "{{ user.username|escape_markdown }}" was changed to: * {{ addr }} diff --git a/Allura/allura/templates/mail/twofactor_disabled.md b/Allura/allura/templates/mail/twofactor_disabled.md index 3e4e619b0..e7e0a868f 100644 --- a/Allura/allura/templates/mail/twofactor_disabled.md +++ b/Allura/allura/templates/mail/twofactor_disabled.md @@ -17,7 +17,7 @@ under the License. -#} -Hello {{ user.username }}, +Hello {{ user.username|escape_markdown }}, You have recently disabled two-factor authentication on {{ config['site_name'] }}. :( diff --git a/Allura/allura/templates/mail/twofactor_enabled.md b/Allura/allura/templates/mail/twofactor_enabled.md index e2d0ca06f..6e0734349 100644 --- a/Allura/allura/templates/mail/twofactor_enabled.md +++ b/Allura/allura/templates/mail/twofactor_enabled.md @@ -17,7 +17,7 @@ under the License. -#} -Hello {{ user.username }}, +Hello {{ user.username|escape_markdown }}, You have recently set up new two-factor authentication on {{ config['site_name'] }}. This is a confirmation email, you are all set. diff --git a/Allura/allura/templates/mail/usermentions_email.md b/Allura/allura/templates/mail/usermentions_email.md index 98763ca69..836c315a1 100644 --- a/Allura/allura/templates/mail/usermentions_email.md +++ b/Allura/allura/templates/mail/usermentions_email.md @@ -16,7 +16,7 @@ specific language governing permissions and limitations under the License. -#} -Your name was mentioned at [{{artifact_linktext}}]({{artifact_link}}) by {{mentioned_by.display_name}} +Your name was mentioned at [{{artifact_linktext|escape_markdown}}]({{artifact_link}}) by {{mentioned_by.display_name|escape_markdown}} It can be viewed using the link below: {{artifact_link}}
