diff --git a/changelog.d/376.feature b/changelog.d/376.feature new file mode 100644 index 00000000..d1ad46ee --- /dev/null +++ b/changelog.d/376.feature @@ -0,0 +1 @@ +Add support for using Jinja2 in e-mail templates. Contributed by H-Shay. \ No newline at end of file diff --git a/matrix_is_test/res/is-test/invite_template.eml.j2 b/matrix_is_test/res/is-test/invite_template.eml.j2 new file mode 100644 index 00000000..0b09cb12 --- /dev/null +++ b/matrix_is_test/res/is-test/invite_template.eml.j2 @@ -0,0 +1,8 @@ +{ + "token": "{{ token }}", + "room_alias": "{{ room_alias }}", + "room_avatar_url": "{{ room_avatar_url }}", + "room_name": "{{ room_name }}", + "sender_display_name": "{{ sender_display_name }}", + "sender_avatar_url": "{{ sender_avatar_url }}" +} diff --git a/matrix_is_test/res/is-test/verification_template.eml.j2 b/matrix_is_test/res/is-test/verification_template.eml.j2 new file mode 100644 index 00000000..d74f9a83 --- /dev/null +++ b/matrix_is_test/res/is-test/verification_template.eml.j2 @@ -0,0 +1 @@ +<<<{{ token }}>>> diff --git a/res/matrix-org/invite_template.eml.j2 b/res/matrix-org/invite_template.eml.j2 new file mode 100644 index 00000000..9fd23212 --- /dev/null +++ b/res/matrix-org/invite_template.eml.j2 @@ -0,0 +1,146 @@ +Date: {{ date|safe }} +From: {{ from|safe }} +To: {{ to|safe }} +Message-ID: {{ messageid|safe }} +Subject: {{ subject_header_value|safe }} +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="{{ multipart_boundary|safe }}" + +--{{ multipart_boundary|safe }} +Content-Type: text/plain; charset=UTF-8 +Content-Disposition: inline + +Hi, + +{{ sender_display_name|safe }} {{ bracketed_verified_sender|safe }}has invited you into a room +{{ bracketed_room_name|safe }}on Matrix. To join the conversation, either pick a +Matrix client from https://matrix.org/docs/projects/try-matrix-now.html or use +the single-click link below to join via Element (requires Chrome, Firefox, +Safari, iOS or Android) + + +{{ web_client_location }}/#/room/{{ room_id|urlencode }}?email={{ to|urlencode }}&signurl=https%3A%2F%2Fmatrix.org%2F_matrix%2Fidentity%2Fapi%2Fv1%2Fsign-ed25519%3Ftoken%3D{{ token|urlencode }}%26private_key%3D{{ ephemeral_private_key|urlencode }}&room_name={{ room_name|urlencode }}&room_avatar_url={{ room_avatar_url|urlencode }}&inviter_name={{ sender_display_name|urlencode }}&guest_access_token={{ guest_access_token|urlencode }}&guest_user_id={{ guest_user_id|urlencode }} + + +About Matrix: + +Matrix.org is an open standard for interoperable, decentralised, real-time communication +over IP, supporting group chat, file transfer, voice and video calling, integrations to +other apps, bridges to other communication systems and much more. It can be used to power +Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere +you need a standard HTTP API for publishing and subscribing to data whilst tracking the +conversation history. + +Matrix defines the standard, and provides open source reference implementations of +Matrix-compatible Servers, Clients, Client SDKs and Application Services to help you +create new communication solutions or extend the capabilities and reach of existing ones. + +Thanks, + +Matrix + +--{{ multipart_boundary|safe }} +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + + + + + +
+ + + + + +
+
+ +

Hi,

+ +

{{ sender_display_name }} {{ bracketed_verified_sender }} has invited you into a room {{ bracketed_room_name }} on +Matrix. To join the conversation, either pick a Matrix client or use the single-click +link below to join via Element (requires +Chrome, +Firefox or +Safari on the web, +or iOS or Android on mobile.)

