7
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-06-08 17:02:19 +00:00

Add encrypt template filter

This is convenient for htpasswd-based authentication to nginx, for
instance.
This commit is contained in:
Régis Behmo 2020-04-04 18:22:15 +02:00
parent 04f672eed2
commit 411327662e
5 changed files with 32 additions and 1 deletions

View File

@ -4,6 +4,7 @@ Note: Breaking changes between versions are indicated by "💥".
## Unreleased
- [Feature] Add `encrypt` template filter to conveniently add htpasswd-based authentication to nginx
- [Bugfix] Fix "missing tty" during init in cron jobs
## v3.11.7 (2020-04-01)

View File

@ -147,6 +147,7 @@ With the above declaration, you can store plugin-specific templates in the ``tem
In Tutor, templates are `Jinja2 <https://jinja.palletsprojects.com/en/2.11.x/>`__-formatted files that will be rendered in the Tutor environment (the ``$(tutor config printroot)/env`` folder) when running ``tutor config save``. The environment files are overwritten every time the environment is saved. Plugin developers can create templates that make use of the built-in `Jinja2 API <https://jinja.palletsprojects.com/en/2.11.x/api/>`__. In addition, a couple additional filters are added by Tutor:
* ``common_domain``: Return the longest common name between two domain names. Example: ``{{ "studio.demo.myopenedx.com"|common_domain("lms.demo.myopenedx.com") }}`` is equal to "demo.myopenedx.com".
* ``encrypt``: Encrypt an arbitrary string. The encryption process is compatible with `htpasswd <https://httpd.apache.org/docs/2.4/programs/htpasswd.html>`__ verification.
* ``list_if``: In a list of ``(value, condition)`` tuples, return the list of ``value`` for which the ``condition`` is true.
* ``patch``: See :ref:`patches <plugin_patches>`.
* ``random_string``: Return a random string of the given length composed of ASCII letters and digits. Example: ``{{ 8|random_string }}``.

View File

@ -22,3 +22,11 @@ class UtilsTests(unittest.TestCase):
def test_list_if(self):
self.assertEqual('["cms"]', utils.list_if([("lms", False), ("cms", True)]))
def test_encrypt_decrypt(self):
password = "passw0rd"
encrypted1 = utils.encrypt(password)
encrypted2 = utils.encrypt(password)
self.assertNotEqual(encrypted1, encrypted2)
self.assertTrue(utils.verify_encrypted(encrypted1, password))
self.assertTrue(utils.verify_encrypted(encrypted2, password))

View File

@ -48,9 +48,10 @@ class Renderer:
loader=jinja2.FileSystemLoader(template_roots),
undefined=jinja2.StrictUndefined,
)
environment.filters["random_string"] = utils.random_string
environment.filters["common_domain"] = utils.common_domain
environment.filters["encrypt"] = utils.encrypt
environment.filters["list_if"] = utils.list_if
environment.filters["random_string"] = utils.random_string
environment.filters["reverse_host"] = utils.reverse_host
environment.filters["walk_templates"] = self.walk_templates
environment.globals["patch"] = self.patch

View File

@ -1,3 +1,5 @@
from crypt import crypt
from hmac import compare_digest
import json
import os
import random
@ -12,6 +14,24 @@ from . import exceptions
from . import fmt
def encrypt(text):
"""
Encrypt some textual content. The method employed is the same as suggested in the
`python docs <https://docs.python.org/3/library/crypt.html#examples>`__. The
encryption process is compatible with the password verification performed by
`htpasswd <https://httpd.apache.org/docs/2.4/programs/htpasswd.html>`__.
"""
hashed = crypt(text)
return crypt(text, hashed)
def verify_encrypted(encrypted, text):
"""
Return True/False if the encrypted content corresponds to the unencrypted text.
"""
return compare_digest(crypt(text, encrypted), encrypted)
def ensure_file_directory_exists(path):
"""
Create file's base directory if it does not exist.