From aaebfe27e4ac9758581a779aadc6fac42aaeec23 Mon Sep 17 00:00:00 2001
From: llj
{% trans "Password:"%} {{ password }}
+{% trans "Password:"%} {{ password|escape }}
{% endif %} {% if extra_msg %} -" {{ extra_msg }} "
+" {{ extra_msg|escape }} "
{% endif %} {% endautoescape %} 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 5/7] 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) From de830a6154cd47be1e3b0a3247e718b4564865a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AC=A2=E4=B9=90=E9=A9=AC?= <38058090+SkywalkerSpace@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:25:28 +0800 Subject: [PATCH 6/7] USE_LDAP_SYNC_ONLY (#6977) --- seahub/api2/serializers.py | 4 ++-- seahub/auth/forms.py | 2 +- seahub/settings.py | 1 + seahub/views/sysadmin.py | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/seahub/api2/serializers.py b/seahub/api2/serializers.py index a729b0e7d2..024698d5d8 100644 --- a/seahub/api2/serializers.py +++ b/seahub/api2/serializers.py @@ -14,7 +14,7 @@ from seahub.two_factor.models import default_device from seahub.two_factor.views.login import is_device_remembered from seahub.utils.two_factor_auth import has_two_factor_auth, \ two_factor_auth_enabled, verify_two_factor_token -from seahub.settings import ENABLE_LDAP +from seahub.settings import ENABLE_LDAP, USE_LDAP_SYNC_ONLY from constance import config logger = logging.getLogger(__name__) @@ -92,7 +92,7 @@ class AuthTokenSerializer(serializers.Serializer): # convert login id or contact email to username if any user = authenticate(username=username, password=password) # After local user authentication process is completed, authenticate LDAP user - if user is None and ENABLE_LDAP: + if user is None and ENABLE_LDAP and not USE_LDAP_SYNC_ONLY: user = authenticate(ldap_user=username, password=password) if user is None: diff --git a/seahub/auth/forms.py b/seahub/auth/forms.py index 91608226b4..99d51526d6 100644 --- a/seahub/auth/forms.py +++ b/seahub/auth/forms.py @@ -71,7 +71,7 @@ class AuthenticationForm(forms.Form): username = Profile.objects.convert_login_str_to_username(username) self.user_cache = authenticate(username=username, password=password) # After local user authentication process is completed, authenticate LDAP user - if self.user_cache is None and settings.ENABLE_LDAP: + if self.user_cache is None and settings.ENABLE_LDAP and not settings.USE_LDAP_SYNC_ONLY: self.user_cache = authenticate(ldap_user=username, password=password) if self.user_cache is None: diff --git a/seahub/settings.py b/seahub/settings.py index 61235f06dc..1b3e9a0fa5 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -335,6 +335,7 @@ LDAP_USER_ROLE_ATTR = '' ACTIVATE_USER_WHEN_IMPORT = True SSO_LDAP_USE_SAME_UID = False +USE_LDAP_SYNC_ONLY = False # enable ldap sasl auth ENABLE_SASL = False diff --git a/seahub/views/sysadmin.py b/seahub/views/sysadmin.py index 8ba0a965f5..ea17c00e4f 100644 --- a/seahub/views/sysadmin.py +++ b/seahub/views/sysadmin.py @@ -816,7 +816,7 @@ def sys_sudo_mode(request): if password: user = authenticate(username=username, password=password) # After local user authentication process is completed, authenticate LDAP user - if user is None and settings.ENABLE_LDAP: + if user is None and settings.ENABLE_LDAP and not settings.USE_LDAP_SYNC_ONLY: user = authenticate(ldap_user=username, password=password) if user: update_sudo_mode_ts(request) From c33f4a772f1501debab61fa45bb205180a28a63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AC=A2=E4=B9=90=E9=A9=AC?= <38058090+SkywalkerSpace@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:22:50 +0800 Subject: [PATCH 7/7] fix admin social_auth_user (#6984) --- seahub/api2/endpoints/admin/users.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/seahub/api2/endpoints/admin/users.py b/seahub/api2/endpoints/admin/users.py index 94782723f8..be10482bcb 100644 --- a/seahub/api2/endpoints/admin/users.py +++ b/seahub/api2/endpoints/admin/users.py @@ -729,6 +729,12 @@ class AdminUsers(APIView): data = [] email_list = [user.email for user in users] social_auth_user_queryset = SocialAuthUser.objects.filter(username__in=email_list) + social_auth_user_dict = {} + for item in social_auth_user_queryset: + if item.username in social_auth_user_dict: + social_auth_user_dict[item.username].append(item) + else: + social_auth_user_dict[item.username] = [item] for user in users: profile = Profile.objects.get_profile_by_user(user.email) @@ -778,7 +784,7 @@ class AdminUsers(APIView): else: info['institution'] = '' - social_auth_user = social_auth_user_queryset.filter(username=user.email) + social_auth_user = social_auth_user_dict.get(user.email, []) info['social_auth'] = [{'provider': item.provider, 'uid': item.uid} for item in social_auth_user] data.append(info)