+

+ +

+ Join the conversation. +

+ +
+

About Matrix:

+ +

Matrix.org is an open standard for interoperable, decentralised, real-time communication +over IP, supporting group chat, file transfer, voice and video calling, integrations to +other apps, bridges to other communication systems and much more. It can be used to power +Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere +you need a standard HTTP API for publishing and subscribing to data whilst tracking the +conversation history.

+ +

Matrix defines the standard, and provides open source reference implementations of +Matrix-compatible Servers, Clients, Client SDKs and Application Services to help you +create new communication solutions or extend the capabilities and reach of existing ones.

+ +

Thanks,

+ +

Matrix

+
+ + + +--{{ multipart_boundary|safe }}-- diff --git a/res/matrix-org/verification_template.eml.j2 b/res/matrix-org/verification_template.eml.j2 new file mode 100644 index 00000000..fffbb87e --- /dev/null +++ b/res/matrix-org/verification_template.eml.j2 @@ -0,0 +1,88 @@ +Date: {{ date|safe }} +From: {{ from|safe }} +To: {{ to|safe }} +Message-ID: {{ messageid|safe }} +Subject: Confirm your email address for Matrix +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="{{ multipart_boundary|safe }}" + +--{{ multipart_boundary|safe }} +Content-Type: text/plain; charset=UTF-8 +Content-Disposition: inline + +Hello, + +We have received a request to use this email address with a matrix.org identity +server. If this was you who made this request, you may use the following link +to complete the verification of your email address: + +{{ link|safe }} + +If your client requires a code, the code is {{ token|safe }} + +If you aren't aware of making such a request, please disregard this email. + + +About Matrix: + +Matrix is an open standard for interoperable, decentralised, real-time communication +over IP. It can be used to power Instant Messaging, VoIP/WebRTC signalling, Internet +of Things communication - or anywhere you need a standard HTTP API for publishing and +subscribing to data whilst tracking the conversation history. + +Matrix defines the standard, and provides open source reference implementations of +Matrix-compatible Servers, Clients, Client SDKs and Application Services to help you +create new communication solutions or extend the capabilities and reach of existing ones. + +--{{ multipart_boundary|safe }} +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + +

Hello,

+ +

We have received a request to use this email address with a matrix.org +identity server. If this was you who made this request, you may use the +following link to complete the verification of your email address:

+ +

Complete email verification

+ +

...or copy this link into your web browser:

+ +

{{ link }}

+ +

If your client requires a code, the code is {{ token }}

+ +

If you aren't aware of making such a request, please disregard this +email.

+ +
+

About Matrix:

+ +

Matrix is an open standard for interoperable, decentralised, real-time communication +over IP. It can be used to power Instant Messaging, VoIP/WebRTC signalling, Internet +of Things communication - or anywhere you need a standard HTTP API for publishing and +subscribing to data whilst tracking the conversation history.

+ +

Matrix defines the standard, and provides open source reference implementations of +Matrix-compatible Servers, Clients, Client SDKs and Application Services to help you +create new communication solutions or extend the capabilities and reach of existing ones.

