1
0
mirror of https://github.com/taigaio/taiga-back synced 2025-10-06 00:02:52 +02:00

add util method for sanitize csv write values

This commit is contained in:
Héctor Fernández
2025-03-19 17:34:31 +01:00
parent 31e7706404
commit 81644a3beb
2 changed files with 63 additions and 30 deletions

View File

@@ -5,6 +5,7 @@
#
# Copyright (c) 2021-present Kaleidos INC
def strip_lines(text):
"""
Given text, try remove unnecessary spaces and
@@ -16,3 +17,12 @@ def strip_lines(text):
def split_in_lines(text):
"""Split a block of text in lines removing unnecessary spaces from each line."""
return (line for line in map(str.strip, text.split("\n")) if line)
def sanitize_csv_text_value(value):
"""Sanitize CSV data to prevent formula injection attacks."""
return (
"'" + value
if isinstance(value, str) and value.startswith(("=", "+", "-", "@"))
else value
)

View File

@@ -12,8 +12,15 @@ from unittest import mock
import django_sites as sites
import re
from taiga.base.utils.urls import get_absolute_url, is_absolute_url, build_url, \
validate_private_url, IpAddresValueError, HostnameException
from taiga.base.utils.text import sanitize_csv_text_value
from taiga.base.utils.urls import (
get_absolute_url,
is_absolute_url,
build_url,
validate_private_url,
IpAddresValueError,
HostnameException,
)
from taiga.base.utils.db import save_in_bulk, update_in_bulk, to_tsquery
pytestmark = pytest.mark.django_db(transaction=True)
@@ -28,7 +35,9 @@ def test_is_absolute_url():
def test_get_absolute_url():
site = sites.get_current()
assert get_absolute_url("http://domain/path") == "http://domain/path"
assert get_absolute_url("/path") == build_url("/path", domain=site.domain, scheme=site.scheme)
assert get_absolute_url("/path") == build_url(
"/path", domain=site.domain, scheme=site.scheme
)
def test_save_in_bulk():
@@ -96,47 +105,61 @@ TS_QUERY_TRANSFORMATIONS = [
def test_to_tsquery():
for (input, expected) in TS_QUERY_TRANSFORMATIONS:
for input, expected in TS_QUERY_TRANSFORMATIONS:
expected = re.sub("([0-9])", r"'\1':*", expected)
actual = to_tsquery(input)
assert actual == expected
@pytest.mark.parametrize("url", [
"http://127.0.0.1",
"http://[::1]",
"http://192.168.0.12",
"http://10.0.0.1",
"https://172.25.0.1",
"https://10.25.23.100",
"ftp://192.168.1.100/",
"http://[::ffff:c0a8:164]/",
"scp://192.168.1.100/",
"http://www.192-168-1-100.sslip.io/",
])
@pytest.mark.parametrize(
"url",
[
"http://127.0.0.1",
"http://[::1]",
"http://192.168.0.12",
"http://10.0.0.1",
"https://172.25.0.1",
"https://10.25.23.100",
"ftp://192.168.1.100/",
"http://[::ffff:c0a8:164]/",
"scp://192.168.1.100/",
"http://www.192-168-1-100.sslip.io/",
],
)
def test_validate_bad_destination_address(url):
with pytest.raises(IpAddresValueError):
validate_private_url(url)
@pytest.mark.parametrize("url", [
"http://test.local/",
"http://test.test/",
])
@pytest.mark.parametrize(
"url",
[
"http://test.local/",
"http://test.test/",
],
)
def test_validate_invalid_destination_address(url):
with pytest.raises(HostnameException):
validate_private_url(url)
@pytest.mark.parametrize("url", [
"http://192.167.0.12",
"http://11.0.0.1",
"https://173.25.0.1",
"https://193.24.23.100",
"ftp://173.168.1.100/",
"scp://194.168.1.100/",
"http://www.google.com/",
"http://1.1.1.1/",
])
@pytest.mark.parametrize(
"url",
[
"http://192.167.0.12",
"http://11.0.0.1",
"https://173.25.0.1",
"https://193.24.23.100",
"ftp://173.168.1.100/",
"scp://194.168.1.100/",
"http://www.google.com/",
"http://1.1.1.1/",
],
)
def test_validate_good_destination_address(url):
assert validate_private_url(url) is None
@pytest.mark.parametrize("value, expected", [("=(3+3)", "'=(3+3)"), (5, 5)])
def test_sanitize_csv_text_value(value, expected):
assert expected == sanitize_csv_text_value(value)