mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
templates: Fix missing quoting of attributes in HTML templates.
This fixes a bundle of issues where we were missing "" around attributes coming from variables. In most cases, the variables were integers or fixed constants from the Zulip codebase (E.g. the name of an installed integration), but in at least one case it was user-provided data that could potentially have security impact.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<div class="emoji-popover">
|
||||
<div class="emoji-popover-top input-append">
|
||||
<input class="emoji-popover-filter" type="text" autofocus placeholder={{t 'Search' }} />
|
||||
<input class="emoji-popover-filter" type="text" autofocus placeholder="{{t 'Search' }}" />
|
||||
<i class="fa fa-search" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="emoji-popover-category-tabs">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#with emoji_dict}}
|
||||
<div class="emoji-popover-emoji {{#if ../message_id }}{{#if has_reacted}} reacted {{/if}} reaction {{else}} composition {{/if}}" data-emoji-name={{name}} tabindex="0" data-emoji-id="{{../type}},{{../section}},{{../index}}">
|
||||
<div class="emoji-popover-emoji {{#if ../message_id }}{{#if has_reacted}} reacted {{/if}} reaction {{else}} composition {{/if}}" data-emoji-name="{{name}}" tabindex="0" data-emoji-id="{{../type}},{{../section}},{{../index}}">
|
||||
{{#if is_realm_emoji}}
|
||||
<img src="{{url}}" class="emoji"/>
|
||||
{{else}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class='pill' data-id='{{ id }}' tabindex=0>
|
||||
{{#if has_image}}
|
||||
<img class="pill-image" src={{img_src}} />
|
||||
<img class="pill-image" src="{{img_src}}" />
|
||||
{{/if}}
|
||||
<span class="pill-value">{{ display_value }}</span>
|
||||
<div class="exit">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="{{this.class}}" aria-label="{{this.label}}" data-reaction-id={{this.local_id}}>
|
||||
<div class="{{this.class}}" aria-label="{{this.label}}" data-reaction-id="{{this.local_id}}">
|
||||
{{#if this.emoji_alt_code}}
|
||||
<div class="emoji_alt_code"> :{{this.emoji_name}}:</div>
|
||||
{{else}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#with muted_topics}}
|
||||
<tr data-stream-id={{stream_id}} data-stream="{{stream}}" data-topic="{{topic}}" data-date-muted="{{date_muted_str}}">
|
||||
<tr data-stream-id="{{stream_id}}" data-stream="{{stream}}" data-topic="{{topic}}" data-date-muted="{{date_muted_str}}">
|
||||
<td>{{stream}}</td>
|
||||
<td>{{topic}}</td>
|
||||
<td>{{date_muted_str}}</td>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
{{/each}}
|
||||
</select>
|
||||
<span id="play_notification_sound">
|
||||
<i class="fa fa-play-circle" aria-label={{t "Play sound" }}></i>
|
||||
<i class="fa fa-play-circle" aria-label="{{t 'Play sound' }}"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
<div class="input" contenteditable="false" style="display: none;"></div>
|
||||
</div>
|
||||
{{else if this.is_link}}
|
||||
<a href={{this.value}} target="_blank" class="value">{{this.value}}</a>
|
||||
<a href="{{this.value}}" target="_blank" class="value">{{this.value}}</a>
|
||||
{{else if this.is_external_account}}
|
||||
<a href={{this.link}} target="_blank" class="value">{{this.value}}</a>
|
||||
<a href="{{this.link}}" target="_blank" class="value">{{this.value}}</a>
|
||||
{{else}}
|
||||
{{#if this.rendered_value}}
|
||||
<div class="value rendered_markdown">{{rendered_markdown this.rendered_value}}</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span class="message_sender{% if status_message %} sender_info_hover{% endif %} no-select">
|
||||
{% if include_sender %}
|
||||
<div class="inline_profile_picture">
|
||||
<img src={{ avatar_url }} alt="" class="no-drag"/>
|
||||
<img src="{{ avatar_url }}" alt="" class="no-drag"/>
|
||||
</div>
|
||||
{% if status_message %}
|
||||
<span class="sender-status">
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
|
||||
{% for integration in integrations_dict.values() %}
|
||||
{% if integration.is_enabled() %}
|
||||
<div id={{ integration.name }} class="integration-instructions">
|
||||
<div id="{{ integration.name }}" class="integration-instructions">
|
||||
<div class="help-content"></div>
|
||||
<p style="font-size:11px; font-style:italic;">
|
||||
Logos are trademarks of their respective owners.
|
||||
|
||||
@@ -28,7 +28,7 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
||||
<input id="id_team_name" class="required" type="text"
|
||||
placeholder="Acme or Ακμή"
|
||||
value="{% if form.realm_name.value() %}{{ form.realm_name.value() }}{% endif %}"
|
||||
name="realm_name" maxlength={{ MAX_REALM_NAME_LENGTH }} required />
|
||||
name="realm_name" maxlength="{{ MAX_REALM_NAME_LENGTH }}" required />
|
||||
</div>
|
||||
<label for="id_team_name" class="inline-block label-title">{{ _('Organization name') }}</label>
|
||||
{% if form.realm_name.errors %}
|
||||
@@ -63,7 +63,7 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
||||
class="{% if root_domain_landing_page %}required{% endif %} subdomain" type="text"
|
||||
placeholder="acme"
|
||||
value="{% if form.realm_subdomain.value() %}{{ form.realm_subdomain.value() }}{% endif %}"
|
||||
name="realm_subdomain" maxlength={{ MAX_REALM_SUBDOMAIN_LENGTH }}
|
||||
name="realm_subdomain" maxlength="{{ MAX_REALM_SUBDOMAIN_LENGTH }}"
|
||||
{% if root_domain_landing_page %}required{% endif %} />
|
||||
<label for="id_team_subdomain" class="realm_subdomain_label">.{{ external_host }}</label>
|
||||
<p id="id_team_subdomain_error_client" class="error help-inline text-error"></p>
|
||||
@@ -124,7 +124,7 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
||||
{% else %}
|
||||
<input id="id_full_name" class="required" type="text" name="full_name"
|
||||
value="{% if full_name %}{{ full_name }}{% elif form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
|
||||
maxlength={{ MAX_NAME_LENGTH }} placeholder="{% trans %}Full name or 名前{% endtrans %}" required />
|
||||
maxlength="{{ MAX_NAME_LENGTH }}" placeholder="{% trans %}Full name or 名前{% endtrans %}" required />
|
||||
<label for="id_full_name" class="inline-block label-title">{{ _('Full name') }}</label>
|
||||
{% if form.full_name.errors %}
|
||||
{% for error in form.full_name.errors %}
|
||||
@@ -151,7 +151,7 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
|
||||
<div class="input-box">
|
||||
<input id="id_password" class="required" type="password" name="password"
|
||||
value="{% if form.password.value() %}{{ form.password.value() }}{% endif %}"
|
||||
maxlength={{ MAX_PASSWORD_LENGTH }}
|
||||
maxlength="{{ MAX_PASSWORD_LENGTH }}"
|
||||
data-min-length="{{password_min_length}}"
|
||||
data-min-guesses="{{password_min_guesses}}" required />
|
||||
<label for="id_password" class="inline-block">{{ _('Password') }}</label>
|
||||
|
||||
@@ -498,6 +498,12 @@ html_rules: List["Rule"] = whitespace_rules + prose_style_rules + [
|
||||
'exclude': {"templates/analytics/support.html"},
|
||||
'good_lines': ['<input class="stream-list-filter" type="text" placeholder="{{ _(\'Search streams\') }}" />'],
|
||||
'bad_lines': ['<input placeholder="foo">']},
|
||||
{'pattern': '={',
|
||||
# TODO: Improve the Apple auth patterns so we can remove this.
|
||||
'exclude_pattern': 'appleid.cdn-apple.com/appleid/button',
|
||||
'description': "Likely missing quoting in HTML attribute",
|
||||
'good_lines': ['<a href="{{variable}}">'],
|
||||
'bad_lines': ['<a href={{variable}}>']},
|
||||
{'pattern': "placeholder='[^{]",
|
||||
'description': "`placeholder` value should be translatable.",
|
||||
'good_lines': ['<input class="stream-list-filter" type="text" placeholder="{{ _(\'Search streams\') }}" />'],
|
||||
|
||||
Reference in New Issue
Block a user