mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-10 23:50:12 +00:00
fixed bug where the backend would fail hard if a too long file name is provided
This commit is contained in:
parent
445cc8dd5f
commit
b5c5c36622
6 changed files with 77 additions and 3 deletions
|
@ -12,7 +12,7 @@ from django.conf import settings
|
|||
from django.core.files.storage import default_storage
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
|
||||
from baserow.core.utils import sha256_hash, stream_size, random_string
|
||||
from baserow.core.utils import sha256_hash, stream_size, random_string, truncate_middle
|
||||
|
||||
from .exceptions import (
|
||||
InvalidFileStreamError, FileSizeTooLargeError, FileURLCouldNotBeReached,
|
||||
|
@ -171,6 +171,7 @@ class UserFileHandler:
|
|||
|
||||
storage = storage or default_storage
|
||||
hash = sha256_hash(stream)
|
||||
file_name = truncate_middle(file_name, 64)
|
||||
|
||||
try:
|
||||
return UserFile.objects.get(original_name=file_name, sha256_hash=hash)
|
||||
|
|
|
@ -3,6 +3,7 @@ import re
|
|||
import random
|
||||
import string
|
||||
import hashlib
|
||||
import math
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
|
@ -213,3 +214,38 @@ def stream_size(stream):
|
|||
size = stream.tell()
|
||||
stream.seek(0)
|
||||
return size
|
||||
|
||||
|
||||
def truncate_middle(content, max_length, middle='...'):
|
||||
"""
|
||||
Truncates the middle part of the string if the total length if too long.
|
||||
|
||||
For example:
|
||||
truncate_middle('testabcdecho', 8) == 'tes...ho'
|
||||
|
||||
:param content: The string that must be truncated.
|
||||
:type: str
|
||||
:param max_length: The maximum amount of characters the string can have.
|
||||
:type max_length: int
|
||||
:param middle: The part that must be added in the middle if the provided
|
||||
content is too long.
|
||||
:type middle str
|
||||
:return: The truncated string.
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
if len(content) <= max_length:
|
||||
return content
|
||||
|
||||
if max_length <= len(middle):
|
||||
raise ValueError('The max_length cannot be lower than the length if the '
|
||||
'middle string.')
|
||||
|
||||
total = max_length - len(middle)
|
||||
start = math.ceil(total / 2)
|
||||
end = math.floor(total / 2)
|
||||
|
||||
left = content[:start]
|
||||
right = content[-end:] if end else ''
|
||||
|
||||
return f'{left}{middle}{right}'
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from io import BytesIO
|
||||
import pytest
|
||||
|
||||
from baserow.core.utils import (
|
||||
extract_allowed, set_allowed_attrs, to_pascal_case, to_snake_case,
|
||||
remove_special_characters, dict_to_object, random_string, sha256_hash,
|
||||
stream_size
|
||||
stream_size, truncate_middle
|
||||
)
|
||||
|
||||
|
||||
|
@ -77,3 +78,19 @@ def test_sha256_hash():
|
|||
|
||||
def test_stream_size():
|
||||
assert stream_size(BytesIO(b'test')) == 4
|
||||
|
||||
|
||||
def test_truncate_middle():
|
||||
assert truncate_middle('testtesttest', 13) == 'testtesttest'
|
||||
assert truncate_middle('testtesttest', 12) == 'testtesttest'
|
||||
assert truncate_middle('testabcdecho', 11) == 'test...echo'
|
||||
assert truncate_middle('testabcdecho', 10) == 'test...cho'
|
||||
assert truncate_middle('testabcdecho', 9) == 'tes...cho'
|
||||
assert truncate_middle('testabcdecho', 8) == 'tes...ho'
|
||||
assert truncate_middle('testabcdecho', 7) == 'te...ho'
|
||||
assert truncate_middle('testabcdecho', 6) == 'te...o'
|
||||
assert truncate_middle('testabcdecho', 5) == 't...o'
|
||||
assert truncate_middle('testabcdecho', 4) == 't...'
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
truncate_middle('testtesttest', 3) == '...'
|
||||
|
|
|
@ -238,6 +238,20 @@ def test_upload_user_file(data_fixture, tmpdir):
|
|||
|
||||
assert UserFile.objects.all().count() == 7
|
||||
|
||||
image = Image.new('RGB', (1, 1), color='red')
|
||||
image_bytes = BytesIO()
|
||||
image.save(image_bytes, format='PNG')
|
||||
user_file = handler.upload_user_file(
|
||||
user,
|
||||
'this_file_has_an_extreme_long_file_name_that_should_not_make_the_system_'
|
||||
'fail_hard_when_trying_to_upload.png',
|
||||
image_bytes,
|
||||
storage=storage
|
||||
)
|
||||
|
||||
assert user_file.original_name == 'this_file_has_an_extreme_long_f...hard_when_' \
|
||||
'trying_to_upload.png'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@responses.activate
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
* Fixed error when a very long user file name is provided when uploading.
|
||||
* Upgraded DRF Spectacular dependency to the latest version.
|
||||
* Added single select field form option validation.
|
||||
* Changed all cookies to SameSite=lax.
|
||||
|
|
|
@ -5,7 +5,12 @@ Baserow is divided into two components, the **backend** and the
|
|||
contains some documentation about those endpoints and how to use them. These endpoints
|
||||
should never be used to show data on your own website because that would mean you have
|
||||
to expose your credentials or JWT token. They should only be used the make changes in
|
||||
in your data. In the future there are going to be features that enable you to expose
|
||||
in your data. You can publicly expose your data in a safe way by creating a
|
||||
[database token](https://api.baserow.io/api/redoc/#operation/create_database_token)
|
||||
token, set the permissions and follow the automatically generated api docs at
|
||||
https://baserow.io/api/docs.
|
||||
|
||||
In the future there are going to be features that enable you to expose
|
||||
your data publicly in a safe way.
|
||||
|
||||
## OpenAPI spec
|
||||
|
|
Loading…
Add table
Reference in a new issue