+ + + + +--{{ multipart_boundary|safe }}-- diff --git a/res/vector-im/invite_template.eml.j2 b/res/vector-im/invite_template.eml.j2 new file mode 100644 index 00000000..d35a4342 --- /dev/null +++ b/res/vector-im/invite_template.eml.j2 @@ -0,0 +1,177 @@ +Date: {{ date|safe }} +From: {{ from|safe }} +To: {{ to|safe }} +Message-ID: {{ messageid|safe }} +Subject: {{ subject_header_value|safe }} +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="{{ multipart_boundary|safe }}" + +--{{ multipart_boundary|safe }} +Content-Type: text/plain; charset=UTF-8 +Content-Disposition: inline + +Hi, + +{{ sender_display_name|safe }} {{ bracketed_verified_sender|safe }}has invited you into a room +{{ bracketed_room_name|safe }}on Element. To join the conversation please follow the +link below. + +{{ web_client_location }}/#/room/{{ room_id|urlencode }}?email={{ to|urlencode }}&signurl=https%3A%2F%2Fvector.im%2F_matrix%2Fidentity%2Fapi%2Fv1%2Fsign-ed25519%3Ftoken%3D{{ token|urlencode }}%26private_key%3D{{ ephemeral_private_key|urlencode }}&room_name={{ room_name|urlencode }}&room_avatar_url={{ room_avatar_url|urlencode }}&inviter_name={{ sender_display_name|urlencode }}&guest_access_token={{ guest_access_token|urlencode }}&guest_user_id={{ guest_user_id|urlencode }} + +Element is an open source collaboration app built on the Matrix.org +open standard for interoperable communication: supporting group chat, +file transfer, voice and video calling, integrations to other apps, bridges +to other communication systems and much more. + +Please note that you will need to use Chrome, Firefox or Safari on the web, or +iOS or Android on mobile. + +Thanks, + +Element + + +About Element: + +Break through - Element allows teams to communicate across a wide range of collaboration +apps. If some team members use Element while others use IRC, Slack or Gitter, Element will +allow these team members to seamlessly work together. Element offers the richest +network of communication bridges. + +Own Your Own Data - No one should control your communication and data but you. Element +lets you run your own server, and provides users and teams with the most advanced +crypto ratchet technology available today for a decentralized secure Internet. + +Open Source - Element is entirely open source: all the code is published on GitHub +(Apache License) for anyone to see and extend. This means teams can customize or +contribute to the code and everyone can benefit from the speed of community innovation. + +Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, +decentralized communication delivering a community of users, bridged networks, +integrated bots and applications plus full end-to-end encryption. To learn more about +Matrix visit https://matrix.org. + +--{{ multipart_boundary|safe }} +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + + + + + +
+ + + + + +
+
+ +

Hi,

+ +

{{ sender_display_name }} {{ bracketed_verified_sender }} has invited you into a +room {{ bracketed_room_name }} on Element.

+ +

+ Join the conversation. +

+ +

Element is an open source collaboration app built on the Matrix.org +open standard for interoperable communication: supporting group chat, file +transfer, voice and video calling, integrations to other apps, bridges +to other communication systems and much more.

+ +

Please note that Element requires +Chrome, +Firefox or +Safari on the web, +or iOS or Android on mobile.

+ +

Thanks,

+ +

Element

+ +
+

About Element:

+ +

Break through - Element allows teams to communicate across a wide range of collaboration +apps. If some team members use Element while others use IRC, Slack or Gitter, Element will +allow these team members to seamlessly work together. Element offers the richest +network of communication bridges.

+ +

Own Your Own Data - No one should control your communication and data but you. Element +lets you run your own server, and provides users and teams with the most advanced +crypto ratchet technology available today for a decentralized secure Internet.

+ +

Open Source - Element is entirely open source: all the code is published on GitHub +(Apache License) for anyone to see and extend. This means teams can customize or +contribute to the code and everyone can benefit from the speed of community innovation.

+ +

Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, +decentralized communication delivering a community of users, bridged networks, +integrated bots and applications plus full end-to-end encryption. To learn more about +Matrix visit https://matrix.org.

