From 20fde747440f4d7d421486cad552fe3cf5f9faa6 Mon Sep 17 00:00:00 2001 From: Ranjiwei <32759763+r350178982@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:33:21 +0800 Subject: [PATCH] update-dir-file-path-validation (#6958) * update-dir-file-path-validation * Update utils.js --- .../components/dialog/create-file-dialog.js | 10 ++++-- .../components/dialog/create-folder-dialog.js | 10 ++++-- frontend/src/utils/utils.js | 31 +++++++++++++++++++ seahub/api2/views.py | 10 ++++-- seahub/utils/__init__.py | 5 ++- 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/dialog/create-file-dialog.js b/frontend/src/components/dialog/create-file-dialog.js index ed568601ba..21aba71260 100644 --- a/frontend/src/components/dialog/create-file-dialog.js +++ b/frontend/src/components/dialog/create-file-dialog.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap'; import { gettext } from '../../utils/constants'; -import { Utils } from '../../utils/utils'; +import { Utils, validateName } from '../../utils/utils'; const propTypes = { fileType: PropTypes.string, @@ -54,9 +54,13 @@ class CreateFile extends React.Component { if (!this.state.isSubmitBtnActive) { return; } - let isDuplicated = this.checkDuplicatedName(); - let newName = this.state.childName; + let newName = this.state.childName.trim(); + let { isValid, errMessage } = validateName(newName); + if (!isValid) { + this.setState({ errMessage }); + return; + } if (isDuplicated) { let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.'); diff --git a/frontend/src/components/dialog/create-folder-dialog.js b/frontend/src/components/dialog/create-folder-dialog.js index c9c1f64526..e138f1109b 100644 --- a/frontend/src/components/dialog/create-folder-dialog.js +++ b/frontend/src/components/dialog/create-folder-dialog.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap'; import { gettext } from '../../utils/constants'; -import { Utils } from '../../utils/utils'; +import { Utils, validateName } from '../../utils/utils'; const propTypes = { fileType: PropTypes.string, @@ -46,9 +46,13 @@ class CreateForder extends React.Component { if (!this.state.isSubmitBtnActive) { return; } - - let newName = this.state.childName; let isDuplicated = this.checkDuplicatedName(); + let newName = this.state.childName.trim(); + let { isValid, errMessage } = validateName(newName); + if (!isValid) { + this.setState({ errMessage }); + return; + } if (isDuplicated) { let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.'); diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index acad5fad6a..7d28667a94 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -1636,3 +1636,34 @@ export const Utils = { }; export const isMobile = (typeof (window) !== 'undefined') && (window.innerWidth < 768 || navigator.userAgent.toLowerCase().match(/(ipod|ipad|iphone|android|coolpad|mmp|smartphone|midp|wap|xoom|symbian|j2me|blackberry|wince)/i) != null); + +export const validateName = (newName) => { + let isValid = true; + let errMessage = ''; + if (!newName || !newName.trim()) { + isValid = false; + errMessage = gettext('Name is required'); + return { isValid, errMessage }; + } + if (newName.includes('/')) { + isValid = false; + errMessage = gettext('Name cannot contain slash'); + return { isValid, errMessage }; + } + if (newName.includes('`')) { + isValid = false; + errMessage = gettext('Name cannot contain backtick'); + return { isValid, errMessage }; + } + if (newName.includes('\\')) { + isValid = false; + errMessage = gettext('Name cannot contain backslash'); + return { isValid, errMessage }; + } + if (newName === '..') { + isValid = false; + errMessage = gettext('Name cannot be double dots'); + return { isValid, errMessage }; + } + return { isValid, errMessage }; +}; diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 3862a5c2c8..590c73f0b6 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -2949,7 +2949,7 @@ class FileView(APIView): if len(newname) > settings.MAX_UPLOAD_FILE_NAME_LEN: return api_error(status.HTTP_400_BAD_REQUEST, 'New name is too long') - if not seafile_api.is_valid_filename('fake_repo_id', newname): + if not is_valid_dirent_name(newname): error_msg = 'File name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) @@ -3091,7 +3091,7 @@ class FileView(APIView): new_file_name = os.path.basename(path) - if not seafile_api.is_valid_filename('fake_repo_id', new_file_name): + if not is_valid_dirent_name(new_file_name): error_msg = 'File name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) @@ -3701,7 +3701,7 @@ class DirView(APIView): if operation.lower() == 'mkdir': new_dir_name = os.path.basename(path) - if not seafile_api.is_valid_filename('fake_repo_id', new_dir_name): + if not is_valid_dirent_name(new_dir_name): error_msg = 'Folder name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) @@ -3771,6 +3771,10 @@ class DirView(APIView): if newname == old_dir_name: return Response('success', status=status.HTTP_200_OK) + if not is_valid_dirent_name(newname): + error_msg = 'Folder name invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + try: # rename duplicate name checked_newname = check_filename_with_rename( diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py index 6110c4fda3..bda7415220 100644 --- a/seahub/utils/__init__.py +++ b/seahub/utils/__init__.py @@ -302,7 +302,10 @@ def is_valid_dirent_name(name): # Emojis fall within the range \U0001F300 to \U0001FAD6 if 0x1F300 <= ord(character) <= 0x1FAD6: return False - + if name == '..': + return False + if '/' in name: + return False # `repo_id` parameter is not used in seafile api return seafile_api.is_valid_filename('fake_repo_id', name)