-
Notifications
You must be signed in to change notification settings - Fork 16
Adds configurable mathjax cdn #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e2195d1
eb11077
c0374d9
694751f
7e8bb9a
0f1b5da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,6 +81,64 @@ MathJax library: | |
| {% mathjax_script %} | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| All `wagtail-polymath` settings are defined in a single `WAGTAIL_POLYMATH` | ||
| dictionary in your settings file. | ||
|
|
||
| By default, wagtail-polymath loads MathJax from jsdelivr, pinned to a specific | ||
| version with a matching [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity) | ||
| (SRI) hash, so the browser can verify the script hasn't been tampered with. | ||
|
|
||
| If you'd rather load MathJax from a different CDN, your own static files, or | ||
| a different version, set `mathjax_url` to the full script URL: | ||
|
|
||
| ```python | ||
| # settings.py | ||
| WAGTAIL_POLYMATH = { | ||
| "mathjax_url": "https://example.com/path/to/tex-mml-chtml.js", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my last item for pause is whether we use the full URL to the library, or the URL base (i.e. On one hand the full library URL gives extra flexibility, on the other we don't have much control. I say let's go with the full URL for now, but leave the option open to change things if we want to |
||
| } | ||
| ``` | ||
|
|
||
| Since we can't know the SRI hash for a script we don't control, setting a | ||
|
zerolab marked this conversation as resolved.
|
||
| custom URL on its own disables integrity checking for that script (no | ||
| `integrity`/`crossorigin` attributes are rendered). If you want that | ||
| protection back, also set `mathjax_sri` to the hash for your chosen file: | ||
|
|
||
| ```python | ||
| # settings.py | ||
| WAGTAIL_POLYMATH = { | ||
| "mathjax_url": "https://example.com/path/to/tex-mml-chtml.js", | ||
| "mathjax_sri": "sha256-...", | ||
| } | ||
| ``` | ||
|
|
||
| `mathjax_sri` has no effect unless `mathjax_url` is also set — the built-in | ||
| default URL always uses its own pinned hash. | ||
|
|
||
| To generate the hash for your chosen file, download it and use `openssl`. | ||
| Note that the `integrity` attribute requires a **base64**-encoded digest — | ||
| `sha256sum`/`shasum` produce a hex digest instead, which will not work: | ||
|
|
||
| ```sh | ||
| openssl dgst -sha256 -binary tex-mml-chtml.js | openssl base64 -A | ||
| ``` | ||
|
|
||
| Prefix the output with `sha256-` to get the full `mathjax_sri` value: | ||
|
|
||
| ```python | ||
| WAGTAIL_POLYMATH = { | ||
| "mathjax_url": "https://example.com/path/to/tex-mml-chtml.js", | ||
| "mathjax_sri": "sha256-dPV35kaoLq1rg+JbYf8p1kTrZamwMY+XIwaWUPwqtpU=", | ||
| } | ||
| ``` | ||
|
|
||
| Both settings apply to the MathJax script loaded in the Wagtail admin (for | ||
| the `MathBlock` live preview) and the one loaded by the `mathjax_script` | ||
| template tag. Note that the bundled preview JS assumes MathJax's combined | ||
| `tex-mml-chtml` component and its `input/asciimath` loader — if you switch to | ||
| a different version or build of MathJax, you're responsible for keeping it | ||
| compatible with that configuration. | ||
|
|
||
| ## Contributing | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| from django.conf import settings | ||
|
|
||
|
|
||
| MATHJAX_VERSION = "4.1.2" | ||
| MATHJAX_DEFAULT_URL = ( | ||
| f"https://cdn.jsdelivr.net/npm/mathjax@{MATHJAX_VERSION}/tex-mml-chtml.js" | ||
| ) | ||
| MATHJAX_DEFAULT_SRI = "sha256-dPV35kaoLq1rg+JbYf8p1kTrZamwMY+XIwaWUPwqtpU=" | ||
|
|
||
|
|
||
| class WagtailPolymathSettings: | ||
| """ | ||
| Shadows Django's settings, exposing the WAGTAIL_POLYMATH dict as attributes. | ||
| For example: | ||
| from wagtail_polymath.settings import wagtail_polymath_settings | ||
| print(wagtail_polymath_settings.mathjax_url) | ||
| """ | ||
|
|
||
| @property | ||
| def _user_settings(self): | ||
| user_settings = getattr(settings, "WAGTAIL_POLYMATH", None) | ||
| return user_settings if isinstance(user_settings, dict) else {} | ||
| @property | ||
| def mathjax_url(self): | ||
| return self._user_settings.get("mathjax_url") or MATHJAX_DEFAULT_URL | ||
|
|
||
| @property | ||
| def mathjax_sri(self): | ||
| if self._user_settings.get("mathjax_url"): | ||
| # We can't know the hash for a script we don't control, so a | ||
| # custom URL without a matching mathjax_sri setting intentionally | ||
| # omits integrity checking rather than erroring. | ||
| return self._user_settings.get("mathjax_sri") | ||
| return MATHJAX_DEFAULT_SRI | ||
|
|
||
|
|
||
| wagtail_polymath_settings = WagtailPolymathSettings() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| from wagtail_polymath.settings import ( | ||
| MATHJAX_DEFAULT_SRI, | ||
| MATHJAX_DEFAULT_URL, | ||
| wagtail_polymath_settings, | ||
| ) | ||
| from wagtail_polymath.templatetags.wagtail_polymath import mathjax_script | ||
| from wagtail_polymath.widgets import MathJaxWidget | ||
|
|
||
|
|
||
| CUSTOM_URL = "https://example.com/mathjax/tex-mml-chtml.js" | ||
| CUSTOM_SRI = "sha256-Ynv3Q3nAtRTr6UDX+X6vbn9d1t8ZO5oV2Y4gvL9y0ck=" | ||
|
|
||
|
|
||
| def widget_media_html(): | ||
| return str(MathJaxWidget().media) | ||
|
|
||
|
|
||
| class TestDefaultMathJaxSettings: | ||
| """No WAGTAIL_POLYMATH setting configured.""" | ||
|
|
||
| def test_mathjax_url_returns_default(self): | ||
| assert wagtail_polymath_settings.mathjax_url == MATHJAX_DEFAULT_URL | ||
|
|
||
| def test_mathjax_sri_returns_default(self): | ||
| assert wagtail_polymath_settings.mathjax_sri == MATHJAX_DEFAULT_SRI | ||
|
|
||
| def test_widget_media_uses_default_url_and_integrity(self): | ||
| html = widget_media_html() | ||
| assert MATHJAX_DEFAULT_URL in html | ||
| assert f'integrity="{MATHJAX_DEFAULT_SRI}"' in html | ||
| assert 'crossorigin="anonymous"' in html | ||
|
|
||
| def test_template_tag_uses_default_url_and_integrity(self): | ||
| html = mathjax_script() | ||
| assert MATHJAX_DEFAULT_URL in html | ||
| assert f'integrity="{MATHJAX_DEFAULT_SRI}"' in html | ||
| assert 'crossorigin="anonymous"' in html | ||
|
|
||
|
|
||
| class TestCustomUrlOnly: | ||
| """WAGTAIL_POLYMATH["mathjax_url"] set, no matching SRI hash supplied.""" | ||
|
|
||
| def test_mathjax_url_returns_custom_url(self, settings): | ||
| settings.WAGTAIL_POLYMATH = {"mathjax_url": CUSTOM_URL} | ||
| assert wagtail_polymath_settings.mathjax_url == CUSTOM_URL | ||
|
|
||
| def test_mathjax_sri_is_none(self, settings): | ||
| settings.WAGTAIL_POLYMATH = {"mathjax_url": CUSTOM_URL} | ||
| assert wagtail_polymath_settings.mathjax_sri is None | ||
|
|
||
| def test_widget_media_omits_integrity(self, settings): | ||
| settings.WAGTAIL_POLYMATH = {"mathjax_url": CUSTOM_URL} | ||
| html = widget_media_html() | ||
| assert CUSTOM_URL in html | ||
| assert MATHJAX_DEFAULT_URL not in html | ||
| assert "integrity" not in html | ||
| assert "crossorigin" not in html | ||
|
|
||
| def test_template_tag_omits_integrity(self, settings): | ||
| settings.WAGTAIL_POLYMATH = {"mathjax_url": CUSTOM_URL} | ||
| html = mathjax_script() | ||
| assert CUSTOM_URL in html | ||
| assert "integrity" not in html | ||
| assert "crossorigin" not in html | ||
|
|
||
|
|
||
| class TestCustomUrlAndSri: | ||
| """Both mathjax_url and mathjax_sri set in WAGTAIL_POLYMATH.""" | ||
|
|
||
| def test_mathjax_sri_returns_custom_sri(self, settings): | ||
| settings.WAGTAIL_POLYMATH = { | ||
| "mathjax_url": CUSTOM_URL, | ||
| "mathjax_sri": CUSTOM_SRI, | ||
| } | ||
| assert wagtail_polymath_settings.mathjax_sri == CUSTOM_SRI | ||
|
|
||
| def test_widget_media_uses_custom_url_and_integrity(self, settings): | ||
| settings.WAGTAIL_POLYMATH = { | ||
| "mathjax_url": CUSTOM_URL, | ||
| "mathjax_sri": CUSTOM_SRI, | ||
| } | ||
| html = widget_media_html() | ||
| assert CUSTOM_URL in html | ||
| assert f'integrity="{CUSTOM_SRI}"' in html | ||
| assert 'crossorigin="anonymous"' in html | ||
|
|
||
| def test_template_tag_uses_custom_url_and_integrity(self, settings): | ||
| settings.WAGTAIL_POLYMATH = { | ||
| "mathjax_url": CUSTOM_URL, | ||
| "mathjax_sri": CUSTOM_SRI, | ||
| } | ||
| html = mathjax_script() | ||
| assert CUSTOM_URL in html | ||
| assert f'integrity="{CUSTOM_SRI}"' in html | ||
| assert 'crossorigin="anonymous"' in html | ||
|
|
||
| def test_sri_ignored_without_matching_url(self, settings): | ||
| """The mathjax_sri key alone (no mathjax_url) must not affect the default.""" | ||
| settings.WAGTAIL_POLYMATH = {"mathjax_sri": CUSTOM_SRI} | ||
| assert wagtail_polymath_settings.mathjax_url == MATHJAX_DEFAULT_URL | ||
| assert wagtail_polymath_settings.mathjax_sri == MATHJAX_DEFAULT_SRI |
Uh oh!
There was an error while loading. Please reload this page.