diff --git a/apps/common/drf/parsers/csv.py b/apps/common/drf/parsers/csv.py index 95a9ec732..58b3f7bc2 100644 --- a/apps/common/drf/parsers/csv.py +++ b/apps/common/drf/parsers/csv.py @@ -6,18 +6,27 @@ import chardet import codecs import unicodecsv +from django.utils.translation import ugettext as _ from rest_framework.parsers import BaseParser -from rest_framework.exceptions import ParseError +from rest_framework.exceptions import ParseError, APIException +from rest_framework import status from common.utils import get_logger logger = get_logger(__file__) +class CsvDataTooBig(APIException): + status_code = status.HTTP_400_BAD_REQUEST + default_code = 'csv_data_too_big' + default_detail = _('The max size of CSV is %d bytes') + + class JMSCSVParser(BaseParser): """ Parses CSV file to serializer data """ + CSV_UPLOAD_MAX_SIZE = 1024 * 1024 * 10 media_type = 'text/csv' @@ -46,23 +55,31 @@ class JMSCSVParser(BaseParser): return fields_map @staticmethod - def _process_row(row): + def _replace_chinese_quot(str_): + trans_table = str.maketrans({ + '“': '"', + '”': '"', + '‘': '"', + '’': '"', + '\'': '"' + }) + return str_.translate(trans_table) + + @classmethod + def _process_row(cls, row): """ 构建json数据前的行处理 """ _row = [] + for col in row: # 列表转换 - if isinstance(col, str) and col.find("[") != -1 and col.find("]") != -1: - # 替换中文格式引号 - col = col.replace("“", '"').replace("”", '"').\ - replace("‘", '"').replace('’', '"').replace("'", '"') + if isinstance(col, str) and col.startswith('[') and col.endswith(']'): + col = cls._replace_chinese_quot(col) col = json.loads(col) # 字典转换 - if isinstance(col, str) and col.find("{") != -1 and col.find("}") != -1: - # 替换中文格式引号 - col = col.replace("“", '"').replace("”", '"'). \ - replace("‘", '"').replace('’', '"').replace("'", '"') + if isinstance(col, str) and col.startswith("{") and col.endswith("}"): + col = cls._replace_chinese_quot(col) col = json.loads(col) _row.append(col) return _row @@ -82,11 +99,19 @@ class JMSCSVParser(BaseParser): def parse(self, stream, media_type=None, parser_context=None): parser_context = parser_context or {} try: - serializer = parser_context["view"].get_serializer() + view = parser_context['view'] + meta = view.request.META + serializer = view.get_serializer() except Exception as e: logger.debug(e, exc_info=True) raise ParseError('The resource does not support imports!') + content_length = int(meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0))) + if content_length > self.CSV_UPLOAD_MAX_SIZE: + msg = CsvDataTooBig.default_detail % self.CSV_UPLOAD_MAX_SIZE + logger.error(msg) + raise CsvDataTooBig(msg) + try: stream_data = stream.read() stream_data = stream_data.strip(codecs.BOM_UTF8) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 23c9e9043..5854d565a 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 66df40408..11d4c9e49 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-24 16:46+0800\n" +"POT-Creation-Date: 2020-06-28 18:58+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -608,7 +608,7 @@ msgid "Assets" msgstr "资产管理" #: assets/models/user.py:111 templates/_nav.html:17 -#: users/views/profile/password.py:42 users/views/profile/pubkey.py:36 +#: users/views/profile/password.py:40 users/views/profile/pubkey.py:36 msgid "Users" msgstr "用户管理" @@ -1133,8 +1133,8 @@ msgid "" "after {} minutes)" msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)" -#: authentication/errors.py:48 users/views/profile/otp.py:107 -#: users/views/profile/otp.py:146 users/views/profile/otp.py:166 +#: authentication/errors.py:48 users/views/profile/otp.py:63 +#: users/views/profile/otp.py:102 users/views/profile/otp.py:121 msgid "MFA code invalid, or ntp sync server time" msgstr "MFA验证码不正确,或者服务器端时间不对" @@ -1364,6 +1364,11 @@ msgstr "%(name)s 创建成功" msgid "%(name)s was updated successfully" msgstr "%(name)s 更新成功" +#: common/drf/parsers/csv.py:22 +#, python-format +msgid "The max size of CSV is %d bytes" +msgstr "CSV 文件最大为 %d 字节" + #: common/fields/form.py:33 msgid "Not a valid json" msgstr "不是合法json" @@ -2647,7 +2652,7 @@ msgstr "复制用户公钥到这里" msgid "Join user groups" msgstr "添加到用户组" -#: users/forms/user.py:103 users/views/profile/password.py:59 +#: users/forms/user.py:103 users/views/profile/password.py:57 #: users/views/profile/reset.py:123 msgid "* Your password does not meet the requirements" msgstr "* 您的密码不符合要求" @@ -3483,27 +3488,27 @@ msgstr "" "
\n" " " -#: users/views/profile/otp.py:190 +#: users/views/profile/otp.py:145 msgid "MFA enable success" msgstr "多因子认证启用成功" -#: users/views/profile/otp.py:191 +#: users/views/profile/otp.py:146 msgid "MFA enable success, return login page" msgstr "多因子认证启用成功,返回到登录页面" -#: users/views/profile/otp.py:193 +#: users/views/profile/otp.py:148 msgid "MFA disable success" msgstr "多因子认证禁用成功" -#: users/views/profile/otp.py:194 +#: users/views/profile/otp.py:149 msgid "MFA disable success, return login page" msgstr "多因子认证禁用成功,返回登录页面" -#: users/views/profile/password.py:43 +#: users/views/profile/password.py:41 msgid "Password update" msgstr "密码更新" -#: users/views/profile/password.py:74 +#: users/views/profile/password.py:72 msgid "Password invalid" msgstr "用户名或密码无效"