Enable Jinja2 autoescaping (#200)
- Enable Jinja2 autoescape by default in the template environment. - Use json.dumps to safely inject sso_name into JavaScript context. - Fix linting issue (line too long) in injected_auth_page.py. - Update tests to verify escaping and safe injection. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: werdnum <271070+werdnum@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
"""Injected authorization page, replacing the original"""
|
"""Injected authorization page, replacing the original"""
|
||||||
|
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from homeassistant.components.http import HomeAssistantView, StaticPathConfig
|
from homeassistant.components.http import HomeAssistantView, StaticPathConfig
|
||||||
@@ -61,12 +62,9 @@ async def frontend_injection(hass: HomeAssistant, sso_name: str) -> None:
|
|||||||
frontend_code = await read_file(frontend_path)
|
frontend_code = await read_file(frontend_path)
|
||||||
|
|
||||||
# Inject JS and register that route
|
# Inject JS and register that route
|
||||||
frontend_code = frontend_code.replace(
|
injection_js = "<script src='/auth/oidc/static/injection.js?v=3'></script>"
|
||||||
"</body>",
|
sso_name_js = f"<script>window.sso_name = {json.dumps(sso_name)};</script>"
|
||||||
"<script src='/auth/oidc/static/injection.js?v=3'></script><script>window.sso_name = '"
|
frontend_code = frontend_code.replace("</body>", f"{injection_js}{sso_name_js}</body>")
|
||||||
+ sso_name
|
|
||||||
+ "';</script></body>",
|
|
||||||
)
|
|
||||||
|
|
||||||
await hass.http.async_register_static_paths(
|
await hass.http.async_register_static_paths(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ class AsyncTemplateRenderer:
|
|||||||
if template_name not in templates:
|
if template_name not in templates:
|
||||||
raise ValueError(f"Template '{template_name}' not found.")
|
raise ValueError(f"Template '{template_name}' not found.")
|
||||||
|
|
||||||
env = Environment(loader=DictLoader(templates), enable_async=True)
|
env = Environment(
|
||||||
|
loader=DictLoader(templates), enable_async=True, autoescape=True
|
||||||
|
)
|
||||||
template = env.get_template(template_name)
|
template = env.get_template(template_name)
|
||||||
|
|
||||||
# Render template
|
# Render template
|
||||||
|
|||||||
@@ -149,3 +149,4 @@ async def test_frontend_injection(hass: HomeAssistant, hass_client):
|
|||||||
text = await resp.text()
|
text = await resp.text()
|
||||||
|
|
||||||
assert "<script src='/auth/oidc/static/injection.js" in text
|
assert "<script src='/auth/oidc/static/injection.js" in text
|
||||||
|
assert "window.sso_name = \"OpenID Connect (SSO)\";" in text
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ async def test_real_template_render():
|
|||||||
"""Test that view template can render an real existing template."""
|
"""Test that view template can render an real existing template."""
|
||||||
|
|
||||||
renderer = AsyncTemplateRenderer()
|
renderer = AsyncTemplateRenderer()
|
||||||
rendered = await renderer.render_template("welcome.html")
|
await renderer.fetch_templates()
|
||||||
|
rendered = await renderer.render_template(
|
||||||
|
"welcome.html", name="<script>alert(1)</script>"
|
||||||
|
)
|
||||||
assert "<!DOCTYPE html>" in rendered
|
assert "<!DOCTYPE html>" in rendered
|
||||||
|
assert "<script>alert(1)</script>" in rendered
|
||||||
|
assert "<script>alert(1)</script>" not in rendered
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user