HTML escape and/or JavaScript quote item fields that are substituted into templates to prevent invalid HTML/JavaScript.

This commit is contained in:
Greg Neagle
2015-06-10 14:19:14 -07:00
parent b37a514624
commit 73a1a33e80
8 changed files with 79 additions and 41 deletions
@@ -520,7 +520,7 @@ class GenericItem(dict):
icon_name += '.png'
icon_path = os.path.join(msclib.html_dir(), 'icons', icon_name)
if os.path.exists(icon_path):
return 'icons/' + icon_name
return 'icons/' + quote(icon_name)
# didn't find one in the downloaded icons
# so create one if needed from a locally installed app
for key in ['icon_name', 'display_name', 'name']:
@@ -531,7 +531,7 @@ class GenericItem(dict):
icon_name += '.png'
icon_path = os.path.join(msclib.html_dir(), icon_name)
if os.path.exists(icon_path) or convertIconToPNG(name, icon_path, 350):
return icon_name
return quote(icon_name)
else:
# use the Generic package icon
return 'static/Generic.png'
@@ -115,6 +115,32 @@ def generate_page(page_name, main_page_template_name, page_dict, **kwargs):
write_page(page_name, html)
def escape_quotes(text):
"""Escape single and double-quotes for JavaScript"""
return text.replace("'", r"\'").replace('"', r'\"')
def escape_html(text):
"""Convert some problematic characters to entities"""
html_escape_table = {
"&": "&",
'"': """,
"'": "'",
">": ">",
"<": "&lt;",
}
return "".join(html_escape_table.get(c, c) for c in text)
def escapeAndQuoteCommonFields(item):
'''Adds _escaped and _quoted versions of several commonly-used fields'''
item['name_escaped'] = escape_html(item['name'])
item['name_quoted'] = escape_html(escape_quotes(item['name']))
item['display_name_escaped'] = escape_html(item['display_name'])
item['developer_escaped'] = escape_html(item['developer'])
item['display_version_escaped'] = escape_html(item['display_version'])
def addGeneralLabels(page):
'''adds localized labels for Software, Categories, My Items and Updates to html pages'''
page['SoftwareLabel'] = NSLocalizedString(u"Software", u"Software label")
@@ -172,7 +198,9 @@ def build_detail_page(item_name):
page_name = u'detail-%s.html' % item_name
for item in items:
if item['name'] == item_name:
# make a copy of the item to use to build our page
page = MunkiItems.OptionalItem(item)
escapeAndQuoteCommonFields(page)
addDetailSidebarLabels(page)
# make "More in CategoryFoo" list
page['hide_more_in_category'] = u'hidden'
@@ -191,6 +219,7 @@ def build_detail_page(item_name):
shuffle(more_in_category)
more_template = get_template('detail_more_items_template.html')
for more_item in more_in_category[:4]:
more_item['display_name_escaped'] = escape_html(more_item['display_name'])
more_item['second_line'] = more_item.get('developer', '')
more_in_category_html += more_template.safe_substitute(more_item)
page['more_in_category'] = more_in_category_html
@@ -214,6 +243,7 @@ def build_detail_page(item_name):
more_template = get_template(
'detail_more_items_template.html')
for more_item in more_by_developer[:4]:
escapeAndQuoteCommonFields(more_item)
more_item['second_line'] = more_item.get('category', '')
more_by_developer_html += more_template.safe_substitute(more_item)
page['more_by_developer'] = more_by_developer_html
@@ -310,6 +340,8 @@ def build_list_page_items_html(category=None, developer=None, filter=None):
if items:
item_template = get_template('list_item_template.html')
for item in sorted(items, key=itemgetter('display_name_lower')):
escapeAndQuoteCommonFields(item)
item['category_and_developer_escaped'] = escape_html(item['category_and_developer'])
item_html += item_template.safe_substitute(item)
# pad with extra empty items so we have a multiple of 3
if len(items) % 3:
@@ -391,24 +423,27 @@ def build_category_items_html():
item_html = u''
for category in sorted(category_list):
category_data = {}
category_data['category_name'] = category
category_data['category_name_escaped'] = escape_html(category)
category_data['category_link'] = u'category-%s.html' % quote(category)
category_items = [item for item in all_items if item.get('category') == category]
shuffle(category_items)
category_data['item1_icon'] = category_items[0]['icon']
category_data['item1_display_name'] = category_items[0]['display_name']
category_data['item1_display_name_escaped'] = escape_html(
category_items[0]['display_name'])
category_data['item1_detail_link'] = category_items[0]['detail_link']
if len(category_items) > 1:
category_data['item2_display_name'] = category_items[1]['display_name']
category_data['item2_display_name_escaped'] = escape_html(
category_items[1]['display_name'])
category_data['item2_detail_link'] = category_items[1]['detail_link']
else:
category_data['item2_display_name'] = u''
category_data['item2_display_name_escaped'] = u''
category_data['item2_detail_link'] = u'#'
if len(category_items) > 2:
category_data['item3_display_name'] = category_items[2]['display_name']
category_data['item3_display_name_escaped'] = escape_html(
category_items[2]['display_name'])
category_data['item3_detail_link'] = category_items[2]['detail_link']
else:
category_data['item3_display_name'] = u''
category_data['item3_display_name_escaped'] = u''
category_data['item3_detail_link'] = u'#'
item_html += item_template.safe_substitute(category_data)
@@ -454,6 +489,7 @@ def build_myitems_rows():
item_template = get_template('myitems_row_template.html')
myitems_rows = u''
for item in sorted(item_list, key=itemgetter('display_name_lower')):
escapeAndQuoteCommonFields(item)
myitems_rows += item_template.safe_substitute(item)
else:
status_results_template = get_template('status_results_template.html')
@@ -494,6 +530,7 @@ def build_updates_page():
if item_list:
for item in item_list:
escapeAndQuoteCommonFields(item)
page['update_rows'] += item_template.safe_substitute(item)
elif not other_updates:
status_results_template = get_template('status_results_template.html')
@@ -615,8 +652,9 @@ def build_updatedetail_page(identifier):
page_name = u'updatedetail-%s.html' % identifier
name, sep, version = identifier.partition('--version-')
for item in items:
if item['name'] == name and item['version_to_install'] == version:
if item['name'] == name and item.get('version_to_install', '') == version:
page = MunkiItems.UpdateItem(item)
escapeAndQuoteCommonFields(page)
addDetailSidebarLabels(page)
force_install_after_date = item.get('force_install_after_date')
if force_install_after_date:
@@ -5,9 +5,9 @@
</div>
</a>
<ul class="list">
<li class="name"><a href="${category_link}">${category_name}</a></li>
<li class="genre"><a href="${item1_detail_link}">${item1_display_name}</a></li>
<li class="genre"><a href="${item2_detail_link}">${item2_display_name}</a></li>
<li class="genre"><a href="${item3_detail_link}">${item3_display_name}</a></li>
<li class="name"><a href="${category_link}">${category_name_escaped}</a></li>
<li class="genre"><a href="${item1_detail_link}">${item1_display_name_escaped}</a></li>
<li class="genre"><a href="${item2_detail_link}">${item2_display_name_escaped}</a></li>
<li class="genre"><a href="${item3_detail_link}">${item3_display_name_escaped}</a></li>
</ul>
</div>
@@ -1,12 +1,12 @@
<div class="lockup small detailed option application mac-application">
<a href="${detail_link}" class="artwork-link">
<div class="artwork">
<img width="75" height="75" alt="${display_name}" class="artwork" src="${icon}" />
<img width="75" height="75" alt="${display_name_escaped}" class="artwork" src="${icon}" />
</div>
</a>
<ul class="list">
<li class="name">
<a href="${detail_link}">${display_name}</a>
<a href="${detail_link}">${display_name_escaped}</a>
</li>
<li class="genre">${second_line}</li>
</ul>
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>${display_name}</title>
<title>${display_name_escaped}</title>
<link charset="utf-8" rel="stylesheet" type="text/css" href="static/base.css" />
<link charset="utf-8" rel="stylesheet" type="text/css" href="static/detail.css" />
@@ -19,13 +19,13 @@
<div class="product-detail">
<div class="lockup product">
<div class="artwork">
<img width="175" height="175" alt="${display_name}" class="artwork" src="${icon}" />
<img width="175" height="175" alt="${display_name_escaped}" class="artwork" src="${icon}" />
</div>
<div class="msc-button large">
<button class="button-area uppercase"
onClick="window.AppController.actionButtonClicked_('${name}');">
onClick="window.AppController.actionButtonClicked_('${name_quoted}');">
<div class="msc-button-inner large ${status}"
id="${name}_action_button_text">
id="${name_escaped}_action_button_text">
${long_action_text}
</div>
</button>
@@ -39,7 +39,7 @@
<div class="product-info box-flex">
<div class="product-review">
<div class="title">
<h1>${display_name}</h1>
<h1>${display_name_escaped}</h1>
</div>
<p class="more-text">
${description}
@@ -63,15 +63,15 @@
<li><span class="label">${sizeLabel} </span>${size}</li>
<li>
<span class="label">${developerLabel} </span>
<a href="${developer_link}">${developer}</a>
<a href="${developer_link}">${developer_escaped}</a>
</li>
</ul>
<hr/>
<ul class="list">
<li>
<span class="label">${statusLabel} </span>
<span class="${status}" id="${name}_status_text">
<span id="${name}_status_text_span">
<span class="${status}" id="${name_escaped}_status_text">
<span id="${name_escaped}_status_text_span">
${status_text}
</span>
<a class="follow" href="updates.html"></a>
@@ -1,19 +1,19 @@
<tr class="installation" id="${name}_myitems_table_row">
<tr class="installation" id="${name_escaped}_myitems_table_row">
<td>
<a href="${detail_link}" class="artwork-link">
<div class="artwork">
<img width="75" height="75" alt="${display_name}" class="artwork" src="${icon}" />
<img width="75" height="75" alt="${display_name_escaped}" class="artwork" src="${icon}" />
</div>
</a>
<ul class="list info">
<li><h2><a title="${display_name}" href="${detail_link}">${display_name}</a></h2></li>
<li>${developer}</li>
<li><h2><a title="${display_name_escaped}" href="${detail_link}">${display_name_escaped}</a></h2></li>
<li>${developer_escaped}</li>
</ul>
</td>
<td>${version_to_install}</td>
<td>${size}</td>
<td class="status">
<span class="${status}" id="${name}_status_text">
<span class="${status}" id="${name_escaped}_status_text">
${status_text}
<a class="follow" href="updates.html">
</span>
@@ -21,9 +21,9 @@
<td>
<div class="msc-button install-updates">
<button class="button-area uppercase"
onClick="window.AppController.myItemsActionButtonClicked_('${name}');">
onClick="window.AppController.myItemsActionButtonClicked_('${name_quoted}');">
<div class="msc-button-inner install-updates ${status}"
id="${name}_action_button_text">
id="${name_escaped}_action_button_text">
${myitem_action_text}
</div>
</button>
@@ -1,14 +1,14 @@
<tr class='installation ${added_or_deleted}' id="${name}_update_table_row">
<tr class='installation ${added_or_deleted}' id="${name_escaped}_update_table_row">
<td>
<a href="${detail_link}" class="artwork-link">
<div class="artwork">
<img width="75" height="75" alt="${display_name}" class="artwork" src="${icon}">
<img width="75" height="75" alt="${display_name_escaped}" class="artwork" src="${icon}">
</div>
</a>
<ul class="list info">
<li><h2><a title="${display_name}" href="${detail_link}">${display_name}</a></h2></li>
<li>${developer}</li>
<li>${version_label} ${display_version}</li>
<li><h2><a title="${display_name_escaped}" href="${detail_link}">${display_name_escaped}</a></h2></li>
<li>${developer_escaped}</li>
<li>${version_label} ${display_version_escaped}</li>
<li class="warning">${restart_action_text}</li>
</ul>
</td>
@@ -20,6 +20,6 @@
</td>
<td class="${hide_cancel_button}">
<button title="${long_action_text}" class="cancel-or-add" aria-label="${long_action_text}"
onClick="fadeOutAndRemove('${name}');"></button>
onClick="fadeOutAndRemove('${name_quoted}');"></button>
</td>
</tr>
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>${display_name}</title>
<title>${display_name_escaped}</title>
<link charset="utf-8" rel="stylesheet" type="text/css" href="static/base.css" />
<link charset="utf-8" rel="stylesheet" type="text/css" href="static/detail.css" />
@@ -20,7 +20,7 @@
<div class="lockup product">
<!--<a href="#">-->
<div class="artwork">
<img width="175" height="175" alt="${display_name}" class="artwork" src="${icon}" />
<img width="175" height="175" alt="${display_name_escaped}" class="artwork" src="${icon}" />
</div>
<!--</a>-->
<div class="warning">
@@ -32,7 +32,7 @@
<div class="product-info box-flex">
<div class="product-review">
<div class="title">
<h1>${display_name}</h1>
<h1>${display_name_escaped}</h1>
</div>
<p class="more-text">
${description}
@@ -48,9 +48,9 @@
<div class="content">
<ul class="list">
<li><span class="label">${typeLabel} </span>${type}</li>
<li><span class="label">${versionLabel} </span>${display_version}</li>
<li><span class="label">${versionLabel} </span>${display_version_escaped}</li>
<li><span class="label">${sizeLabel} </span>${size}</li>
<li><span class="label">${developerLabel} </span>${developer}</li>
<li><span class="label">${developerLabel} </span>${developer_escaped}</li>
</ul>
<hr/>
<ul class="list">