misc: do not decorate uploaded HTML files (#87331)
gitea/wcs/pipeline/head This commit looks good Details

This commit is contained in:
Frédéric Péters 2024-02-22 16:39:35 +01:00
parent 8a7c779d91
commit b48214feac
10 changed files with 52 additions and 15 deletions

View File

@ -238,6 +238,42 @@ def test_form_file_field_image_submit(pub):
assert '<img alt="" src="tempfile?' not in resp.text
def test_form_file_field_html_submit(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [fields.FileField(id='0', label='file')]
formdef.store()
formdef.data_class().wipe()
html_content = b'<html><body>hello</body></html>'
upload = Upload('test.html', html_content, 'text/html')
app = get_app(pub)
resp = app.get('/test/')
resp.forms[0]['f0$file'] = upload
resp = resp.forms[0].submit('submit')
assert 'Check values then click submit.' in resp.text
tempfile_id = resp.pyquery('.fileinfo .filename a').attr.href.split('=')[1]
resp_tempfile = app.get('/test/tempfile?t=%s' % tempfile_id)
assert resp_tempfile.body == html_content
resp = resp.form.submit('submit').follow()
assert resp.click('test.html').follow().content_type == 'text/html'
assert resp.click('test.html').follow().body == html_content
# check it's also served raw from backoffice
user = create_user(pub)
user.is_admin = True
user.store()
app = get_app(pub)
login(app, username='foo', password='foo')
resp = app.get(formdef.data_class().select()[0].get_backoffice_url())
assert resp.click('test.html').follow().content_type == 'text/html'
assert resp.click('test.html').follow().body == html_content
def test_form_file_field_submit_document_type(pub):
FormDef.wipe()
formdef = FormDef()

View File

@ -388,7 +388,7 @@ class NamedDataSourcePage(Directory):
def preview_block(self):
get_request().disable_error_notifications = True
get_request().ignore_session = True
get_response().filter = {'raw': True}
get_response().raw = True
data_source = self.datasource.extended_data_source
try:
items = get_structured_items(data_source)

View File

@ -401,7 +401,7 @@ class UsersDirectory(Directory):
r += htmltext('</div>')
if get_request().form.get('ajax') == 'true':
get_response().filter = {'raw': True}
get_response().raw = True
return r.getvalue()
ident_methods = get_cfg('identification', {}).get('methods', [])

View File

@ -161,7 +161,7 @@ class NamedWsCallPage(Directory):
def usage(self):
get_request().disable_error_notifications = True
get_request().ignore_session = True
get_response().filter = {'raw': True}
get_response().raw = True
usage = {}

View File

@ -717,7 +717,7 @@ class ManagementDirectory(Directory):
if get_request().form.get('ajax') == 'true':
get_request().ignore_session = True
get_response().filter = {'raw': True}
get_response().raw = True
return r.getvalue()
get_response().filter['sidebar'] = self.get_global_listing_sidebar(
@ -2442,7 +2442,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
if get_request().form.get('ajax') == 'true':
get_request().ignore_session = True
get_response().filter = {'raw': True}
get_response().raw = True
r = TemplateIO(html=True)
r += multi_form.render()
r += get_session().display_message()
@ -3129,7 +3129,7 @@ class FormPage(Directory, TempfileDirectoryMixin):
if get_request().form.get('ajax') == 'true':
get_request().ignore_session = True
get_response().filter = {'raw': True}
get_response().raw = True
return r.getvalue()
page = TemplateIO(html=True)
@ -3368,13 +3368,13 @@ class FormBackOfficeStatusPage(FormStatusPage):
def lateral_block(self):
self.check_receiver()
get_response().filter = {'raw': True}
get_response().raw = True
response = self.get_lateral_block()
return response
def user_pending_forms(self):
self.check_receiver()
get_response().filter = {'raw': True}
get_response().raw = True
response = self.get_user_pending_forms()
# preemptive locking of forms
@ -4159,7 +4159,7 @@ class FormBackOfficeStatusPage(FormStatusPage):
or get_publisher().get_backoffice_root().is_accessible('workflows')
):
raise errors.AccessForbiddenError()
get_response().filter = {'raw': True}
get_response().raw = True
return self.test_tool_result()

View File

@ -175,7 +175,7 @@ class FormFillPage(PublicFormFillPage):
return super()._q_index(*args, **kwargs)
def lateral_block(self):
get_response().filter = {'raw': True}
get_response().raw = True
response = self.get_lateral_block()
return response

View File

@ -92,7 +92,7 @@ class TemplateWithFallbackView(TemplateView):
response.reason_phrase = self.quixote_response.reason_phrase
elif request.headers.get('X-Popup') == 'true':
response = HttpResponse('<div><div class="popup-content">%s</div></div>' % context['body'])
elif 'raw' in (getattr(self.quixote_response, 'filter') or {}):
elif self.quixote_response.raw:
# used for raw HTML snippets (for example in the test tool
# results in inspect page).
response = HttpResponse(context['body'])
@ -161,7 +161,7 @@ class CompatWcsPublisher(WcsPublisher):
if response.status_code == 304:
# clients don't like to receive content with a 304
return ''
if response.content_type != 'text/html':
if response.content_type != 'text/html' or response.raw:
return output
if not hasattr(response, 'filter') or not response.filter:
return output

View File

@ -112,7 +112,7 @@ class FileDirectory(Directory):
# force potential HTML upload to be used as-is (not decorated with theme)
# and with minimal permissions
response.filter = {}
response.raw = True
response.set_header(
'Content-Security-Policy',
'default-src \'none\'; img-src %s;' % get_request().build_absolute_uri(),
@ -1074,7 +1074,7 @@ class TempfileDirectoryMixin:
# force potential HTML upload to be used as-is (not decorated with theme)
# and with minimal permissions
response.filter = {}
response.raw = True
response.set_header(
'Content-Security-Policy',
'default-src \'none\'; img-src %s;' % get_request().build_absolute_uri(),

View File

@ -28,6 +28,7 @@ class HTTPResponse(quixote.http_response.HTTPResponse):
javascript_code_parts = None
css_includes = None
after_jobs = None
raw = False # in case of html content, send result as is (True) or embedded in page template (False)
def __init__(self, charset=None, **kwargs):
quixote.http_response.HTTPResponse.__init__(self, charset=charset, **kwargs)

View File

@ -78,7 +78,7 @@ def error_page(error_message, error_title=None, location_hint=None):
def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs):
from .publisher import get_cfg
if response.content_type != 'text/html':
if response.content_type != 'text/html' or response.raw:
return {'body': body}
if get_request().get_header('x-popup') == 'true':