diff options
| author | Nick Pope <nick.pope@flightdataservices.com> | 2019-04-07 21:01:47 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-02-17 09:50:50 +0100 |
| commit | 8eef22dfed2d53df0da10c0090d9cb04f66efb15 (patch) | |
| tree | b6c8154c346f456bb0b68eeb40746cc8ab2044bd /django/views | |
| parent | bae053d497ba8a8de7e4f725973924bfb1885fd2 (diff) | |
Fixed #34343 -- Moved built-in templates to filesystem.
Diffstat (limited to 'django/views')
| -rw-r--r-- | django/views/csrf.py | 99 | ||||
| -rw-r--r-- | django/views/i18n.py | 120 | ||||
| -rw-r--r-- | django/views/static.py | 41 | ||||
| -rw-r--r-- | django/views/templates/csrf_403.html | 84 | ||||
| -rw-r--r-- | django/views/templates/directory_index.html | 21 | ||||
| -rw-r--r-- | django/views/templates/i18n_catalog.js | 102 |
6 files changed, 248 insertions, 219 deletions
diff --git a/django/views/csrf.py b/django/views/csrf.py index 53ca2cb823..1b34adbe4b 100644 --- a/django/views/csrf.py +++ b/django/views/csrf.py @@ -1,3 +1,5 @@ +from pathlib import Path + from django.conf import settings from django.http import HttpResponseForbidden from django.template import Context, Engine, TemplateDoesNotExist, loader @@ -12,93 +14,17 @@ from django.utils.version import get_docs_version # tags cannot be used with this inline templates as makemessages would not be # able to discover the strings. -CSRF_FAILURE_TEMPLATE = """ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta http-equiv="content-type" content="text/html; charset=utf-8"> - <meta name="robots" content="NONE,NOARCHIVE"> - <title>403 Forbidden</title> - <style type="text/css"> - html * { padding:0; margin:0; } - body * { padding:10px 20px; } - body * * { padding:0; } - body { font:small sans-serif; background:#eee; color:#000; } - body>div { border-bottom:1px solid #ddd; } - h1 { font-weight:normal; margin-bottom:.4em; } - h1 span { font-size:60%; color:#666; font-weight:normal; } - #info { background:#f6f6f6; } - #info ul { margin: 0.5em 4em; } - #info p, #summary p { padding-top:10px; } - #summary { background: #ffc; } - #explanation { background:#eee; border-bottom: 0px none; } - </style> -</head> -<body> -<div id="summary"> - <h1>{{ title }} <span>(403)</span></h1> - <p>{{ main }}</p> -{% if no_referer %} - <p>{{ no_referer1 }}</p> - <p>{{ no_referer2 }}</p> - <p>{{ no_referer3 }}</p> -{% endif %} -{% if no_cookie %} - <p>{{ no_cookie1 }}</p> - <p>{{ no_cookie2 }}</p> -{% endif %} -</div> -{% if DEBUG %} -<div id="info"> - <h2>Help</h2> - {% if reason %} - <p>Reason given for failure:</p> - <pre> - {{ reason }} - </pre> - {% endif %} - - <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when - <a - href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django’s - CSRF mechanism</a> has not been used correctly. For POST forms, you need to - ensure:</p> - - <ul> - <li>Your browser is accepting cookies.</li> - - <li>The view function passes a <code>request</code> to the template’s <a - href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a> - method.</li> - - <li>In the template, there is a <code>{% templatetag openblock %} csrf_token - {% templatetag closeblock %}</code> template tag inside each POST form that - targets an internal URL.</li> - - <li>If you are not using <code>CsrfViewMiddleware</code>, then you must use - <code>csrf_protect</code> on any views that use the <code>csrf_token</code> - template tag, as well as those that accept the POST data.</li> +CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html" - <li>The form has a valid CSRF token. After logging in in another browser - tab or hitting the back button after a login, you may need to reload the - page with the form, because the token is rotated after a login.</li> - </ul> - <p>You’re seeing the help section of this page because you have <code>DEBUG = - True</code> in your Django settings file. Change that to <code>False</code>, - and only the initial error message will be displayed. </p> +def builtin_template_path(name): + """ + Return a path to a builtin template. - <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p> -</div> -{% else %} -<div id="explanation"> - <p><small>{{ more }}</small></p> -</div> -{% endif %} -</body> -</html> -""" # NOQA -CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html" + Avoid calling this function at the module level or in a class-definition + because __file__ may not exist, e.g. in frozen environments. + """ + return Path(__file__).parent / "templates" / name def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME): @@ -151,8 +77,9 @@ def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME): t = loader.get_template(template_name) except TemplateDoesNotExist: if template_name == CSRF_FAILURE_TEMPLATE_NAME: - # If the default template doesn't exist, use the string template. - t = Engine().from_string(CSRF_FAILURE_TEMPLATE) + # If the default template doesn't exist, use the fallback template. + with builtin_template_path("csrf_403.html").open(encoding="utf-8") as fh: + t = Engine().from_string(fh.read()) c = Context(c) else: # Raise if a developer-specified template doesn't exist. diff --git a/django/views/i18n.py b/django/views/i18n.py index 91f797dce9..771035d8ab 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -1,6 +1,7 @@ import json import os import re +from pathlib import Path from django.apps import apps from django.conf import settings @@ -16,6 +17,16 @@ from django.views.generic import View LANGUAGE_QUERY_PARAMETER = "language" +def builtin_template_path(name): + """ + Return a path to a builtin template. + + Avoid calling this function at the module level or in a class-definition + because __file__ may not exist, e.g. in frozen environments. + """ + return Path(__file__).parent / "templates" / name + + def set_language(request): """ Redirect to a given URL while setting the chosen language in the session @@ -84,112 +95,6 @@ def get_formats(): return {attr: get_format(attr) for attr in FORMAT_SETTINGS} -js_catalog_template = r""" -{% autoescape off %} -'use strict'; -{ - const globals = this; - const django = globals.django || (globals.django = {}); - - {% if plural %} - django.pluralidx = function(n) { - const v = {{ plural }}; - if (typeof v === 'boolean') { - return v ? 1 : 0; - } else { - return v; - } - }; - {% else %} - django.pluralidx = function(count) { return (count == 1) ? 0 : 1; }; - {% endif %} - - /* gettext library */ - - django.catalog = django.catalog || {}; - {% if catalog_str %} - const newcatalog = {{ catalog_str }}; - for (const key in newcatalog) { - django.catalog[key] = newcatalog[key]; - } - {% endif %} - - if (!django.jsi18n_initialized) { - django.gettext = function(msgid) { - const value = django.catalog[msgid]; - if (typeof value === 'undefined') { - return msgid; - } else { - return (typeof value === 'string') ? value : value[0]; - } - }; - - django.ngettext = function(singular, plural, count) { - const value = django.catalog[singular]; - if (typeof value === 'undefined') { - return (count == 1) ? singular : plural; - } else { - return value.constructor === Array ? value[django.pluralidx(count)] : value; - } - }; - - django.gettext_noop = function(msgid) { return msgid; }; - - django.pgettext = function(context, msgid) { - let value = django.gettext(context + '\x04' + msgid); - if (value.includes('\x04')) { - value = msgid; - } - return value; - }; - - django.npgettext = function(context, singular, plural, count) { - let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count); - if (value.includes('\x04')) { - value = django.ngettext(singular, plural, count); - } - return value; - }; - - django.interpolate = function(fmt, obj, named) { - if (named) { - return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); - } else { - return fmt.replace(/%s/g, function(match){return String(obj.shift())}); - } - }; - - - /* formatting library */ - - django.formats = {{ formats_str }}; - - django.get_format = function(format_type) { - const value = django.formats[format_type]; - if (typeof value === 'undefined') { - return format_type; - } else { - return value; - } - }; - - /* add to global namespace */ - globals.pluralidx = django.pluralidx; - globals.gettext = django.gettext; - globals.ngettext = django.ngettext; - globals.gettext_noop = django.gettext_noop; - globals.pgettext = django.pgettext; - globals.npgettext = django.npgettext; - globals.interpolate = django.interpolate; - globals.get_format = django.get_format; - - django.jsi18n_initialized = true; - } -}; -{% endautoescape %} -""" # NOQA - - class JavaScriptCatalog(View): """ Return the selected language catalog as a JavaScript library. @@ -308,7 +213,8 @@ class JavaScriptCatalog(View): def indent(s): return s.replace("\n", "\n ") - template = Engine().from_string(js_catalog_template) + with builtin_template_path("i18n_catalog.js").open(encoding="utf-8") as fh: + template = Engine().from_string(fh.read()) context["catalog_str"] = ( indent(json.dumps(context["catalog"], sort_keys=True, indent=2)) if context["catalog"] diff --git a/django/views/static.py b/django/views/static.py index f75b86f970..df46c53093 100644 --- a/django/views/static.py +++ b/django/views/static.py @@ -14,6 +14,16 @@ from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy +def builtin_template_path(name): + """ + Return a path to a builtin template. + + Avoid calling this function at the module level or in a class-definition + because __file__ may not exist, e.g. in frozen environments. + """ + return Path(__file__).parent / "templates" / name + + def serve(request, path, document_root=None, show_indexes=False): """ Serve static files below a given point in the directory structure. @@ -53,29 +63,7 @@ def serve(request, path, document_root=None, show_indexes=False): return response -DEFAULT_DIRECTORY_INDEX_TEMPLATE = """ -{% load i18n %} -<!DOCTYPE html> -<html lang="en"> - <head> - <meta http-equiv="Content-type" content="text/html; charset=utf-8"> - <meta http-equiv="Content-Language" content="en-us"> - <meta name="robots" content="NONE,NOARCHIVE"> - <title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title> - </head> - <body> - <h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1> - <ul> - {% if directory != "/" %} - <li><a href="../">../</a></li> - {% endif %} - {% for f in file_list %} - <li><a href="{{ f|urlencode }}">{{ f }}</a></li> - {% endfor %} - </ul> - </body> -</html> -""" +# Translatable string for static directory index template title. template_translatable = gettext_lazy("Index of %(directory)s") @@ -88,9 +76,10 @@ def directory_index(path, fullpath): ] ) except TemplateDoesNotExist: - t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string( - DEFAULT_DIRECTORY_INDEX_TEMPLATE - ) + with builtin_template_path("directory_index.html").open(encoding="utf-8") as fh: + t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string( + fh.read() + ) c = Context() else: c = {} diff --git a/django/views/templates/csrf_403.html b/django/views/templates/csrf_403.html new file mode 100644 index 0000000000..402a2c6cdd --- /dev/null +++ b/django/views/templates/csrf_403.html @@ -0,0 +1,84 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <meta name="robots" content="NONE,NOARCHIVE"> + <title>403 Forbidden</title> + <style type="text/css"> + html * { padding:0; margin:0; } + body * { padding:10px 20px; } + body * * { padding:0; } + body { font:small sans-serif; background:#eee; color:#000; } + body>div { border-bottom:1px solid #ddd; } + h1 { font-weight:normal; margin-bottom:.4em; } + h1 span { font-size:60%; color:#666; font-weight:normal; } + #info { background:#f6f6f6; } + #info ul { margin: 0.5em 4em; } + #info p, #summary p { padding-top:10px; } + #summary { background: #ffc; } + #explanation { background:#eee; border-bottom: 0px none; } + </style> +</head> +<body> +<div id="summary"> + <h1>{{ title }} <span>(403)</span></h1> + <p>{{ main }}</p> +{% if no_referer %} + <p>{{ no_referer1 }}</p> + <p>{{ no_referer2 }}</p> + <p>{{ no_referer3 }}</p> +{% endif %} +{% if no_cookie %} + <p>{{ no_cookie1 }}</p> + <p>{{ no_cookie2 }}</p> +{% endif %} +</div> +{% if DEBUG %} +<div id="info"> + <h2>Help</h2> + {% if reason %} + <p>Reason given for failure:</p> + <pre> + {{ reason }} + </pre> + {% endif %} + + <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when + <a + href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django’s + CSRF mechanism</a> has not been used correctly. For POST forms, you need to + ensure:</p> + + <ul> + <li>Your browser is accepting cookies.</li> + + <li>The view function passes a <code>request</code> to the template’s <a + href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a> + method.</li> + + <li>In the template, there is a <code>{% templatetag openblock %} csrf_token + {% templatetag closeblock %}</code> template tag inside each POST form that + targets an internal URL.</li> + + <li>If you are not using <code>CsrfViewMiddleware</code>, then you must use + <code>csrf_protect</code> on any views that use the <code>csrf_token</code> + template tag, as well as those that accept the POST data.</li> + + <li>The form has a valid CSRF token. After logging in in another browser + tab or hitting the back button after a login, you may need to reload the + page with the form, because the token is rotated after a login.</li> + </ul> + + <p>You’re seeing the help section of this page because you have <code>DEBUG = + True</code> in your Django settings file. Change that to <code>False</code>, + and only the initial error message will be displayed. </p> + + <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p> +</div> +{% else %} +<div id="explanation"> + <p><small>{{ more }}</small></p> +</div> +{% endif %} +</body> +</html> diff --git a/django/views/templates/directory_index.html b/django/views/templates/directory_index.html new file mode 100644 index 0000000000..d67e5e0edd --- /dev/null +++ b/django/views/templates/directory_index.html @@ -0,0 +1,21 @@ +{% load i18n %} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="en-us"> + <meta name="robots" content="NONE,NOARCHIVE"> + <title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title> + </head> + <body> + <h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1> + <ul> + {% if directory != "/" %} + <li><a href="../">../</a></li> + {% endif %} + {% for f in file_list %} + <li><a href="{{ f|urlencode }}">{{ f }}</a></li> + {% endfor %} + </ul> + </body> +</html> diff --git a/django/views/templates/i18n_catalog.js b/django/views/templates/i18n_catalog.js new file mode 100644 index 0000000000..b1fe4a9aac --- /dev/null +++ b/django/views/templates/i18n_catalog.js @@ -0,0 +1,102 @@ +{% autoescape off %} +'use strict'; +{ + const globals = this; + const django = globals.django || (globals.django = {}); + + {% if plural %} + django.pluralidx = function(n) { + const v = {{ plural }}; + if (typeof v === 'boolean') { + return v ? 1 : 0; + } else { + return v; + } + }; + {% else %} + django.pluralidx = function(count) { return (count == 1) ? 0 : 1; }; + {% endif %} + + /* gettext library */ + + django.catalog = django.catalog || {}; + {% if catalog_str %} + const newcatalog = {{ catalog_str }}; + for (const key in newcatalog) { + django.catalog[key] = newcatalog[key]; + } + {% endif %} + + if (!django.jsi18n_initialized) { + django.gettext = function(msgid) { + const value = django.catalog[msgid]; + if (typeof value === 'undefined') { + return msgid; + } else { + return (typeof value === 'string') ? value : value[0]; + } + }; + + django.ngettext = function(singular, plural, count) { + const value = django.catalog[singular]; + if (typeof value === 'undefined') { + return (count == 1) ? singular : plural; + } else { + return value.constructor === Array ? value[django.pluralidx(count)] : value; + } + }; + + django.gettext_noop = function(msgid) { return msgid; }; + + django.pgettext = function(context, msgid) { + let value = django.gettext(context + '\x04' + msgid); + if (value.includes('\x04')) { + value = msgid; + } + return value; + }; + + django.npgettext = function(context, singular, plural, count) { + let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count); + if (value.includes('\x04')) { + value = django.ngettext(singular, plural, count); + } + return value; + }; + + django.interpolate = function(fmt, obj, named) { + if (named) { + return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); + } else { + return fmt.replace(/%s/g, function(match){return String(obj.shift())}); + } + }; + + + /* formatting library */ + + django.formats = {{ formats_str }}; + + django.get_format = function(format_type) { + const value = django.formats[format_type]; + if (typeof value === 'undefined') { + return format_type; + } else { + return value; + } + }; + + /* add to global namespace */ + globals.pluralidx = django.pluralidx; + globals.gettext = django.gettext; + globals.ngettext = django.ngettext; + globals.gettext_noop = django.gettext_noop; + globals.pgettext = django.pgettext; + globals.npgettext = django.npgettext; + globals.interpolate = django.interpolate; + globals.get_format = django.get_format; + + django.jsi18n_initialized = true; + } +}; +{% endautoescape %} |
