misc: directly serve cards file fields when url is signed (#55374)

This commit is contained in:
Frédéric Péters 2021-07-04 15:12:12 +02:00
parent 07bc7d4b6f
commit d2496c3973
5 changed files with 52 additions and 6 deletions

View File

@ -355,6 +355,35 @@ def test_cards_http_auth_access(pub, local_user):
assert resp.json['err_desc'] == 'unsufficient roles'
def test_card_get_file(pub):
pub.role_class.wipe()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'test'
carddef.fields = [
fields.StringField(id='0', label='foobar', varname='foobar'),
fields.FileField(id='3', label='foobar4', varname='file'),
]
carddef.store()
upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
upload.receive([b'file content'])
carddef.data_class().wipe()
formdata = carddef.data_class()()
formdata.data = {'0': 'blah', '3': upload}
formdata.just_created()
formdata.store()
resp = get_app(pub).get(sign_uri('/api/cards/test/%s/' % formdata.id))
file_url = resp.json['fields']['file']['url']
assert get_app(pub).get(file_url, status=403)
resp = get_app(pub).get(sign_uri(file_url), status=200)
assert resp.text == 'file content'
def test_post_invalid_json(pub, local_user):
resp = get_app(pub).post(
'/api/cards/test/submit', params='not a json payload', content_type='application/json', status=400

View File

@ -51,6 +51,9 @@ class CardData(FormData):
def get_author_qualification(self):
return None
def get_file_base_url(self):
return '%sdownload' % self.get_api_url()
def just_created(self):
super().just_created()
if self.submission_agent_id:

View File

@ -1438,7 +1438,7 @@ class FileField(WidgetField):
return t.getvalue()
def get_download_url(self, formdata, **kwargs):
return '%sdownload?%s' % (formdata.get_url(), self.get_download_query_string(**kwargs))
return '%s?%s' % (formdata.get_file_base_url(), self.get_download_query_string(**kwargs))
def get_opendocument_node_value(self, value, formdata=None, **kwargs):
show_link = True

View File

@ -70,8 +70,8 @@ def get_dict_with_varnames(fields, data, formdata=None, varnames_only=False):
if value and hasattr(value, 'base_filename'):
new_data['var_%s' % field.varname] = value.base_filename
if formdata is not None:
new_data['var_%s_url' % field.varname] = '%sdownload?f=%s' % (
formdata.get_url(),
new_data['var_%s_url' % field.varname] = '%s?f=%s' % (
formdata.get_file_base_url(),
field.id,
)
elif raw_value is not None:
@ -698,6 +698,9 @@ class FormData(StorableObject):
def get_api_url(self):
return '%s%s/' % (self.formdef.get_api_url(), self.id)
def get_file_base_url(self):
return '%sdownload' % self.get_url()
def get_display_id(self):
return str(self.id_display or self.id)

View File

@ -36,11 +36,11 @@ from ..qommon import _, errors, get_logger, misc, template
class FileDirectory(Directory):
_q_exports = []
_lookup_methods = ['lookup_file_field']
thumbnails = False
def __init__(self, formdata, reference):
def __init__(self, formdata, reference, thumbnails=False):
self.formdata = formdata
self.reference = reference
self.thumbnails = thumbnails
def lookup_file_field(self, filename):
try:
@ -674,7 +674,8 @@ class FormStatusPage(Directory, FormTemplateMixin):
return get_publisher().get_root_url()
def download(self):
self.check_receiver()
if not is_url_signed():
self.check_receiver()
try:
fn = get_request().form['f']
if '$' in fn:
@ -704,8 +705,18 @@ class FormStatusPage(Directory, FormTemplateMixin):
else:
raise errors.TraversalError()
if is_url_signed():
# serve file directly, no redirect to URL with path ending with filename
file_directory = FileDirectory(
self.filled,
reference=fn,
thumbnails=bool(get_request().form.get('thumbnail') and file.can_thumbnail()),
)
return file_directory._q_lookup(component=None)
if getattr(file, 'base_filename'):
file_url += urllib.parse.quote(file.base_filename)
return redirect(file_url)
@classmethod