+ +
+ + + +--{{ multipart_boundary|safe }}-- diff --git a/res/vector-im/verification_template.eml.j2 b/res/vector-im/verification_template.eml.j2 new file mode 100644 index 00000000..66f15396 --- /dev/null +++ b/res/vector-im/verification_template.eml.j2 @@ -0,0 +1,171 @@ +Date: {{ date|safe }} +From: {{ from|safe }} +To: {{ to|safe }} +Message-ID: {{ messageid|safe }} +Subject: Confirm your email address for Element +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="{{ multipart_boundary|safe }}" + +--{{ multipart_boundary|safe }} +Content-Type: text/plain; charset=UTF-8 +Content-Disposition: inline + +Hello there! + +You have asked us to register this email address with element.io - the open source, +distributed and secure shared workspace for the web that's built on Matrix. + +If it was really you who made this request, you can click on the following link to +complete the verification of your email address: + +{{ link|safe }} + +Please note that you will need to use Chrome, Firefox or Safari on the web, or +iOS or Android on mobile. + +If you didn't make this request, you can safely disregard this email. + +Thanks! + +Element + + +About Element: + +Break through - Element allows teams to communicate across a wide range of collaboration +apps. If some team members use Element while others use IRC, Slack or Gitter, Element will +allow these team members to seamlessly work together. Element offers the richest +network of communication bridges. + +Own Your Own Data - No one should control your communication and data but you. Element +lets you run your own server, and provides users and teams with the most advanced +crypto ratchet technology available today for a decentralized secure Internet. + +Open Source - Element is entirely open source: all the code is published on GitHub +(Apache License) for anyone to see and extend. This means teams can customize or +contribute to the code and everyone can benefit from the speed of community innovation. + +Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, +decentralized communication delivering a community of users, bridged networks, +integrated bots and applications plus full end-to-end encryption. To learn more about +Matrix visit https://matrix.org. + +--{{ multipart_boundary|safe }} +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + + + + + +
+ + + + + +
+
+ +

Hello there!

+ +

You have asked us to register this email address with element.io - the open source, + distributed and secure shared workspace for the web that's built on Matrix.

+ +

If it was really you who made this request, you can click on the following link to + complete the verification of your email address:

+ +

Complete email verification

+ + +

Please note that Element requires + Chrome, + Firefox or + Safari on the web, + or iOS or Android on mobile.

+ +

If you didn't make this request, you can safely disregard this email.

+ +

Thanks!

+ +

Element

+ +
+

About Element:

+ +

Break through - Element allows teams to communicate across a wide range of collaboration + apps. If some team members use Element while others use IRC, Slack or Gitter, Element will + allow these team members to seamlessly work together. Element offers the richest + network of communication bridges.

+ +

Own Your Own Data - No one should control your communication and data but you. Element + lets you run your own server, and provides users and teams with the most advanced + crypto ratchet technology available today for a decentralized secure Internet.

+ +

Open Source - Element is entirely open source: all the code is published on GitHub + (Apache License) for anyone to see and extend. This means teams can customize or + contribute to the code and everyone can benefit from the speed of community innovation.

+ +

Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, + decentralized communication delivering a community of users, bridged networks, + integrated bots and applications plus full end-to-end encryption. To learn more about + Matrix visit https://matrix.org.

+ +
+ + + +--{{ multipart_boundary|safe }}-- diff --git a/res/vector_verification_sample.txt b/res/vector_verification_sample.txt new file mode 100644 index 00000000..e48dce85 --- /dev/null +++ b/res/vector_verification_sample.txt @@ -0,0 +1,158 @@ +Hello there! + +You have asked us to register this email address with element.io - the open source, +distributed and secure shared workspace for the web that's built on Matrix. + +If it was really you who made this request, you can click on the following link to +complete the verification of your email address: + +https://link_test.com + +Please note that you will need to use Chrome, Firefox or Safari on the web, or +iOS or Android on mobile. + +If you didn't make this request, you can safely disregard this email. + +Thanks! + +Element + + +About Element: + +Break through - Element allows teams to communicate across a wide range of collaboration +apps. If some team members use Element while others use IRC, Slack or Gitter, Element will +allow these team members to seamlessly work together. Element offers the richest +network of communication bridges. + +Own Your Own Data - No one should control your communication and data but you. Element +lets you run your own server, and provides users and teams with the most advanced +crypto ratchet technology available today for a decentralized secure Internet. + +Open Source - Element is entirely open source: all the code is published on GitHub +(Apache License) for anyone to see and extend. This means teams can customize or +contribute to the code and everyone can benefit from the speed of community innovation. + +Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, +decentralized communication delivering a community of users, bridged networks, +integrated bots and applications plus full end-to-end encryption. To learn more about +Matrix visit https://matrix.org. + +--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + + + + + +
+ + + + + +
+
+ +

