diff --git a/CHANGES.rst b/CHANGES.rst index 79d6d3e..26f9179 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,14 @@ +Release 4.0.0 (24/01/2023) +========================== + +* Enforcing `subresource integrity`_ (SRI) checks breaks loading rendered + documentation from local filesystem (``file:///`` URIs). + SRI checks may now be configured by the boolean configuration option + ``jquery_use_sri``, which defaults to ``False``. + See `sphinx_rtd_theme#1420`_ for further details. + +.. _sphinx_rtd_theme#1420: https://github.com/readthedocs/sphinx_rtd_theme/issues/1420 + Release 3.0.0 (03/11/2022) ========================== diff --git a/README.rst b/README.rst index 7e955b6..50e365a 100644 --- a/README.rst +++ b/README.rst @@ -19,3 +19,27 @@ To use it, add ``sphinxcontrib.jquery`` as a Sphinx extension: "sphinxcontrib.jquery", ] ... + + +Configuration +------------- + +.. As this is a README, we restrict the directives we use to those which GitHub + renders correctly. This means that we cannot use ``versionadded``, + ``confval``, ``warning``, or other similar directives. + We use a reStructuredText definition list to emulate the ``confval`` + rendering. + We use inline **bold** syntax as a poor-man's ``.. warning::`` directive. + +``jquery_use_sri`` + A boolean value controlling whether to enable `subresource integrity`_ (SRI) + checks for JavaScript files that this extension loads. + + The default is ``False``. + + **Warning**: Enabling SRI checks may break documentation when loaded from + local filesystem (``file:///`` URIs). + + *New in version 4.0.* + + .. _subresource integrity: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity diff --git a/sphinxcontrib/jquery/__init__.py b/sphinxcontrib/jquery/__init__.py index f38224f..3ac504a 100644 --- a/sphinxcontrib/jquery/__init__.py +++ b/sphinxcontrib/jquery/__init__.py @@ -3,8 +3,8 @@ import sphinx -__version__ = "3.0.0" -version_info = (3, 0, 0) +__version__ = "4.0.0" +version_info = (4, 0, 0) _ROOT_DIR = path.abspath(path.dirname(__file__)) _FILES = ( @@ -19,18 +19,33 @@ ) -def setup(app): +def add_js_files(app, config): jquery_installed = getattr(app, "_sphinxcontrib_jquery_installed", False) + if sphinx.version_info[:2] >= (6, 0) and not jquery_installed: makedirs(path.join(app.outdir, '_static'), exist_ok=True) for (filename, integrity) in _FILES: - app.add_js_file(filename, integrity=integrity, priority=100) + # The default is not to enable subresource integrity checks, as it + # does not trigger the hash check but instead blocks the request + # when viewing documentation locally through the ``file://`` URIs. + if config.jquery_use_sri: + app.add_js_file(filename, priority=100, integrity=integrity) + else: + app.add_js_file(filename, priority=100) shutil.copyfile( path.join(_ROOT_DIR, filename), path.join(app.outdir, '_static', filename) ) app._sphinxcontrib_jquery_installed = True + +def setup(app): + # Configuration value for enabling `subresource integrity`__ (SRI) checks + # __ https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity + app.add_config_value("jquery_use_sri", default=False, rebuild="html", types=(bool,)) + + app.connect('config-inited', add_js_files) + return { "parallel_read_safe": True, "parallel_write_safe": True, diff --git a/tests/test_jquery_installed.py b/tests/test_jquery_installed.py index 92e9fdc..38e05e6 100644 --- a/tests/test_jquery_installed.py +++ b/tests/test_jquery_installed.py @@ -31,8 +31,8 @@ def inner(**kwargs): @pytest.mark.skipif(sphinx.version_info[:2] < (6, 0), reason="Requires Sphinx 6.0 or greater") -def test_jquery_installed_sphinx_ge_60(blank_app): - out_dir = blank_app(confoverrides={"extensions": ["sphinxcontrib.jquery"]}) +def test_jquery_installed_sphinx_ge_60_use_sri(blank_app): + out_dir = blank_app(confoverrides={"extensions": ["sphinxcontrib.jquery"], "jquery_use_sri": True}) text = out_dir.joinpath("index.html").read_text(encoding="utf-8") assert ('') in text + assert ('') in text + + static_dir = out_dir / '_static' + assert static_dir.joinpath('jquery.js').is_file() + assert static_dir.joinpath('_sphinx_javascript_frameworks_compat.js').is_file() + + @pytest.mark.skipif(sphinx.version_info[:2] >= (6, 0), reason="Requires Sphinx older than 6.0") def test_jquery_installed_sphinx_lt_60(blank_app):