mirror of https://github.com/zulip/zulip.git
CVE-2022-23656: Fix cross-site scripting vulnerability in tooltips.
An attacker could maliciously craft a full name for their account and send messages to a topic with several participants; a victim who then opens an overflow tooltip including this full name on the recent topics page could trigger execution of JavaScript code controlled by the attacker. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
05a17e5854
commit
e090027adc
|
@ -32,7 +32,6 @@ const default_popover_props = {
|
|||
delay: 0,
|
||||
appendTo: () => document.body,
|
||||
trigger: "click",
|
||||
allowHTML: true,
|
||||
interactive: true,
|
||||
hideOnClick: true,
|
||||
/* The light-border TippyJS theme is a bit of a misnomer; it
|
||||
|
@ -60,6 +59,7 @@ export function initialize() {
|
|||
delegate("body", {
|
||||
...default_popover_props,
|
||||
target: "#streams_inline_icon",
|
||||
allowHTML: true,
|
||||
onShow(instance) {
|
||||
const can_create_streams =
|
||||
settings_data.user_can_create_private_streams() ||
|
||||
|
@ -89,6 +89,7 @@ export function initialize() {
|
|||
...default_popover_props,
|
||||
target: ".compose_mobile_button",
|
||||
placement: "top",
|
||||
allowHTML: true,
|
||||
onShow(instance) {
|
||||
on_show_prep(instance);
|
||||
instance.setContent(
|
||||
|
@ -125,6 +126,7 @@ export function initialize() {
|
|||
...default_popover_props,
|
||||
target: ".compose_control_menu_wrapper",
|
||||
placement: "top",
|
||||
allowHTML: true,
|
||||
onShow(instance) {
|
||||
instance.setContent(
|
||||
render_compose_control_buttons_popover({
|
||||
|
@ -143,6 +145,7 @@ export function initialize() {
|
|||
...default_popover_props,
|
||||
target: ".enter_sends",
|
||||
placement: "top",
|
||||
allowHTML: true,
|
||||
onShow(instance) {
|
||||
on_show_prep(instance);
|
||||
instance.setContent(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import $ from "jquery";
|
||||
import _ from "lodash";
|
||||
|
||||
import render_recent_topic_row from "../templates/recent_topic_row.hbs";
|
||||
import render_recent_topics_filters from "../templates/recent_topics_filters.hbs";
|
||||
|
@ -291,7 +292,9 @@ function format_topic(topic_data) {
|
|||
),
|
||||
);
|
||||
}
|
||||
const other_sender_names = displayed_other_names.join("<br/>");
|
||||
const other_sender_names_html = displayed_other_names
|
||||
.map((name) => _.escape(name))
|
||||
.join("<br />");
|
||||
|
||||
return {
|
||||
// stream info
|
||||
|
@ -309,7 +312,7 @@ function format_topic(topic_data) {
|
|||
topic_url: hash_util.by_stream_topic_uri(stream_id, topic),
|
||||
senders: senders_info,
|
||||
other_senders_count: Math.max(0, all_senders.length - MAX_AVATAR),
|
||||
other_sender_names,
|
||||
other_sender_names_html,
|
||||
muted,
|
||||
topic_muted,
|
||||
participated: topic_data.participated,
|
||||
|
|
|
@ -171,7 +171,9 @@ export const update_elements = (content) => {
|
|||
text: rendered_time.text,
|
||||
});
|
||||
$(this).html(rendered_timestamp);
|
||||
$(this).attr("data-tippy-content", rendered_time.tooltip_content);
|
||||
$(this)
|
||||
.attr("data-tippy-content", rendered_time.tooltip_content_html)
|
||||
.attr("data-tippy-allowHTML", "true");
|
||||
} else {
|
||||
// This shouldn't happen. If it does, we're very interested in debugging it.
|
||||
blueslip.error(`Could not parse datetime supplied by backend: ${time_str}`);
|
||||
|
|
|
@ -226,17 +226,17 @@ export function render_date(time: Date, time_above: Date | undefined, today: Dat
|
|||
// Renders the timestamp returned by the <time:> Markdown syntax.
|
||||
export function render_markdown_timestamp(time: number | Date): {
|
||||
text: string;
|
||||
tooltip_content: string;
|
||||
tooltip_content_html: string;
|
||||
} {
|
||||
const hourformat = user_settings.twenty_four_hour_time ? "HH:mm" : "h:mm a";
|
||||
const timestring = format(time, "E, MMM d yyyy, " + hourformat);
|
||||
|
||||
const tz_offset_str = get_tz_with_UTC_offset(time);
|
||||
const tooltip_html_content = render_markdown_time_tooltip({tz_offset_str});
|
||||
const tooltip_content_html = render_markdown_time_tooltip({tz_offset_str});
|
||||
|
||||
return {
|
||||
text: timestring,
|
||||
tooltip_content: tooltip_html_content,
|
||||
tooltip_content_html: tooltip_content_html,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ tippy.setDefaultProps({
|
|||
appendTo: "parent",
|
||||
|
||||
// html content is not supported by default
|
||||
// enable it by passing data-tippy-allowHtml="true"
|
||||
// enable it by passing data-tippy-allowHTML="true"
|
||||
// in the tag or a parameter.
|
||||
});
|
||||
|
||||
|
@ -200,7 +200,6 @@ export function initialize() {
|
|||
".rendered_markdown .copy_codeblock",
|
||||
"#compose_top_right [data-tippy-content]",
|
||||
],
|
||||
allowHTML: true,
|
||||
appendTo: () => document.body,
|
||||
onHidden(instance) {
|
||||
instance.destroy();
|
||||
|
|
|
@ -203,7 +203,7 @@ function initialize_compose_box() {
|
|||
embedded: $("#compose").attr("data-embedded") === "",
|
||||
file_upload_enabled: page_params.max_file_upload_size_mib > 0,
|
||||
giphy_enabled: giphy.is_giphy_enabled(),
|
||||
scroll_to_bottom_key: common.has_mac_keyboard()
|
||||
scroll_to_bottom_key_html: common.has_mac_keyboard()
|
||||
? "Fn + <span class='tooltip_right_arrow'>→</span>"
|
||||
: "End",
|
||||
}),
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
minimal css and no JS. We keep it `position: absolute` to prevent
|
||||
it changing compose box layout in any way. --}}
|
||||
<div id="scroll-to-bottom-button-container">
|
||||
<div id="scroll-to-bottom-button-clickable-area" data-tippy-content="{{t 'Scroll to bottom' }} <span class='hotkey-hint'>({{scroll_to_bottom_key}})</span>" data-tippy-allowHtml="true">
|
||||
<div id="scroll-to-bottom-button-clickable-area" data-tippy-content="{{t 'Scroll to bottom' }} <span class='hotkey-hint'>({{scroll_to_bottom_key_html}})</span>" data-tippy-allowHTML="true">
|
||||
<div id="scroll-to-bottom-button">
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<a role="button" class="undo_markdown_preview compose_control_button fa fa-edit" aria-label="{{t 'Write' }}" tabindex=0 style="display:none;" data-tippy-content="{{t 'Write' }}"></a>
|
||||
<a role="button" class="compose_control_button fa fa-video-camera video_link" aria-label="{{t 'Add video call' }}" tabindex=0 data-tippy-content="{{t 'Add video call' }}"></a>
|
||||
<a role="button" class="compose_control_button fa fa-smile-o emoji_map" aria-label="{{t 'Add emoji' }}" tabindex=0 data-tippy-content="{{t 'Add emoji' }}"></a>
|
||||
<a role="button" class="compose_control_button fa fa-clock-o time_pick" aria-label="{{t 'Add global time' }}" tabindex=0 data-tippy-content="{{t 'Add global time<br />Everyone sees global times in their own time zone.' }}" data-tippy-maxWidth="none" data-tippy-allowHtml="true"></a>
|
||||
<a role="button" class="compose_control_button fa fa-clock-o time_pick" aria-label="{{t 'Add global time' }}" tabindex=0 data-tippy-content="{{t 'Add global time<br />Everyone sees global times in their own time zone.' }}" data-tippy-allowHTML="true" data-tippy-maxWidth="none"></a>
|
||||
<a role="button" class="compose_control_button compose_gif_icon {{#unless giphy_enabled }} hide {{/unless}} zulip-icon zulip-icon-gif" aria-label="{{t 'Add GIF' }}" tabindex=0 data-tippy-content="{{t 'Add GIF' }}"></a>
|
||||
<div class="divider hide-sm">|</div>
|
||||
<div class="{{#if message_id}}hide-lg{{else}}hide-sm{{/if}}">
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<td class='recent_topic_users'>
|
||||
<ul class="recent_topics_participants">
|
||||
{{#if other_senders_count}}
|
||||
<li class="recent_topics_participant_item tippy-zulip-tooltip" data-tippy-content="{{other_sender_names}}" data-tippy-allowHtml="true">
|
||||
<li class="recent_topics_participant_item tippy-zulip-tooltip" data-tippy-content="{{other_sender_names_html}}" data-tippy-allowHTML="true">
|
||||
<span class="recent_topics_participant_overflow">+{{other_senders_count}}</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<a id="invite-user-link" href="#invite"><i class="fa fa-user-plus" aria-hidden="true"></i>{{t 'Invite more users' }}</a>
|
||||
{{/if}}
|
||||
<a id="sidebar-keyboard-shortcuts" data-overlay-trigger="keyboard-shortcuts" class="hidden-for-spectators">
|
||||
<i class="fa fa-keyboard-o fa-2x tippy-zulip-tooltip" id="keyboard-icon" data-tippy-allowHtml="true" data-tippy-content="{{t 'Keyboard shortcuts' }} <span class='hotkey-hint'>(?)</span>"></i>
|
||||
<i class="fa fa-keyboard-o fa-2x tippy-zulip-tooltip" id="keyboard-icon" data-tippy-allowHTML="true" data-tippy-content="{{t 'Keyboard shortcuts' }} <span class='hotkey-hint'>(?)</span>"></i>
|
||||
</a>
|
||||
<div class="only-visible-for-spectators">
|
||||
<div class="realm-description">
|
||||
|
|
Loading…
Reference in New Issue