Hello there!

+ +

You have asked us to register this email address with element.io - the open source, + distributed and secure shared workspace for the web that's built on Matrix.

+ +

If it was really you who made this request, you can click on the following link to + complete the verification of your email address:

+ +

Complete email verification

+ + +

Please note that Element requires + Chrome, + Firefox or + Safari on the web, + or iOS or Android on mobile.

+ +

If you didn't make this request, you can safely disregard this email.

+ +

Thanks!

+ +

Element

+ +
+

About Element:

+ +

Break through - Element allows teams to communicate across a wide range of collaboration + apps. If some team members use Element while others use IRC, Slack or Gitter, Element will + allow these team members to seamlessly work together. Element offers the richest + network of communication bridges.

+ +

Own Your Own Data - No one should control your communication and data but you. Element + lets you run your own server, and provides users and teams with the most advanced + crypto ratchet technology available today for a decentralized secure Internet.

+ +

Open Source - Element is entirely open source: all the code is published on GitHub + (Apache License) for anyone to see and extend. This means teams can customize or + contribute to the code and everyone can benefit from the speed of community innovation.

+ +

Made on Matrix - Element is built on top of Matrix. Matrix is an open network for secure, + decentralized communication delivering a community of users, bridged networks, + integrated bots and applications plus full end-to-end encryption. To learn more about + Matrix visit https://matrix.org.

