diff --git a/frontend/src/components/dialog/update-webdav-password.js b/frontend/src/components/dialog/update-webdav-password.js index edaa3289d6..be12939565 100644 --- a/frontend/src/components/dialog/update-webdav-password.js +++ b/frontend/src/components/dialog/update-webdav-password.js @@ -1,7 +1,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Input, InputGroup, InputGroupAddon } from 'reactstrap'; +import { Modal, ModalHeader, ModalBody, ModalFooter, Alert, Button, Input, InputGroup, InputGroupAddon } from 'reactstrap'; import { gettext } from '../../utils/constants'; +import { Utils } from '../../utils/utils'; +const { webdavSecretMinLength, webdavSecretStrengthLevel } = window.app.pageOptions; const propTypes = { password: PropTypes.string.isRequired, @@ -14,6 +16,7 @@ class UpdateWebdavPassword extends Component { constructor(props) { super(props); this.state = { + errorInfo: '', password: this.props.password, isPasswordVisible: false, btnDisabled: false @@ -21,9 +24,25 @@ class UpdateWebdavPassword extends Component { } submit = () => { + + if (this.state.password.length === 0) { + this.setState({errorInfo: 'Please enter password'}); + return false; + } + if (this.state.password.length < webdavSecretMinLength) { + this.setState({errorInfo: 'Password is too short'}); + return false; + } + + if (Utils.getStrengthLevel(this.state.password) < webdavSecretStrengthLevel) { + this.setState({errorInfo: gettext('Password is too weak, should have at least {webdavSecretStrengthLevel} of the following: num, upper letter, lower letter and other symbols'.replace('{webdavSecretStrengthLevel}', webdavSecretStrengthLevel))}); + return false; + } + this.setState({ btnDisabled: true }); + this.props.updatePassword(this.state.password); } @@ -39,11 +58,7 @@ class UpdateWebdavPassword extends Component { } generatePassword = () => { - let randomPassword = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 8; i++) { - randomPassword += possible.charAt(Math.floor(Math.random() * possible.length)); - } + let randomPassword = Utils.generatePassword(webdavSecretMinLength); this.setState({ password: randomPassword, isPasswordVisible: true @@ -52,9 +67,13 @@ class UpdateWebdavPassword extends Component { render() { const { toggle } = this.props; + let passwordLengthTip = gettext('(at least {passwordLength} characters and has {shareLinkPasswordStrengthLevel} of the following: num, upper letter, lower letter and other symbols)'); + passwordLengthTip = passwordLengthTip.replace('{passwordLength}', webdavSecretMinLength) + .replace('{shareLinkPasswordStrengthLevel}', webdavSecretStrengthLevel); return ( {gettext('WebDav Password')} + {passwordLengthTip} @@ -65,6 +84,7 @@ class UpdateWebdavPassword extends Component { + {this.state.errorInfo && {gettext(this.state.errorInfo)}} diff --git a/frontend/src/components/user-settings/webdav-password.js b/frontend/src/components/user-settings/webdav-password.js index a8c2983e73..92667e5690 100644 --- a/frontend/src/components/user-settings/webdav-password.js +++ b/frontend/src/components/user-settings/webdav-password.js @@ -6,7 +6,7 @@ import { Utils } from '../../utils/utils'; import toaster from '../toast'; import UpdateWebdavPassword from '../dialog/update-webdav-password'; -const { webdavPasswd } = window.app.pageOptions; +const { webdavPasswd, webdavSecretMinLength, webdavSecretStrengthLevel} = window.app.pageOptions; class WebdavPassword extends React.Component { diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index 277d54f378..354a07198e 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -1327,7 +1327,7 @@ export const Utils = { // 91~96:[~` // 97~122:a~z // 123~127:{~ - for (var i = 0; i <= length-4; i++) { + for (var i = 0; i < length-4; i++) { var num = Math.floor((Math.random() * (127-33)) + 33); password += String.fromCharCode(num); } diff --git a/seahub/api2/endpoints/webdav_secret.py b/seahub/api2/endpoints/webdav_secret.py index 1888966096..5d49e5189f 100644 --- a/seahub/api2/endpoints/webdav_secret.py +++ b/seahub/api2/endpoints/webdav_secret.py @@ -14,6 +14,7 @@ from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error from seahub.options.models import UserOptions from seahub.utils.hasher import AESPasswordHasher +from seahub.utils import get_password_strength_level # Get an instance of a logger logger = logging.getLogger(__name__) @@ -37,6 +38,7 @@ class WebdavSecretView(APIView): }) def put(self, request, format=None): + if not settings.ENABLE_WEBDAV_SECRET: return api_error(status.HTTP_403_FORBIDDEN, 'Feature is not enabled.') @@ -45,11 +47,20 @@ class WebdavSecretView(APIView): username = request.user.username secret = request.data.get("secret", None) - if len(secret) >= 30: - return api_error(status.HTTP_400_BAD_REQUEST, - _("Length of WebDav password should be less than 30.")) if secret: + if len(secret) >= 30: + error_msg = _('Length of WebDav password should be less than 30.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if len(secret) < settings.WEBDAV_SECRET_MIN_LENGTH: + error_msg = _('Password is too short.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if get_password_strength_level(secret) < settings.WEBDAV_SECRET_STRENGTH_LEVEL: + error_msg = _('Password is too weak.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + encoded = aes.encode(secret) UserOptions.objects.set_webdav_secret(username, encoded) else: diff --git a/seahub/profile/templates/profile/set_profile_react.html b/seahub/profile/templates/profile/set_profile_react.html index 5a054dfc79..3a3bc8eac4 100644 --- a/seahub/profile/templates/profile/set_profile_react.html +++ b/seahub/profile/templates/profile/set_profile_react.html @@ -27,6 +27,8 @@ window.app.pageOptions = { enableGetAuthToken: {% if ENABLE_GET_AUTH_TOKEN_BY_SESSION %} true {% else %} false {% endif %}, enableWebdavSecret: {% if ENABLE_WEBDAV_SECRET %} true {% else %} false {% endif %}, + webdavSecretMinLength: {{ WEBDAV_SECRET_MIN_LENGTH }}, + webdavSecretStrengthLevel: {{ WEBDAV_SECRET_STRENGTH_LEVEL }}, {% if ENABLE_WEBDAV_SECRET %} webdavPasswd: '{{ webdav_passwd|escapejs }}', {% endif %} diff --git a/seahub/profile/views.py b/seahub/profile/views.py index f2bcc73a8a..bde1728546 100644 --- a/seahub/profile/views.py +++ b/seahub/profile/views.py @@ -26,6 +26,7 @@ from seahub.work_weixin.utils import work_weixin_oauth_check from seahub.settings import ENABLE_DELETE_ACCOUNT, ENABLE_UPDATE_USER_INFO from seahub.dingtalk.settings import ENABLE_DINGTALK + @login_required def edit_profile(request): """ @@ -122,6 +123,8 @@ def edit_profile(request): 'ENABLE_CHANGE_PASSWORD': settings.ENABLE_CHANGE_PASSWORD, 'ENABLE_GET_AUTH_TOKEN_BY_SESSION': settings.ENABLE_GET_AUTH_TOKEN_BY_SESSION, 'ENABLE_WEBDAV_SECRET': settings.ENABLE_WEBDAV_SECRET, + 'WEBDAV_SECRET_MIN_LENGTH': settings.WEBDAV_SECRET_MIN_LENGTH, + 'WEBDAV_SECRET_STRENGTH_LEVEL': settings.WEBDAV_SECRET_STRENGTH_LEVEL, 'ENABLE_DELETE_ACCOUNT': ENABLE_DELETE_ACCOUNT, 'ENABLE_UPDATE_USER_INFO': ENABLE_UPDATE_USER_INFO, 'webdav_passwd': webdav_passwd, @@ -148,10 +151,11 @@ def edit_profile(request): resp_dict['default_device'] = default_device(request.user) resp_dict['backup_tokens'] = backup_tokens - #template = 'profile/set_profile.html' + # template = 'profile/set_profile.html' template = 'profile/set_profile_react.html' return render(request, template, resp_dict) + @login_required def user_profile(request, username): if is_valid_username(username): @@ -179,6 +183,7 @@ def user_profile(request, username): 'd_profile': d_profile, }) + @login_required def get_user_profile(request, user): data = { @@ -213,6 +218,7 @@ def get_user_profile(request, user): return HttpResponse(json.dumps(data), content_type=content_type) + @login_required def delete_user_account(request): if not ENABLE_DELETE_ACCOUNT: @@ -239,6 +245,7 @@ def delete_user_account(request): return HttpResponseRedirect(settings.LOGIN_URL) + @login_required def default_repo(request): """Handle post request to create default repo for user. diff --git a/seahub/settings.py b/seahub/settings.py index e4f045b3b8..795ebcd46a 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -721,6 +721,9 @@ THUMBNAIL_VIDEO_FRAME_TIME = 5 # use the frame at 5 second as thumbnail OFFICE_TEMPLATE_ROOT = os.path.join(MEDIA_ROOT, 'office-template') ENABLE_WEBDAV_SECRET = False +WEBDAV_SECRET_MIN_LENGTH = 1 +WEBDAV_SECRET_STRENGTH_LEVEL = 1 + ENABLE_USER_SET_CONTACT_EMAIL = False #####################