Some more defensive escaping for various settings in the UI

Entering HTML fragments into the webcam stream URL could cause
issues, anything injected via Jinja should now be escaped properly.
This commit is contained in:
Gina Häußge 2015-10-06 13:41:54 +02:00
parent 45c92cb1f4
commit 548f976d35
5 changed files with 22 additions and 13 deletions

View file

@ -16,11 +16,16 @@ from octoprint.server import app, userManager, pluginManager, gettext, \
debug, LOCALES, VERSION, DISPLAY_VERSION, UI_API_KEY, BRANCH
from octoprint.settings import settings
import re
from . import util
import logging
_logger = logging.getLogger(__name__)
_valid_id_re = re.compile("[a-z_]+")
_valid_div_re = re.compile("[a-zA-Z_-]+")
@app.route("/")
@util.flask.cached(refreshif=lambda: util.flask.cache_check_headers() or "_refresh" in request.values,
key=lambda: "view/%s/%s" % (request.path, g.locale),
@ -367,6 +372,9 @@ def _process_template_config(name, implementation, rule, config=None, counter=1)
data["_div"] = rule["div"](name)
if "suffix" in data:
data["_div"] = data["_div"] + data["suffix"]
if not _valid_div_re.match(data["_div"]):
_logger.warn("Template config {} contains invalid div identifier {}, skipping it".format(name, data["_div"]))
return None
if not "template" in data:
data["template"] = rule["template"](name)
@ -378,6 +386,7 @@ def _process_template_config(name, implementation, rule, config=None, counter=1)
data_bind = "allowBindings: true"
if "data_bind" in data:
data_bind = data_bind + ", " + data["data_bind"]
data_bind = data_bind.replace("\"", "\\\"")
data["data_bind"] = data_bind
data["_key"] = "plugin_" + name

View file

@ -20,7 +20,7 @@
class="{% if mark_active %}active{% set mark_active = False %}{% endif %} {% if "classes_link" in data %}{{ data.classes_link|join(' ') }}{% elif "classes" in data %}{{ data.classes|join(' ') }}{% endif %}"
{% if "styles_link" in data %} style="{{ data.styles_link|join(', ') }}" {% elif "styles" in data %} style="{{ data.styles|join(', ') }}" {% endif %}
>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry }}</a>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry|e }}</a>
</li>
{% if "custom_bindings" not in data or data["custom_bindings"] %}<!-- /ko -->{% endif %}
{% endif %}

View file

@ -17,7 +17,7 @@
class="{% if mark_active %}active{% set mark_active = False %}{% endif %} {% if "classes_link" in data %}{{ data.classes_link|join(' ') }}{% elif "classes" in data %}{{ data.classes|join(' ') }}{% endif %}"
{% if "styles_link" in data %} style="{{ data.styles_link|join(', ') }}" {% elif "styles" in data %} style="{{ data.styles|join(', ') }}" {% endif %}
>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry }}</a>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry|e }}</a>
</li>
{% if "custom_bindings" not in data or data["custom_bindings"] %}<!-- /ko -->{% endif %}
{% endif %}

View file

@ -55,7 +55,7 @@
>
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-target="#{{ data._div }}">
{% if "icon" in data %}<i class="icon-{{ data.icon }}"></i> {% endif %}{{ entry }}
{% if "icon" in data %}<i class="icon-{{ data.icon }}"></i> {% endif %}{{ entry|e }}
</a>
{% if "template_header" in data %}
{% include data.template_header ignore missing %}
@ -87,7 +87,7 @@
{% if "data_bind" in data %}data-bind="{{ data.data_bind }}"{% endif %}
{% if "styles_link" in data %} style="{{ data.styles_link|join(', ') }}" {% elif "styles" in data %} style="{{ data.styles|join(', ') }}" {% endif %}
>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry }}</a>
<a href="#{{ data._div }}" data-toggle="tab">{{ entry|e }}</a>
</li>
{% if "custom_bindings" not in data or data["custom_bindings"] %}<!-- /ko -->{% endif %}
{% endfor %}
@ -112,7 +112,7 @@
</div>
<div class="footer">
<ul class="pull-left muted">
<li><small>{{ _('Version') }}: <span class="version">{{ display_version }}</span></small></li>
<li><small>{{ _('Version') }}: <span class="version">{{ display_version|e }}</span></small></li>
</ul>
<ul class="pull-right">
<li><a href="http://octoprint.org"><i class="icon-home"></i> {{ _('Homepage') }}</a></li>

View file

@ -10,24 +10,24 @@
var CONFIG_TIMELAPSEFILESPERPAGE = 10;
var CONFIG_LOGFILESPERPAGE = 10;
var CONFIG_USERSPERPAGE = 10;
var CONFIG_WEBCAM_STREAM = "{{ webcamStream }}";
var CONFIG_WEBCAM_STREAM = "{{ webcamStream|e }}";
var CONFIG_ACCESS_CONTROL = {% if enableAccessControl -%} true; {% else %} false; {%- endif %}
var CONFIG_SD_SUPPORT = {% if enableSdSupport -%} true; {% else %} false; {%- endif %}
var CONFIG_FIRST_RUN = {% if firstRun -%} true; {% else %} false; {%- endif %}
var CONFIG_TEMPERATURE_GRAPH = {% if enableTemperatureGraph -%} true; {% else %} false; {%- endif %}
var CONFIG_GCODE_SIZE_THRESHOLD = {{ gcodeThreshold }};
var CONFIG_GCODE_MOBILE_SIZE_THRESHOLD = {{ gcodeMobileThreshold }};
var CONFIG_GCODE_SIZE_THRESHOLD = {{ gcodeThreshold|e }};
var CONFIG_GCODE_MOBILE_SIZE_THRESHOLD = {{ gcodeMobileThreshold|e }};
var SOCKJS_URI = "{{ url_for('index') }}" + "sockjs";
var SOCKJS_DEBUG = CONFIG_DEBUG;
// sockjs should define CLOSE_NORMAL for us, but they don't (from ws spec)
var SOCKJS_CLOSE_NORMAL = 1000;
var UI_API_KEY = "{{ uiApiKey }}";
var VERSION = "{{ version }}";
var DISPLAY_VERSION = "{{ display_version }}";
var BRANCH = "{{ branch }}";
var LOCALE = "{{ g.locale }}";
var UI_API_KEY = "{{ uiApiKey|e }}";
var VERSION = "{{ version|e }}";
var DISPLAY_VERSION = "{{ display_version|e }}";
var BRANCH = "{{ branch|e }}";
var LOCALE = "{{ g.locale|e }}";
var AVAILABLE_LOCALES = {{ locales|tojson }};
var OCTOPRINT_VIEWMODELS = [];