+ +
+ + + +--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-- \ No newline at end of file diff --git a/setup.py b/setup.py index 034a4704..92a2c70f 100644 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ def read(fname): description="Reference Matrix Identity Verification and Lookup Server", python_requires=">=3.6", install_requires=[ + "jinja2>=3.0.0", "signedjson==1.1.1", "unpaddedbase64==1.1.0", "Twisted>=18.4.0", diff --git a/sydent/sydent.py b/sydent/sydent.py index e7579ca2..0f27657a 100644 --- a/sydent/sydent.py +++ b/sydent/sydent.py @@ -23,6 +23,7 @@ from typing import Set import twisted.internet.reactor +from jinja2 import Environment, FileSystemLoader from twisted.internet import address, task from twisted.python import log @@ -294,6 +295,10 @@ def __init__( "email", "email.third_party_invite_domain_obfuscate_characters" ) ) + self.template_environment = Environment( + loader=FileSystemLoader(self.cfg.get("general", "templates.path")), + autoescape=True, + ) # See if a pepper already exists in the database # Note: This MUST be run before we start serving requests, otherwise lookups for @@ -472,7 +477,14 @@ def get_branded_template(self, brand, template_name, deprecated_template_name): brand = self.cfg.get("general", "brand.default") root_template_path = self.cfg.get("general", "templates.path") - return os.path.join(root_template_path, brand, template_name) + + # Grab jinja template if it exists + if os.path.exists( + os.path.join(root_template_path, brand, template_name + ".j2") + ): + return os.path.join(brand, template_name + ".j2") + else: + return os.path.join(root_template_path, brand, template_name) class Validators: diff --git a/sydent/util/emailutils.py b/sydent/util/emailutils.py index e9de0ac6..6e532dc3 100644 --- a/sydent/util/emailutils.py +++ b/sydent/util/emailutils.py @@ -63,17 +63,23 @@ def sendEmail( } ) - allSubstitutions = {} - for k, v in substitutions.items(): - allSubstitutions[k] = v - allSubstitutions[k + "_forhtml"] = escape(v) - allSubstitutions[k + "_forurl"] = urllib.parse.quote(v) + # use jinja for rendering if jinja templates are present + if templateFile.endswith(".j2"): + # We add randomize the multipart boundary to stop user input from + # conflicting with it. + substitutions["multipart_boundary"] = generateAlphanumericTokenOfLength(32) + template = sydent.template_environment.get_template(templateFile) + mailString = template.render(substitutions) + else: + allSubstitutions = {} + for k, v in substitutions.items(): + allSubstitutions[k] = v + allSubstitutions[k + "_forhtml"] = escape(v) + allSubstitutions[k + "_forurl"] = urllib.parse.quote(v) + allSubstitutions["multipart_boundary"] = generateAlphanumericTokenOfLength(32) + with open(templateFile) as template_file: + mailString = template_file.read() % allSubstitutions - # We add randomize the multipart boundary to stop user input from - # conflicting with it. - allSubstitutions["multipart_boundary"] = generateAlphanumericTokenOfLength(32) - - mailString = open(templateFile).read() % allSubstitutions parsedFrom = email.utils.parseaddr(mailFrom)[1] parsedTo = email.utils.parseaddr(mailTo)[1] if parsedFrom == "" or parsedTo == "": diff --git a/tests/test_jinja_templates.py b/tests/test_jinja_templates.py new file mode 100644 index 00000000..06ef612b --- /dev/null +++ b/tests/test_jinja_templates.py @@ -0,0 +1,224 @@ +# Copyright 2021 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os.path +import urllib +from unittest.mock import Mock, patch + +from twisted.trial import unittest + +from sydent.util.emailutils import sendEmail +from tests.utils import make_sydent + + +class TestTemplate(unittest.TestCase): + def setUp(self): + # Create a new sydent + config = { + "general": { + "templates.path": os.path.join( + os.path.dirname(os.path.dirname(__file__)), "res" + ), + }, + } + self.sydent = make_sydent(test_config=config) + + def test_jinja_vector_invite(self): + substitutions = { + "address": "foo@example.com", + "medium": "email", + "room_alias": "#somewhere:exmaple.org", + "room_avatar_url": "mxc://example.org/s0meM3dia", + "room_id": "!something:example.org", + "room_name": "Bob's Emporium of Messages", + "sender": "@bob:example.com", + "sender_avatar_url": "mxc://example.org/an0th3rM3dia", + "sender_display_name": "", + "bracketed_verified_sender": "Bob Smith", + "bracketed_room_name": "Bob's Emporium of Messages", + "to": "person@test.test", + "token": "a_token", + "ephemeral_private_key": "mystery_key", + "web_client_location": "https://app.element.io", + } + + templateFile = self.sydent.get_branded_template( + "vector-im", + "invite_template.eml", + ("email", "email.invite_template"), + ) + + with patch("sydent.util.emailutils.smtplib") as smtplib: + sendEmail(self.sydent, templateFile, "test@test.com", substitutions) + + smtp = smtplib.SMTP.return_value + email_contents = smtp.sendmail.call_args[0][2].decode("utf-8") + + # test url input is encoded + self.assertIn(urllib.parse.quote("mxc://example.org/s0meM3dia"), email_contents) + + # test html input is escaped + self.assertIn("Bob's Emporium of Messages", email_contents) + + # test safe values are not escaped + self.assertIn("", email_contents) + + # test our link is as expected + expected_url = ( + "https://app.element.io/#/room/" + + urllib.parse.quote("!something:example.org") + + "?email=" + + urllib.parse.quote("test@test.com") + + "&signurl=https%3A%2F%2Fvector.im%2F_matrix%2Fidentity%2Fapi%2Fv1%2Fsign-ed25519%3Ftoken%3D" + + urllib.parse.quote("a_token") + + "%26private_key%3D" + + urllib.parse.quote("mystery_key") + + "&room_name=" + + urllib.parse.quote("Bob's Emporium of Messages") + + "&room_avatar_url=" + + urllib.parse.quote("mxc://example.org/s0meM3dia") + + "&inviter_name=" + + urllib.parse.quote("") + + "&guest_access_token=&guest_user_id=" + ) + text = email_contents.splitlines() + link = text[19] + self.assertEqual(link, expected_url) + + def test_jinja_matrix_invite(self): + substitutions = { + "address": "foo@example.com", + "medium": "email", + "room_alias": "#somewhere:exmaple.org", + "room_avatar_url": "mxc://example.org/s0meM3dia", + "room_id": "!something:example.org", + "room_name": "Bob's Emporium of Messages", + "sender": "@bob:example.com", + "sender_avatar_url": "mxc://example.org/an0th3rM3dia", + "sender_display_name": "", + "bracketed_verified_sender": "Bob Smith", + "bracketed_room_name": "Bob's Emporium of Messages", + "to": "person@test.test", + "token": "a_token", + "ephemeral_private_key": "mystery_key", + "web_client_location": "https://matrix.org", + } + + templateFile = self.sydent.get_branded_template( + "matrix-org", + "invite_template.eml", + ("email", "email.invite_template"), + ) + + with patch("sydent.util.emailutils.smtplib") as smtplib: + sendEmail(self.sydent, templateFile, "test@test.com", substitutions) + + smtp = smtplib.SMTP.return_value + email_contents = smtp.sendmail.call_args[0][2].decode("utf-8") + + # test url input is encoded + self.assertIn(urllib.parse.quote("mxc://example.org/s0meM3dia"), email_contents) + + # test html input is escaped + self.assertIn("Bob's Emporium of Messages", email_contents) + + # test safe values are not escaped + self.assertIn("", email_contents) + + # test our link is as expected + expected_url = ( + "https://matrix.org/#/room/" + + urllib.parse.quote("!something:example.org") + + "?email=" + + urllib.parse.quote("test@test.com") + + "&signurl=https%3A%2F%2Fmatrix.org%2F_matrix%2Fidentity%2Fapi%2Fv1%2Fsign-ed25519%3Ftoken%3D" + + urllib.parse.quote("a_token") + + "%26private_key%3D" + + urllib.parse.quote("mystery_key") + + "&room_name=" + + urllib.parse.quote("Bob's Emporium of Messages") + + "&room_avatar_url=" + + urllib.parse.quote("mxc://example.org/s0meM3dia") + + "&inviter_name=" + + urllib.parse.quote("") + + "&guest_access_token=&guest_user_id=" + ) + text = email_contents.splitlines() + link = text[22] + self.assertEqual(link, expected_url) + + def test_jinja_matrix_verification(self): + substitutions = { + "address": "foo@example.com", + "medium": "email", + "to": "person@test.test", + "token": "<>", + "link": "https://link_test.com", + } + + templateFile = self.sydent.get_branded_template( + "matrix-org", + "verification_template.eml", + ("email", "email.verification_template"), + ) + + with patch("sydent.util.emailutils.smtplib") as smtplib: + sendEmail(self.sydent, templateFile, "test@test.com", substitutions) + + smtp = smtplib.SMTP.return_value + email_contents = smtp.sendmail.call_args[0][2].decode("utf-8") + + # test html input is escaped + self.assertIn("<<token>>", email_contents) + + # test safe values are not escaped + self.assertIn("<>", email_contents) + + @patch( + "sydent.util.emailutils.generateAlphanumericTokenOfLength", + Mock(return_value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + ) + def test_jinja_vector_verification(self): + substitutions = { + "address": "foo@example.com", + "medium": "email", + "to": "person@test.test", + "link": "https://link_test.com", + } + + templateFile = self.sydent.get_branded_template( + "vector-im", + "verification_template.eml", + ("email", "email.verification_template"), + ) + + with patch("sydent.util.emailutils.smtplib") as smtplib: + sendEmail(self.sydent, templateFile, "test@test.com", substitutions) + + smtp = smtplib.SMTP.return_value + email_contents = smtp.sendmail.call_args[0][2].decode("utf-8") + + path = os.path.join( + self.sydent.cfg.get("general", "templates.path"), + "vector_verification_sample.txt", + ) + + with open(path, "r") as file: + expected_text = file.read() + + # remove the email headers as they are variable + email_contents = email_contents[email_contents.index("Hello") :] + + # test all ouput is as expected + self.assertEqual(email_contents, expected_text)