[FIX] P3: remove cgi.escape uses

cgi.escape is unsafe (quote=False by default) and deprecated in Python
3. We already have an openerp.tools.misc.html_escape version which
forwards to the (modern and safe) werkzeug.utils.escape, just use that
everywhere, and convert extant uses of werkzeug.utils.escape to
utils.html_escape as well so that we do the same thing everywhere.
This commit is contained in:
Xavier Morel
2017-05-15 12:26:31 +02:00
parent 5617d4614b
commit e2f1af78c4
8 changed files with 28 additions and 35 deletions
+2 -2
View File
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cgi
import json
from odoo import http
from odoo.http import request
from odoo.tools import misc
class ImportController(http.Controller):
@@ -20,4 +20,4 @@ class ImportController(http.Controller):
'file_type': file.content_type,
})
return 'window.top.%s(%s)' % (cgi.escape(jsonp), json.dumps({'result': written}))
return 'window.top.%s(%s)' % (misc.html_escape(jsonp), json.dumps({'result': written}))
@@ -1,6 +1,5 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cgi
import json
import logging
@@ -10,6 +9,7 @@ import re
import werkzeug.urls
from odoo import api, models
from odoo.tools import misc
from odoo.addons.google_account import TIMEOUT
_logger = logging.getLogger(__name__)
@@ -70,7 +70,7 @@ class GoogleDrive(models.Model):
href="https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full/R60C15"/>
<gs:cell row="60" col="15" inputValue="{config}"/>
</entry>
</feed>''' .format(key=spreadsheet_key, formula=cgi.escape(formula, quote=True), config=cgi.escape(config_formula, quote=True))
</feed>''' .format(key=spreadsheet_key, formula=misc.html_escape(formula), config=misc.html_escape(config_formula))
try:
req = requests.post(
@@ -8,6 +8,7 @@ import werkzeug
import odoo
from odoo import http
from odoo.tools import misc
_logger = logging.getLogger(__name__)
@@ -106,7 +107,7 @@ class PosboxHomepage(odoo.addons.web.controllers.main.Home):
f = open('/tmp/scanned_networks.txt', 'r')
for line in f:
line = line.rstrip()
line = werkzeug.utils.escape(line)
line = misc.html_escape(line)
wifi_template += '<option value="' + line + '">' + line + '</option>\n'
f.close()
except IOError:
@@ -3,15 +3,12 @@
from datetime import date, timedelta
import cgi
import ssl
import requests
import werkzeug
from odoo import models, api, service
from odoo.exceptions import UserError
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, misc
class MercuryTransaction(models.Model):
@@ -53,7 +50,7 @@ class MercuryTransaction(models.Model):
soap_header = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mer="http://www.mercurypay.com"><soapenv:Header/><soapenv:Body><mer:CreditTransaction><mer:tran>'
soap_footer = '</mer:tran><mer:pw>' + data['merchant_pwd'] + '</mer:pw></mer:CreditTransaction></soapenv:Body></soapenv:Envelope>'
xml_transaction = soap_header + cgi.escape(xml_transaction) + soap_footer
xml_transaction = soap_header + misc.escape_html(xml_transaction) + soap_footer
response = ''
+1 -2
View File
@@ -12,7 +12,6 @@ from odoo import fields, tools
from odoo.http import request
from odoo.modules.module import get_resource_path
import psycopg2
import werkzeug
from odoo.tools import func, misc, pycompat
import logging
@@ -587,7 +586,7 @@ class StylesheetAsset(WebAsset):
return self.with_header(content)
def to_html(self):
media = (' media="%s"' % werkzeug.utils.escape(self.media)) if self.media else ''
media = (' media="%s"' % misc.html_escape(self.media)) if self.media else ''
if self.url:
href = self.html_url
return '<link rel="stylesheet" href="%s" type="text/css"%s/>' % (href, media)
+10 -11
View File
@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cgi
import unittest
from odoo.tools import html_sanitize, append_content_to_html, plaintext2html, email_split
from odoo.tools import html_sanitize, append_content_to_html, plaintext2html, email_split, misc
from . import test_mail_examples
@@ -99,7 +98,7 @@ class TestSanitizer(unittest.TestCase):
"Div nico <div-nico@open.com>"
]
for email in emails:
self.assertIn(cgi.escape(email), html_sanitize(email), 'html_sanitize stripped emails of original html')
self.assertIn(misc.html_escape(email), html_sanitize(email), 'html_sanitize stripped emails of original html')
def test_sanitize_unescape_emails(self):
not_emails = [
@@ -108,7 +107,7 @@ class TestSanitizer(unittest.TestCase):
for email in not_emails:
sanitized = html_sanitize(email)
left_part = email.split('>')[0] # take only left part, as the sanitizer could add data information on node
self.assertNotIn(cgi.escape(email), sanitized, 'html_sanitize stripped emails of original html')
self.assertNotIn(misc.html_escape(email), sanitized, 'html_sanitize stripped emails of original html')
self.assertIn(left_part, sanitized)
def test_style_parsing(self):
@@ -172,14 +171,14 @@ class TestSanitizer(unittest.TestCase):
for ext in test_mail_examples.QUOTE_BLOCKQUOTE_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.QUOTE_BLOCKQUOTE_OUT:
self.assertIn('<span data-o-mail-quote="1">%s' % cgi.escape(ext.decode('utf-8')), html)
self.assertIn('<span data-o-mail-quote="1">%s' % misc.html_escape(ext.decode('utf-8')), html)
def test_quote_thunderbird(self):
html = html_sanitize(test_mail_examples.QUOTE_THUNDERBIRD_1)
for ext in test_mail_examples.QUOTE_THUNDERBIRD_1_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.QUOTE_THUNDERBIRD_1_OUT:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(ext.decode('utf-8')), html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(ext.decode('utf-8')), html)
def test_quote_hotmail_html(self):
html = html_sanitize(test_mail_examples.QUOTE_HOTMAIL_HTML)
@@ -226,7 +225,7 @@ class TestSanitizer(unittest.TestCase):
for text in in_lst:
self.assertIn(text, new_html)
for text in out_lst:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(text), new_html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(text), new_html)
def test_quote_signature(self):
test_data = [
@@ -245,27 +244,27 @@ class TestSanitizer(unittest.TestCase):
for ext in test_mail_examples.GMAIL_1_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.GMAIL_1_OUT:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(ext), html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(ext), html)
def test_quote_text(self):
html = html_sanitize(test_mail_examples.TEXT_1)
for ext in test_mail_examples.TEXT_1_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.TEXT_1_OUT:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(ext), html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(ext), html)
html = html_sanitize(test_mail_examples.TEXT_2)
for ext in test_mail_examples.TEXT_2_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.TEXT_2_OUT:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(ext), html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(ext), html)
def test_quote_bugs(self):
html = html_sanitize(test_mail_examples.BUG1)
for ext in test_mail_examples.BUG_1_IN:
self.assertIn(ext, html)
for ext in test_mail_examples.BUG_1_OUT:
self.assertIn('<span data-o-mail-quote="1">%s</span>' % cgi.escape(ext.decode('utf-8')), html)
self.assertIn('<span data-o-mail-quote="1">%s</span>' % misc.html_escape(ext.decode('utf-8')), html)
def test_misc(self):
# False / void should not crash
+3 -5
View File
@@ -1,19 +1,17 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cgi
import collections
import json
import os.path
import re
from lxml import etree
from itertools import chain
from odoo.modules import get_module_resource
from odoo.tests.common import TransactionCase
from odoo.addons.base.ir.ir_qweb import QWebException
from odoo.tools import pycompat
from odoo.tools import pycompat, misc, ustr
def dedent_and_strip(string):
@@ -48,12 +46,12 @@ class TestQWebTField(TransactionCase):
result = self.engine.render(field, {'company': company})
self.assertEqual(
result,
ustr(result),
'<span data-oe-model="res.company" data-oe-id="%d" '
'data-oe-field="name" data-oe-type="char" '
'data-oe-expression="company.name">%s</span>' % (
company.id,
cgi.escape(s.encode('utf-8')),
misc.html_escape(s),
),
)
+6 -7
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cgi
import logging
import lxml.html.clean as clean
import random
@@ -16,7 +15,7 @@ from lxml import etree
import odoo
from odoo.loglevels import ustr
from odoo.tools import pycompat
from odoo.tools import pycompat, misc
_logger = logging.getLogger(__name__)
@@ -178,10 +177,10 @@ def html_sanitize(src, silent=True, sanitize_tags=True, sanitize_attributes=Fals
part = re.compile(r"(<(([^a<>]|a[^<>\s])[^<>]*)@[^<>]+>)", re.IGNORECASE | re.DOTALL)
# remove results containing cite="mid:email_like@address" (ex: blockquote cite)
# cite_except = re.compile(r"^((?!cite[\s]*=['\"]).)*$", re.IGNORECASE)
src = part.sub(lambda m: ('cite=' not in m.group(1) and 'alt=' not in m.group(1)) and cgi.escape(m.group(1)) or m.group(1), src)
src = part.sub(lambda m: ('cite=' not in m.group(1) and 'alt=' not in m.group(1)) and misc.html_escape(m.group(1)) or m.group(1), src)
# html encode mako tags <% ... %> to decode them later and keep them alive, otherwise they are stripped by the cleaner
src = src.replace('<%', cgi.escape('<%'))
src = src.replace('%>', cgi.escape('%>'))
src = src.replace('<%', misc.html_escape('<%'))
src = src.replace('%>', misc.html_escape('%>'))
kwargs = {
'page_structure': True,
@@ -334,7 +333,7 @@ def html2plaintext(html, body_id=None, encoding='utf-8'):
def plaintext2html(text, container_tag=False):
""" Convert plaintext into html. Content of the text is escaped to manage
html entities, using cgi.escape().
html entities, using misc.html_escape().
- all \n,\r are replaced by <br />
- enclose content into <p>
- convert url into clickable link
@@ -343,7 +342,7 @@ def plaintext2html(text, container_tag=False):
:param string container_tag: container of the html; by default the
content is embedded into a <div>
"""
text = cgi.escape(ustr(text))
text = misc.html_escape(ustr(text))
# 1. replace \n and \r
text = text.replace('\n', '<br/>')