diff --git a/frontend/src/components/dialog/generate-share-link.js b/frontend/src/components/dialog/generate-share-link.js index 0cde7f8f29..80584bca74 100644 --- a/frontend/src/components/dialog/generate-share-link.js +++ b/frontend/src/components/dialog/generate-share-link.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import moment from 'moment'; import copy from 'copy-to-clipboard'; import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, Alert, FormText } from 'reactstrap'; -import { isPro, gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants'; +import { isPro, gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkForceUsePassword, shareLinkPasswordMinLength, shareLinkPasswordStrengthLevel, canSendShareLinkEmail } from '../../utils/constants'; import ShareLinkPermissionEditor from '../../components/select-editor/share-link-permission-editor'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; @@ -47,7 +47,7 @@ class GenerateShareLink extends React.Component { this.state = { isOpIconShown: false, isValidate: false, - isShowPasswordInput: false, + isShowPasswordInput: shareLinkForceUsePassword ? true : false, isPasswordVisible: false, isExpireChecked: !this.isExpireDaysNoLimit, setExp: 'by-days', @@ -232,8 +232,8 @@ class GenerateShareLink extends React.Component { seafileAPI.deleteShareLink(sharedLinkInfo.token).then(() => { this.setState({ password: '', - passwordnew: '', - isShowPasswordInput: false, + passwdnew: '', + isShowPasswordInput: shareLinkForceUsePassword ? true : false, expireDays: this.defaultExpireDays, isExpireChecked: !this.isExpireDaysNoLimit, errorInfo: '', @@ -272,6 +272,10 @@ class GenerateShareLink extends React.Component { this.setState({errorInfo: 'Passwords don\'t match'}); return false; } + if (Utils.getStrengthLevel(password) < shareLinkPasswordStrengthLevel) { + this.setState({errorInfo: gettext('Password is too weak, should have at least {shareLinkPasswordStrengthLevel} of the following: num, upper letter, lower letter and other symbols'.replace('{shareLinkPasswordStrengthLevel}', shareLinkPasswordStrengthLevel))}); + return false; + } } if (isExpireChecked) { @@ -359,8 +363,9 @@ class GenerateShareLink extends React.Component { return ; } - let passwordLengthTip = gettext('(at least {passwordLength} characters)'); - passwordLengthTip = passwordLengthTip.replace('{passwordLength}', shareLinkPasswordMinLength); + 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}', shareLinkPasswordMinLength) + .replace('{shareLinkPasswordStrengthLevel}', shareLinkPasswordStrengthLevel); if (this.state.sharedLinkInfo) { let sharedLinkInfo = this.state.sharedLinkInfo; @@ -442,10 +447,17 @@ class GenerateShareLink extends React.Component { return (
+ {shareLinkForceUsePassword ? ( + + ) : ( + )} {this.state.isShowPasswordInput &&
diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js index 50da663a97..4d75783ff3 100644 --- a/frontend/src/components/dialog/generate-upload-link.js +++ b/frontend/src/components/dialog/generate-upload-link.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import copy from 'copy-to-clipboard'; import moment from 'moment'; import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, Alert, FormText } from 'reactstrap'; -import { gettext, shareLinkPasswordMinLength, canSendShareLinkEmail, uploadLinkExpireDaysMin, uploadLinkExpireDaysMax, uploadLinkExpireDaysDefault } from '../../utils/constants'; +import { gettext, shareLinkForceUsePassword, shareLinkPasswordMinLength, shareLinkPasswordStrengthLevel, canSendShareLinkEmail, uploadLinkExpireDaysMin, uploadLinkExpireDaysMax, uploadLinkExpireDaysDefault } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; import UploadLink from '../../models/upload-link'; @@ -42,10 +42,10 @@ class GenerateUploadLink extends React.Component { this.expirationLimitTip = expirationLimitTip; this.state = { - showPasswordInput: false, + showPasswordInput: shareLinkForceUsePassword ? true : false, passwordVisible: false, password: '', - passwdnew: '', + passwordnew: '', sharedUploadInfo: null, isSendLinkShown: false, isExpireChecked: !this.isExpireDaysNoLimit, @@ -80,7 +80,7 @@ class GenerateUploadLink extends React.Component { this.setState({ showPasswordInput: !this.state.showPasswordInput, password: '', - passwdnew: '', + passwordnew: '', errorInfo: '' }); } @@ -155,6 +155,10 @@ class GenerateUploadLink extends React.Component { this.setState({errorInfo: gettext('Passwords don\'t match')}); return false; } + if (Utils.getStrengthLevel(password) < shareLinkPasswordStrengthLevel) { + this.setState({errorInfo: gettext('Password is too weak, should have at least {shareLinkPasswordStrengthLevel} of the following: num, upper letter, lower letter and other symbols'.replace('{shareLinkPasswordStrengthLevel}', shareLinkPasswordStrengthLevel))}); + return false; + } } if (isExpireChecked) { @@ -233,7 +237,7 @@ class GenerateUploadLink extends React.Component { let sharedUploadInfo = this.state.sharedUploadInfo; seafileAPI.deleteUploadLink(sharedUploadInfo.token).then(() => { this.setState({ - showPasswordInput: false, + showPasswordInput: shareLinkForceUsePassword ? true : false, expireDays: this.defaultExpireDays, isExpireChecked: !this.isExpireDaysNoLimit, password: '', @@ -256,8 +260,10 @@ class GenerateUploadLink extends React.Component { const { isSendLinkShown } = this.state; - let passwordLengthTip = gettext('(at least {passwordLength} characters)'); - passwordLengthTip = passwordLengthTip.replace('{passwordLength}', shareLinkPasswordMinLength); + 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}', shareLinkPasswordMinLength) + .replace('{shareLinkPasswordStrengthLevel}', shareLinkPasswordStrengthLevel); + if (this.state.sharedUploadInfo) { let sharedUploadInfo = this.state.sharedUploadInfo; return ( @@ -297,8 +303,17 @@ class GenerateUploadLink extends React.Component { {this.state.showPasswordInput &&
diff --git a/frontend/src/components/dir-view-mode/dir-column-view.js b/frontend/src/components/dir-view-mode/dir-column-view.js index 4ea3fb154e..8a5ef81992 100644 --- a/frontend/src/components/dir-view-mode/dir-column-view.js +++ b/frontend/src/components/dir-view-mode/dir-column-view.js @@ -205,6 +205,7 @@ class DirColumnView extends React.Component { updateUsedRepoTags={this.props.updateUsedRepoTags} isDirentListLoading={this.props.isDirentListLoading} direntList={this.props.direntList} + fullDirentList={this.props.fullDirentList} sortBy={this.props.sortBy} sortOrder={this.props.sortOrder} sortItems={this.props.sortItems} diff --git a/frontend/src/components/system-notification.js b/frontend/src/components/system-notification.js index 71d6b1f755..fbdac0725c 100644 --- a/frontend/src/components/system-notification.js +++ b/frontend/src/components/system-notification.js @@ -42,7 +42,7 @@ class SystemNotification extends React.Component { return (
-

{curNoteMsg}

+

); diff --git a/frontend/src/pages/lib-content-view/lib-content-container.js b/frontend/src/pages/lib-content-view/lib-content-container.js index 4bcf2bdf21..6e7709c187 100644 --- a/frontend/src/pages/lib-content-view/lib-content-container.js +++ b/frontend/src/pages/lib-content-view/lib-content-container.js @@ -310,6 +310,7 @@ class LibContentContainer extends React.Component { updateUsedRepoTags={this.props.updateUsedRepoTags} isDirentListLoading={this.props.isDirentListLoading} direntList={this.props.direntList} + fullDirentList={this.props.fullDirentList} sortBy={this.props.sortBy} sortOrder={this.props.sortOrder} sortItems={this.props.sortItems} diff --git a/frontend/src/pages/sys-admin/web-settings/web-settings.js b/frontend/src/pages/sys-admin/web-settings/web-settings.js index 09e2bc1c9d..053f5102f4 100644 --- a/frontend/src/pages/sys-admin/web-settings/web-settings.js +++ b/frontend/src/pages/sys-admin/web-settings/web-settings.js @@ -299,12 +299,26 @@ class WebSettings extends Component { value={config_dict['REPO_PASSWORD_MIN_LENGTH']} helpTip={gettext('The least number of characters an encrypted library password should include.')} /> + + = 48 && n <= 57) // nums + return 1; + if (n >= 65 && n <= 90) // uppers + return 2; + if (n >= 97 && n <= 122) // lowers + return 4; + else + return 8; + }, + + calculateBitwise: function(num) { + var level = 0; + for (var i = 0; i < 4; i++){ + // bitwise AND + if (num&1) level++; + // Right logical shift + num>>>=1; + } + return level; + }, }; diff --git a/seahub/api2/endpoints/admin/users_batch.py b/seahub/api2/endpoints/admin/users_batch.py index 75a99f7d0f..590c77b686 100644 --- a/seahub/api2/endpoints/admin/users_batch.py +++ b/seahub/api2/endpoints/admin/users_batch.py @@ -290,7 +290,8 @@ class AdminImportUsers(APIView): # skip first row(head field). next(rows) for row in rows: - records.append([col.value for col in row]) + if not all(col.value is None for col in row): + records.append([col.value for col in row]) if user_number_over_limit(new_users=len(records)): error_msg = 'The number of users exceeds the limit.' diff --git a/seahub/api2/endpoints/admin/web_settings.py b/seahub/api2/endpoints/admin/web_settings.py index df5883875d..c3da1e8ac4 100644 --- a/seahub/api2/endpoints/admin/web_settings.py +++ b/seahub/api2/endpoints/admin/web_settings.py @@ -4,7 +4,6 @@ import logging from constance import config from django.conf import settings as dj_settings -from django.utils.translation import ugettext as _ from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAdminUser @@ -25,6 +24,7 @@ DIGIT_WEB_SETTINGS = [ 'ENABLE_REPO_HISTORY_SETTING', 'USER_STRONG_PASSWORD_REQUIRED', 'ENABLE_ENCRYPTED_LIBRARY', 'USER_PASSWORD_MIN_LENGTH', 'USER_PASSWORD_STRENGTH_LEVEL', 'SHARE_LINK_PASSWORD_MIN_LENGTH', + 'SHARE_LINK_FORCE_USE_PASSWORD', 'SHARE_LINK_PASSWORD_STRENGTH_LEVEL', 'ENABLE_USER_CREATE_ORG_REPO', 'FORCE_PASSWORD_CHANGE', 'LOGIN_ATTEMPT_LIMIT', 'FREEZE_USER_ON_LOGIN_FAILED', 'ENABLE_SHARE_TO_ALL_GROUPS', 'ENABLE_TWO_FACTOR_AUTH', @@ -87,6 +87,10 @@ class AdminWebSettings(APIView): error_msg = 'value invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + if key == 'SHARE_LINK_PASSWORD_STRENGTH_LEVEL' and value not in (1, 2, 3, 4): + error_msg = 'value invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + if (key in STRING_WEB_SETTINGS and key != 'CUSTOM_CSS') and not value: error_msg = 'value invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) diff --git a/seahub/api2/endpoints/share_links.py b/seahub/api2/endpoints/share_links.py index ca14c52ac6..c7d4f2d9d4 100644 --- a/seahub/api2/endpoints/share_links.py +++ b/seahub/api2/endpoints/share_links.py @@ -32,7 +32,7 @@ from seahub.constants import PERMISSION_READ_WRITE, PERMISSION_READ, \ from seahub.share.models import FileShare, UploadLinkShare, check_share_link_access from seahub.utils import gen_shared_link, is_org_context, normalize_file_path, \ normalize_dir_path, is_pro_version, get_file_type_and_ext, \ - check_filename_with_rename, gen_file_upload_url + check_filename_with_rename, gen_file_upload_url, get_password_strength_level from seahub.utils.file_op import if_locked_by_online_office from seahub.utils.file_types import IMAGE, VIDEO, XMIND from seahub.utils.timeutils import datetime_to_isoformat_timestr, \ @@ -263,10 +263,21 @@ class ShareLinks(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get('password', None) - if password and len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: - error_msg = _('Password is too short.') + + if config.SHARE_LINK_FORCE_USE_PASSWORD and not password: + error_msg = _('Password is required.') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + if password: + + if len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: + error_msg = _('Password is too short.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if get_password_strength_level(password) < config.SHARE_LINK_PASSWORD_STRENGTH_LEVEL: + error_msg = _('Password is too weak.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + expire_days = request.data.get('expire_days', '') expiration_time = request.data.get('expiration_time', '') if expire_days and expiration_time: diff --git a/seahub/api2/endpoints/upload_links.py b/seahub/api2/endpoints/upload_links.py index 185fc30597..4357246a00 100644 --- a/seahub/api2/endpoints/upload_links.py +++ b/seahub/api2/endpoints/upload_links.py @@ -26,7 +26,7 @@ from seahub.api2.permissions import CanGenerateUploadLink from seahub.share.models import UploadLinkShare, check_share_link_common from seahub.utils import gen_shared_upload_link, gen_file_upload_url, \ - is_pro_version + is_pro_version, get_password_strength_level from seahub.views import check_folder_permission from seahub.utils.timeutils import datetime_to_isoformat_timestr @@ -157,10 +157,21 @@ class UploadLinks(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get('password', None) - if password and len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: - error_msg = _('Password is too short') + + if config.SHARE_LINK_FORCE_USE_PASSWORD and not password: + error_msg = _('Password is required.') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + if password: + + if len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: + error_msg = _('Password is too short.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if get_password_strength_level(password) < config.SHARE_LINK_PASSWORD_STRENGTH_LEVEL: + error_msg = _('Password is too weak.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + expire_days = request.data.get('expire_days', '') expiration_time = request.data.get('expiration_time', '') if expire_days and expiration_time: diff --git a/seahub/api2/views.py b/seahub/api2/views.py index b1515f737a..c380857da6 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -3996,7 +3996,7 @@ class SharedFileDetailView(APIView): password = request.GET.get('password', '') if not password: - return api_error(status.HTTP_403_FORBIDDEN, "Password is required") + return api_error(status.HTTP_403_FORBIDDEN, _('Password is required.')) if not check_password(password, fileshare.password): return api_error(status.HTTP_403_FORBIDDEN, "Invalid Password") @@ -4116,7 +4116,7 @@ class SharedDirView(APIView): password = request.GET.get('password', '') if not password: - return api_error(status.HTTP_403_FORBIDDEN, "Password is required") + return api_error(status.HTTP_403_FORBIDDEN, _('Password is required.')) if not check_password(password, fileshare.password): return api_error(status.HTTP_403_FORBIDDEN, "Invalid Password") diff --git a/seahub/auth/views.py b/seahub/auth/views.py index 72976231c6..d946b60be6 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -203,6 +203,7 @@ def login(request, template_name='registration/login.html', 'signup_url': signup_url, 'enable_sso': enable_sso, 'login_bg_image_path': login_bg_image_path, + 'enable_change_password': settings.ENABLE_CHANGE_PASSWORD, }) def login_simple_check(request): diff --git a/seahub/base/context_processors.py b/seahub/base/context_processors.py index 90e010ee8f..d4a72250d9 100644 --- a/seahub/base/context_processors.py +++ b/seahub/base/context_processors.py @@ -17,7 +17,7 @@ from constance import config import seaserv -from seahub.settings import SEAFILE_VERSION, SITE_TITLE, SITE_NAME, \ +from seahub.settings import SEAFILE_VERSION, \ MAX_FILE_NAME, LOGO_PATH, BRANDING_CSS, LOGO_WIDTH, LOGO_HEIGHT,\ SHOW_REPO_DOWNLOAD_BUTTON, SITE_ROOT, ENABLE_GUEST_INVITATION, \ FAVICON_PATH, THUMBNAIL_SIZE_FOR_ORIGINAL, \ @@ -123,7 +123,9 @@ def base(request): 'max_file_name': MAX_FILE_NAME, 'has_file_search': HAS_FILE_SEARCH, 'show_repo_download_button': SHOW_REPO_DOWNLOAD_BUTTON, + 'share_link_force_use_password': config.SHARE_LINK_FORCE_USE_PASSWORD, 'share_link_password_min_length': config.SHARE_LINK_PASSWORD_MIN_LENGTH, + 'share_link_password_strength_level': config.SHARE_LINK_PASSWORD_STRENGTH_LEVEL, 'repo_password_min_length': config.REPO_PASSWORD_MIN_LENGTH, 'events_enabled': EVENTS_ENABLED, 'sysadmin_extra_enabled': ENABLE_SYSADMIN_EXTRA, diff --git a/seahub/settings.py b/seahub/settings.py index b12f8446e1..c6771fd9d5 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -353,8 +353,17 @@ UPLOAD_LINK_EXPIRE_DAYS_MAX = 0 # 0 means no limit # greater than or equal to MIN and less than or equal to MAX UPLOAD_LINK_EXPIRE_DAYS_DEFAULT = 0 -# mininum length for the password of a share link -SHARE_LINK_PASSWORD_MIN_LENGTH = 8 +# force use password when generate a share/upload link +SHARE_LINK_FORCE_USE_PASSWORD = False + +# mininum length for the password of a share/upload link +SHARE_LINK_PASSWORD_MIN_LENGTH = 10 + +# LEVEL for the password of a share/upload link +# based on four types of input: +# num, upper letter, lower letter, other symbols +# '3' means password must have at least 3 types of the above. +SHARE_LINK_PASSWORD_STRENGTH_LEVEL = 1 # enable or disable share link audit ENABLE_SHARE_LINK_AUDIT = False @@ -898,7 +907,9 @@ CONSTANCE_CONFIG = { 'USER_PASSWORD_STRENGTH_LEVEL': (USER_PASSWORD_STRENGTH_LEVEL, ''), 'SHARE_LINK_TOKEN_LENGTH': (SHARE_LINK_TOKEN_LENGTH, ''), + 'SHARE_LINK_FORCE_USE_PASSWORD': (SHARE_LINK_FORCE_USE_PASSWORD, ''), 'SHARE_LINK_PASSWORD_MIN_LENGTH': (SHARE_LINK_PASSWORD_MIN_LENGTH, ''), + 'SHARE_LINK_PASSWORD_STRENGTH_LEVEL': (SHARE_LINK_PASSWORD_STRENGTH_LEVEL, ''), 'ENABLE_TWO_FACTOR_AUTH': (ENABLE_TWO_FACTOR_AUTH, ''), 'TEXT_PREVIEW_EXT': (TEXT_PREVIEW_EXT, ''), diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index f7b5f170a1..824a6c1c92 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -93,7 +93,9 @@ return libraryTemplates; })(), enableRepoSnapshotLabel: {% if enable_repo_snapshot_label %} true {% else %} false {% endif %}, + shareLinkForceUsePassword: {% if share_link_force_use_password %} true {% else %} false {% endif %}, shareLinkPasswordMinLength: {{ share_link_password_min_length }}, + shareLinkPasswordStrengthLevel: {{ share_link_password_strength_level }}, sideNavFooterCustomHtml: "{{ side_nav_footer_custom_html|safe|escapejs }}", aboutDialogCustomHtml: "{{ about_dialog_custom_html|safe|escapejs }}", maxFileName: "{{ max_file_name }}", diff --git a/seahub/templates/file_view_react.html b/seahub/templates/file_view_react.html index e32d9163a6..7e2eab1329 100644 --- a/seahub/templates/file_view_react.html +++ b/seahub/templates/file_view_react.html @@ -13,7 +13,9 @@ window.app.pageOptions = { canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %}, canSendShareLinkEmail: {% if user.permissions.can_send_share_link_mail %} true {% else %} false {% endif %}, + shareLinkForceUsePassword: {% if share_link_force_use_password %} true {% else %} false {% endif %}, shareLinkPasswordMinLength: {{ share_link_password_min_length }}, + shareLinkPasswordStrengthLevel: {{ share_link_password_strength_level }}, shareLinkExpireDaysDefault: {{ share_link_expire_days_default }}, shareLinkExpireDaysMin: {{ share_link_expire_days_min }}, shareLinkExpireDaysMax: {{ share_link_expire_days_max }}, diff --git a/seahub/templates/markdown_file_view_react.html b/seahub/templates/markdown_file_view_react.html index e587a68c07..ef4b969c94 100644 --- a/seahub/templates/markdown_file_view_react.html +++ b/seahub/templates/markdown_file_view_react.html @@ -47,7 +47,9 @@ hasDraft: '{{ has_draft }}' === 'True', draftFilePath: '{{ draft_file_path }}', draftOriginFilePath: '{{ draft_origin_file_path }}', + shareLinkForceUsePassword: {% if share_link_force_use_password %} true {% else %} false {% endif %}, shareLinkPasswordMinLength: {{ share_link_password_min_length }}, + shareLinkPasswordStrengthLevel: {{ share_link_password_strength_level }}, shareLinkExpireDaysDefault: {{ share_link_expire_days_default }}, shareLinkExpireDaysMin: {{ share_link_expire_days_min }}, shareLinkExpireDaysMax: {{ share_link_expire_days_max }}, diff --git a/seahub/templates/registration/login.html b/seahub/templates/registration/login.html index 2aa2287d78..8586f61f52 100644 --- a/seahub/templates/registration/login.html +++ b/seahub/templates/registration/login.html @@ -65,7 +65,9 @@ html, body, #wrapper { height:100%; } {% blocktrans %}Remember me for {{remember_days}} days {% endblocktrans %} + {% if enable_change_password %} {% trans "Forgot password?" %} + {% endif %} diff --git a/seahub/two_factor/views/core.py b/seahub/two_factor/views/core.py index 9134b2772e..f9a90a2cfb 100644 --- a/seahub/two_factor/views/core.py +++ b/seahub/two_factor/views/core.py @@ -286,7 +286,7 @@ class QRGeneratorView(View): otpauth_url = get_otpauth_url( accountname=self.request.user.username, - issuer=get_current_site(self.request).name, + issuer=config.SITE_NAME, secret=key, digits=totp_digits()) diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py index 4bb58705fe..c0af8d917b 100644 --- a/seahub/utils/__init__.py +++ b/seahub/utils/__init__.py @@ -3,19 +3,18 @@ from functools import partial import os import re -import urllib.request, urllib.parse, urllib.error -import urllib.request, urllib.error, urllib.parse +import urllib.request +import urllib.parse +import urllib.error import uuid import logging import hashlib import tempfile -import locale import configparser import mimetypes import contextlib from datetime import datetime from urllib.parse import urlparse, urljoin -import json from constance import config import seaserv @@ -24,9 +23,9 @@ from seaserv import seafile_api from django.urls import reverse from django.core.mail import EmailMessage from django.shortcuts import render -from django.template import Context, loader +from django.template import loader from django.utils.translation import ugettext as _ -from django.http import HttpResponseRedirect, HttpResponse, HttpResponseNotModified +from django.http import HttpResponseRedirect, HttpResponse from django.utils.http import urlquote from django.utils.html import escape from django.utils.timezone import make_naive, is_aware @@ -35,7 +34,7 @@ from django.views.static import serve as django_static_serve from seahub.auth import REDIRECT_FIELD_NAME from seahub.api2.models import Token, TokenV2 import seahub.settings -from seahub.settings import SITE_NAME, MEDIA_URL, LOGO_PATH, \ +from seahub.settings import MEDIA_URL, LOGO_PATH, \ MEDIA_ROOT, CUSTOM_LOGO_PATH try: from seahub.settings import EVENTS_CONFIG_FILE @@ -1254,6 +1253,16 @@ def is_user_password_strong(password): else: return True +def get_password_strength_level(password): + + num = 0 + for letter in password: + # get ascii dec + # bitwise OR + num |= get_char_mode(ord(letter)) + + return calculate_bitwise(num) + def get_char_mode(n): """Return different num according to the type of given letter: '1': num, diff --git a/seahub/views/file.py b/seahub/views/file.py index 8fc0ad4fa1..47e5bed952 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -10,7 +10,9 @@ import json import time import uuid import stat -import urllib.request, urllib.error, urllib.parse +import urllib.request +import urllib.error +import urllib.parse import chardet import logging import posixpath @@ -45,7 +47,7 @@ from seahub.onlyoffice.utils import get_onlyoffice_dict from seahub.auth.decorators import login_required from seahub.base.decorators import repo_passwd_set_required from seahub.base.accounts import ANONYMOUS_EMAIL -from seahub.base.templatetags.seahub_tags import file_icon_filter, email2nickname +from seahub.base.templatetags.seahub_tags import file_icon_filter from seahub.share.models import FileShare, check_share_link_common from seahub.share.decorators import share_link_audit, share_link_login_required from seahub.wiki.utils import get_wiki_dirent @@ -87,6 +89,7 @@ import seahub.settings as settings from seahub.settings import FILE_ENCODING_LIST, FILE_PREVIEW_MAX_SIZE, \ FILE_ENCODING_TRY_LIST, MEDIA_URL, SEAFILE_COLLAB_SERVER, ENABLE_WATERMARK, \ SHARE_LINK_EXPIRE_DAYS_MIN, SHARE_LINK_EXPIRE_DAYS_MAX, SHARE_LINK_PASSWORD_MIN_LENGTH, \ + SHARE_LINK_FORCE_USE_PASSWORD, SHARE_LINK_PASSWORD_STRENGTH_LEVEL, \ SHARE_LINK_EXPIRE_DAYS_DEFAULT, ENABLE_SHARE_LINK_REPORT_ABUSE @@ -564,7 +567,9 @@ def view_lib_file(request, repo_id, path): 'highlight_keyword': settings.HIGHLIGHT_KEYWORD, 'enable_file_comment': settings.ENABLE_FILE_COMMENT, 'enable_watermark': ENABLE_WATERMARK, + 'share_link_force_use_password': SHARE_LINK_FORCE_USE_PASSWORD, 'share_link_password_min_length': SHARE_LINK_PASSWORD_MIN_LENGTH, + 'share_link_password_strength_level': SHARE_LINK_PASSWORD_STRENGTH_LEVEL, 'share_link_expire_days_default': SHARE_LINK_EXPIRE_DAYS_DEFAULT, 'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN, 'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX, diff --git a/tests/api/endpoints/admin/test_web_settings.py b/tests/api/endpoints/admin/test_web_settings.py index c8154639cb..81477ceee7 100644 --- a/tests/api/endpoints/admin/test_web_settings.py +++ b/tests/api/endpoints/admin/test_web_settings.py @@ -27,7 +27,7 @@ class AdminWebSettingsTest(BaseTestCase): self.assertEqual(200, resp.status_code) json_resp = json.loads(resp.content) - assert len(json_resp) == 28 + assert len(json_resp) == 30 @override_settings(ENABLE_SETTINGS_VIA_WEB = False) def test_get_with_enable_settings(self):