mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-20 19:08:21 +00:00
[passwd strength] add STRONG password check(default not enabled) when user sign-up or change-password
This commit is contained in:
@@ -7,10 +7,13 @@ from seahub.base.accounts import User
|
||||
from seahub.auth import authenticate
|
||||
from seahub.auth.tokens import default_token_generator
|
||||
from seahub.utils import IS_EMAIL_CONFIGURED, send_html_email, \
|
||||
is_valid_username, is_ldap_user
|
||||
is_valid_username, is_ldap_user, is_user_password_strong
|
||||
|
||||
from captcha.fields import CaptchaField
|
||||
|
||||
from seahub.settings import USER_STRONG_PASSWORD_REQUIRED, \
|
||||
USER_PASSWORD_STRENGTH_LEVEL, USER_PASSWORD_MIN_LENGTH
|
||||
|
||||
class AuthenticationForm(forms.Form):
|
||||
"""
|
||||
Base class for authenticating users. Extend this to get a form that accepts
|
||||
@@ -64,7 +67,7 @@ class AuthenticationForm(forms.Form):
|
||||
|
||||
class CaptchaAuthenticationForm(AuthenticationForm):
|
||||
captcha = CaptchaField()
|
||||
|
||||
|
||||
class PasswordResetForm(forms.Form):
|
||||
email = forms.EmailField(label=_("E-mail"), max_length=255)
|
||||
|
||||
@@ -74,7 +77,7 @@ class PasswordResetForm(forms.Form):
|
||||
"""
|
||||
if not IS_EMAIL_CONFIGURED:
|
||||
raise forms.ValidationError(_(u'Failed to send email, email service is not properly configured, please contact administrator.'))
|
||||
|
||||
|
||||
email = self.cleaned_data["email"].lower().strip()
|
||||
|
||||
# TODO: add filter method to UserManager
|
||||
@@ -121,9 +124,21 @@ class SetPasswordForm(forms.Form):
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
|
||||
|
||||
super(SetPasswordForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean_new_password1(self):
|
||||
if 'new_password1' in self.cleaned_data:
|
||||
pwd = self.cleaned_data['new_password1']
|
||||
|
||||
if USER_STRONG_PASSWORD_REQUIRED is True:
|
||||
if is_user_password_strong(pwd) is True:
|
||||
return pwd
|
||||
else:
|
||||
raise forms.ValidationError(_("%s characters or more, include %s types or more of these: letters(case sensitive), numbers, and symbols") % (USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL))
|
||||
else:
|
||||
return pwd
|
||||
|
||||
def clean_new_password2(self):
|
||||
password1 = self.cleaned_data.get('new_password1')
|
||||
password2 = self.cleaned_data.get('new_password2')
|
||||
|
@@ -25,6 +25,8 @@ from seahub.auth.tokens import default_token_generator
|
||||
from seahub.base.accounts import User
|
||||
from seahub.utils import is_ldap_user
|
||||
from seahub.utils.ip import get_remote_ip
|
||||
from seahub.settings import USER_PASSWORD_MIN_LENGTH, \
|
||||
USER_STRONG_PASSWORD_REQUIRED, USER_PASSWORD_STRENGTH_LEVEL
|
||||
|
||||
# Get an instance of a logger
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -35,9 +37,9 @@ def log_user_in(request, user, redirect_to):
|
||||
# Light security check -- make sure redirect_to isn't garbage.
|
||||
if not redirect_to or ' ' in redirect_to:
|
||||
redirect_to = settings.LOGIN_REDIRECT_URL
|
||||
|
||||
# Heavier security check -- redirects to http://example.com should
|
||||
# not be allowed, but things like /view/?param=http://example.com
|
||||
|
||||
# Heavier security check -- redirects to http://example.com should
|
||||
# not be allowed, but things like /view/?param=http://example.com
|
||||
# should be allowed. This regex checks if there is a '//' *before* a
|
||||
# question mark.
|
||||
elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
|
||||
@@ -103,7 +105,7 @@ def _incr_login_faied_attempts(username=None, ip=None):
|
||||
|
||||
def _clear_login_failed_attempts(request):
|
||||
"""Clear login failed attempts records.
|
||||
|
||||
|
||||
Arguments:
|
||||
- `request`:
|
||||
"""
|
||||
@@ -167,9 +169,9 @@ def login(request, template_name='registration/login.html',
|
||||
form = CaptchaAuthenticationForm(request)
|
||||
else:
|
||||
form = authentication_form(request)
|
||||
|
||||
|
||||
request.session.set_test_cookie()
|
||||
|
||||
|
||||
if Site._meta.installed:
|
||||
current_site = Site.objects.get_current()
|
||||
else:
|
||||
@@ -213,7 +215,7 @@ def login_simple_check(request):
|
||||
user = User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
|
||||
for backend in get_backends():
|
||||
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
|
||||
|
||||
@@ -223,7 +225,7 @@ def login_simple_check(request):
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
|
||||
|
||||
def logout(request, next_page=None, template_name='registration/logged_out.html', redirect_field_name=REDIRECT_FIELD_NAME):
|
||||
"Logs out the user and displays 'You are logged out' message."
|
||||
from seahub.auth import logout
|
||||
@@ -255,7 +257,7 @@ def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_N
|
||||
# 4 views for password reset:
|
||||
# - password_reset sends the mail
|
||||
# - password_reset_done shows a success message for the above
|
||||
# - password_reset_confirm checks the link the user clicked and
|
||||
# - password_reset_confirm checks the link the user clicked and
|
||||
# prompts for a new password
|
||||
# - password_reset_complete shows a success message for the above
|
||||
|
||||
@@ -352,8 +354,12 @@ def password_change(request, template_name='registration/password_change_form.ht
|
||||
return HttpResponseRedirect(post_change_redirect)
|
||||
else:
|
||||
form = password_change_form(user=request.user)
|
||||
|
||||
return render_to_response(template_name, {
|
||||
'form': form,
|
||||
'min_len': USER_PASSWORD_MIN_LENGTH,
|
||||
'strong_pwd_required': USER_STRONG_PASSWORD_REQUIRED,
|
||||
'level': USER_PASSWORD_STRENGTH_LEVEL,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def password_change_done(request, template_name='registration/password_change_done.html'):
|
||||
|
@@ -13,12 +13,14 @@ from registration import signals
|
||||
from seaserv import ccnet_threaded_rpc, unset_repo_passwd, is_passwd_set
|
||||
|
||||
from seahub.profile.models import Profile, DetailedProfile
|
||||
from seahub.utils import is_valid_username
|
||||
from seahub.utils import is_valid_username, is_user_password_strong
|
||||
try:
|
||||
from seahub.settings import CLOUD_MODE
|
||||
except ImportError:
|
||||
CLOUD_MODE = False
|
||||
|
||||
from seahub.settings import USER_STRONG_PASSWORD_REQUIRED, \
|
||||
USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL
|
||||
|
||||
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
||||
|
||||
@@ -463,40 +465,14 @@ class RegistrationForm(forms.Form):
|
||||
def clean_password1(self):
|
||||
if 'password1' in self.cleaned_data:
|
||||
pwd = self.cleaned_data['password1']
|
||||
if len(pwd) < 6:
|
||||
raise forms.ValidationError(
|
||||
_("Passwords must have at least 6 characters."))
|
||||
|
||||
if USER_STRONG_PASSWORD_REQUIRED is True:
|
||||
if is_user_password_strong(pwd) is True:
|
||||
return pwd
|
||||
else:
|
||||
raise forms.ValidationError(_("%s characters or more, include %s types or more of these: letters(case sensitive), numbers, and symbols") % (USER_PASSWORD_MIN_LENGTH, USER_PASSWORD_STRENGTH_LEVEL))
|
||||
else:
|
||||
num = 0
|
||||
for letter in pwd:
|
||||
# get ascii dec
|
||||
# bitwise OR
|
||||
num |= self.get_char_mode(ord(letter))
|
||||
level = self.caculate_bitwise(num)
|
||||
if level == 1:
|
||||
raise forms.ValidationError(_("Passwords must contain at least 2 types: uppercase letters, lowercase letters, numbers, and symbols"))
|
||||
|
||||
return self.cleaned_data['password1']
|
||||
|
||||
def get_char_mode(self, n):
|
||||
if (n >= 48 and n <= 57): #nums
|
||||
return 1;
|
||||
if (n >= 65 and n <= 90): #uppers
|
||||
return 2;
|
||||
if (n >= 97 and n <= 122): #lowers
|
||||
return 4;
|
||||
else:
|
||||
return 8;
|
||||
|
||||
def caculate_bitwise(self, num):
|
||||
level = 0
|
||||
for i in range(4):
|
||||
# bitwise AND
|
||||
if (num&1):
|
||||
level += 1
|
||||
# Right logical shift
|
||||
num = num >> 1
|
||||
return level
|
||||
return pwd
|
||||
|
||||
def clean_password2(self):
|
||||
"""
|
||||
|
@@ -104,10 +104,10 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'seahub.auth.middleware.AuthenticationMiddleware',
|
||||
'seahub.base.middleware.BaseMiddleware',
|
||||
'seahub.base.middleware.BaseMiddleware',
|
||||
'seahub.base.middleware.InfobarMiddleware',
|
||||
)
|
||||
|
||||
@@ -161,7 +161,7 @@ LOCALE_PATHS = (
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
'djblets.util.context_processors.siteRoot',
|
||||
'django.core.context_processors.request',
|
||||
@@ -207,6 +207,18 @@ SHOW_REPO_DOWNLOAD_BUTTON = False
|
||||
# mininum length for password of encrypted library
|
||||
REPO_PASSWORD_MIN_LENGTH = 8
|
||||
|
||||
# mininum length for user's password
|
||||
USER_PASSWORD_MIN_LENGTH = 6
|
||||
|
||||
# LEVEL 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.
|
||||
USER_PASSWORD_STRENGTH_LEVEL = 3
|
||||
|
||||
# default False, only check USER_PASSWORD_MIN_LENGTH
|
||||
# when True, check password strength level, STRONG(or above) is allowed
|
||||
USER_STRONG_PASSWORD_REQUIRED = False
|
||||
|
||||
# Using server side crypto by default, otherwise, let user choose crypto method.
|
||||
FORCE_SERVER_CRYPTO = True
|
||||
|
||||
@@ -219,7 +231,7 @@ OFFICE_PREVIEW_MAX_SIZE = 2 * 1024 * 1024
|
||||
USE_PDFJS = True
|
||||
FILE_ENCODING_LIST = ['auto', 'utf-8', 'gbk', 'ISO-8859-1', 'ISO-8859-5']
|
||||
FILE_ENCODING_TRY_LIST = ['utf-8', 'gbk']
|
||||
HIGHLIGHT_KEYWORD = False # If True, highlight the keywords in the file when the visit is via clicking a link in 'search result' page.
|
||||
HIGHLIGHT_KEYWORD = False # If True, highlight the keywords in the file when the visit is via clicking a link in 'search result' page.
|
||||
|
||||
# Common settings(file extension, storage) for avatar and group avatar.
|
||||
AVATAR_FILE_STORAGE = '' # Replace with 'seahub.base.database_storage.DatabaseStorage' if save avatar files to database
|
||||
@@ -346,7 +358,7 @@ LOGGING = {
|
||||
'filename': os.path.join(LOG_DIR, 'seahub.log'),
|
||||
'maxBytes': 1024*1024*10, # 10 MB
|
||||
'formatter':'standard',
|
||||
},
|
||||
},
|
||||
'request_handler': {
|
||||
'level':'WARN',
|
||||
'class':'logging.handlers.RotatingFileHandler',
|
||||
@@ -452,7 +464,7 @@ def load_local_settings(module):
|
||||
elif re.search('^[A-Z]', attr):
|
||||
globals()[attr] = getattr(module, attr)
|
||||
|
||||
|
||||
|
||||
# Load seahub_extra_settings.py
|
||||
try:
|
||||
from seahub_extra import seahub_extra_settings
|
||||
@@ -478,7 +490,7 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# In server release, sqlite3 db file is <topdir>/seahub.db
|
||||
# In server release, sqlite3 db file is <topdir>/seahub.db
|
||||
DATABASES['default']['NAME'] = os.path.join(install_topdir, 'seahub.db')
|
||||
if 'win32' not in sys.platform:
|
||||
# In server release, gunicorn is used to deploy seahub
|
||||
|
@@ -7,9 +7,13 @@
|
||||
<h2 class="hd">{% trans "Password Modification" %}</h2>
|
||||
<form action="" method="post" class="con">{% csrf_token %}
|
||||
<label for="id_old_password">{% trans "Current Password: " %}</label>
|
||||
{{ form.old_password }} {{ form.old_password.errors }}
|
||||
{{ form.old_password }} {{ form.old_password.errors }}
|
||||
<label for="id_new_password1">{% trans "New Password: " %}</label>
|
||||
{{ form.new_password1 }} {{ form.new_password1.errors }}
|
||||
{% if strong_pwd_required %}
|
||||
<span class="icon-question-sign" title="{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols"{% endblocktrans%}></span>
|
||||
{% endif %}
|
||||
{{ form.new_password1 }} {{ form.new_password1.errors }}
|
||||
<div id="pwd_strength"></div>
|
||||
<label for="id_new_password2">{% trans "Confirm Password: " %}</label>
|
||||
{{ form.new_password2 }} {{ form.new_password2.errors }}
|
||||
|
||||
@@ -22,6 +26,47 @@
|
||||
|
||||
{% block extra_script %}
|
||||
<script type="text/javascript">
|
||||
$('[type="password"]').addClass('input');
|
||||
$('[type="password"]').addClass('input');
|
||||
|
||||
{% include "snippets/password_strength_js.html" %}
|
||||
|
||||
$("#id_new_password1").keyup(function() {
|
||||
var pwd = $(this).val(),
|
||||
level = getStrengthLevel(pwd);
|
||||
|
||||
if (pwd.length > 0) {
|
||||
showStrength(level);
|
||||
};
|
||||
});
|
||||
|
||||
$('form').submit(function(){
|
||||
var old_pwd = $.trim($('input[name="old_password"]').val()),
|
||||
pwd1 = $.trim($('input[name="new_password1"]').val()),
|
||||
pwd2 = $.trim($('input[name="new_password2"]').val()),
|
||||
level = getStrengthLevel(pwd1);
|
||||
|
||||
if (!old_pwd) {
|
||||
$('.error').removeClass('hide').html("{% trans "Current password cannot be blank" %}");
|
||||
return false;
|
||||
}
|
||||
if (!pwd1) {
|
||||
$('.error').removeClass('hide').html("{% trans "Password cannot be blank" %}");
|
||||
return false;
|
||||
}
|
||||
if (!pwd2) {
|
||||
$('.error').removeClass('hide').html("{% trans "Please enter the password again" %}");
|
||||
return false;
|
||||
}
|
||||
if (pwd1 != pwd2) {
|
||||
$('.error').removeClass('hide').html("{% trans "Passwords don't match" %}");
|
||||
return false;
|
||||
}
|
||||
{% if strong_pwd_required %}
|
||||
if (level < {{level}}) {
|
||||
$('.error').removeClass('hide').html("{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols{% endblocktrans %}");
|
||||
return false;
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@@ -16,7 +16,10 @@
|
||||
|
||||
<label for="id_email">{% trans "Email" %}</label>
|
||||
{{ form.email }} {{ form.email.errors }}
|
||||
<label for="id_password1">{% trans "Password" %}</label> <span class="icon-question-sign" title="{% trans "6 characters or more, include 2 types or more of these: letters(case sensitive), numbers, and symbols" %}"></span>
|
||||
<label for="id_password1">{% trans "Password" %}</label>
|
||||
{% if strong_pwd_required %}
|
||||
<span class="icon-question-sign" title="{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols"{% endblocktrans%}></span>
|
||||
{% endif %}
|
||||
{{ form.password1 }} {{ form.password1.errors }}
|
||||
<div id="pwd_strength"></div>
|
||||
<label for="id_password2">{% trans "Confirm Password" %}</label>
|
||||
@@ -40,73 +43,17 @@
|
||||
|
||||
{% block extra_script %}
|
||||
<script type="text/javascript">
|
||||
|
||||
{% include "snippets/password_strength_js.html" %}
|
||||
|
||||
$("#id_password1").keyup(function() {
|
||||
var level = getStrengthLevel($(this).val());
|
||||
showStrength(level);
|
||||
});
|
||||
var pwd = $(this).val(),
|
||||
level = getStrengthLevel(pwd);
|
||||
|
||||
function getStrengthLevel(pwd) {
|
||||
var num = 0,
|
||||
min_passwd_len = 6;
|
||||
|
||||
if (pwd.length < min_passwd_len) {
|
||||
return 0;
|
||||
} else {
|
||||
for (var i = 0; i < pwd.length; i++) {
|
||||
// return the unicode
|
||||
// bitwise OR
|
||||
num |= getCharMode(pwd.charCodeAt(i));
|
||||
};
|
||||
return calculateBitwise(num);
|
||||
if (pwd.length > 0) {
|
||||
showStrength(level);
|
||||
};
|
||||
}
|
||||
|
||||
function getCharMode(n) {
|
||||
if (n >= 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;
|
||||
}
|
||||
|
||||
function calculateBitwise(num) {
|
||||
var level = 0;
|
||||
for (var i = 0; i < 4; i++){
|
||||
// bitwise AND
|
||||
if (num&1) level++;
|
||||
// Right logical shift
|
||||
num>>>=1;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
function showStrength(level) {
|
||||
var strength_ct = $("#pwd_strength");
|
||||
var strength = [
|
||||
"{% trans "too weak" %}",
|
||||
"{% trans "weak" %}",
|
||||
"{% trans "medium" %}",
|
||||
"{% trans "strong" %}"
|
||||
];
|
||||
switch (level) {
|
||||
case 0:
|
||||
strength_ct.html(strength[0]).css("color", '#F00000');
|
||||
break;
|
||||
case 1:
|
||||
strength_ct.html('<span style="background:#db4747;">' + strength[1] + '</span><span>' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||
break;
|
||||
case 2:
|
||||
strength_ct.html('<span>' + strength[1] + '</span><span style="background:#fdd64d;">' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
strength_ct.html('<span>' + strength[1] + '</span><span>' + strength[2] + '</span><span style="background:#4aa323;">' + strength[3] + '</span>');
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('form').submit(function(){
|
||||
var email = $.trim($('input[name="email"]').val()),
|
||||
@@ -130,14 +77,12 @@ $('form').submit(function(){
|
||||
$('.error').removeClass('hide').html("{% trans "Passwords don't match" %}");
|
||||
return false;
|
||||
}
|
||||
if (pwd1.length < 6) {
|
||||
$('.error').removeClass('hide').html("{% trans "Passwords must have at least 6 characters" %}");
|
||||
return false;
|
||||
}
|
||||
if (level <= 2) {
|
||||
$('.error').removeClass('hide').html("{% trans "Passwords contain at least 2 types: uppercase letters, lowercase letters, numbers, and symbols" %}");
|
||||
return false;
|
||||
}
|
||||
{% if strong_pwd_required %}
|
||||
if (level < {{level}}) {
|
||||
$('.error').removeClass('hide').html("{% blocktrans %}{{min_len}} characters or more, include {{level}} types or more of these: letters(case sensitive), numbers, and symbols{% endblocktrans %}");
|
||||
return false;
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
62
seahub/templates/snippets/password_strength_js.html
Normal file
62
seahub/templates/snippets/password_strength_js.html
Normal file
@@ -0,0 +1,62 @@
|
||||
{% load i18n %}
|
||||
function getStrengthLevel(pwd) {
|
||||
var num = 0;
|
||||
|
||||
if (pwd.length < {{min_len}}) {
|
||||
return 0;
|
||||
} else {
|
||||
for (var i = 0; i < pwd.length; i++) {
|
||||
// return the unicode
|
||||
// bitwise OR
|
||||
num |= getCharMode(pwd.charCodeAt(i));
|
||||
};
|
||||
return calculateBitwise(num);
|
||||
};
|
||||
}
|
||||
|
||||
function getCharMode(n) {
|
||||
if (n >= 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;
|
||||
}
|
||||
|
||||
function calculateBitwise(num) {
|
||||
var level = 0;
|
||||
for (var i = 0; i < 4; i++){
|
||||
// bitwise AND
|
||||
if (num&1) level++;
|
||||
// Right logical shift
|
||||
num>>>=1;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
function showStrength(level) {
|
||||
var strength_ct = $("#pwd_strength");
|
||||
var strength = [
|
||||
"{% trans "too weak" %}",
|
||||
"{% trans "weak" %}",
|
||||
"{% trans "medium" %}",
|
||||
"{% trans "strong" %}"
|
||||
];
|
||||
switch (level) {
|
||||
case 0:
|
||||
strength_ct.html(strength[0]).css("color", '#F00000');
|
||||
break;
|
||||
case 1:
|
||||
strength_ct.html('<span style="background:#db4747;">' + strength[1] + '</span><span>' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||
break;
|
||||
case 2:
|
||||
strength_ct.html('<span>' + strength[1] + '</span><span style="background:#fdd64d;">' + strength[2] + '</span><span>' + strength[3] + '</span>');
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
strength_ct.html('<span>' + strength[1] + '</span><span>' + strength[2] + '</span><span style="background:#4aa323;">' + strength[3] + '</span>');
|
||||
break;
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ $(function() {
|
||||
$('#encrypt-switch').click(function () {
|
||||
var form = $('#repo-create-form'),
|
||||
pwd_input = $('input[type="password"]', form);
|
||||
|
||||
|
||||
if ($(this).attr('checked')) {
|
||||
pwd_input.attr('disabled', false).removeClass('input-disabled');
|
||||
} else {
|
||||
@@ -23,7 +23,7 @@ $('#encrypt-switch').click(function () {
|
||||
}
|
||||
});
|
||||
$('#repo-create-form').submit(function() {
|
||||
var form = $(this),
|
||||
var form = $(this),
|
||||
form_id = form.attr('id'),
|
||||
name = $('[name="repo_name"]', form).val(),
|
||||
desc = $('[name="repo_desc"]', form).val(),
|
||||
|
@@ -29,7 +29,8 @@ from seaserv import seafserv_rpc, seafserv_threaded_rpc, get_repo, get_commits,\
|
||||
list_personal_repos_by_owner, get_group_repos, \
|
||||
list_inner_pub_repos, CCNET_CONF_PATH, SERVICE_URL
|
||||
import seahub.settings
|
||||
from seahub.settings import SITE_NAME, MEDIA_URL, LOGO_PATH
|
||||
from seahub.settings import SITE_NAME, MEDIA_URL, LOGO_PATH, \
|
||||
USER_PASSWORD_STRENGTH_LEVEL, USER_PASSWORD_MIN_LENGTH
|
||||
try:
|
||||
from seahub.settings import EVENTS_CONFIG_FILE
|
||||
except ImportError:
|
||||
@@ -78,7 +79,7 @@ PREVIEW_FILEEXT = {
|
||||
def gen_fileext_type_map():
|
||||
"""
|
||||
Generate previewed file extension and file type relation map.
|
||||
|
||||
|
||||
"""
|
||||
d = {}
|
||||
for filetype in PREVIEW_FILEEXT.keys():
|
||||
@@ -156,7 +157,7 @@ def gen_token(max_length=5):
|
||||
Generate a random token.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
return uuid.uuid4().hex[:max_length]
|
||||
|
||||
def normalize_cache_key(value, prefix=None):
|
||||
@@ -165,7 +166,7 @@ def normalize_cache_key(value, prefix=None):
|
||||
"""
|
||||
key = value if prefix is None else prefix + value
|
||||
return urlquote(key)
|
||||
|
||||
|
||||
def get_repo_last_modify(repo):
|
||||
""" Get last modification time for a repo.
|
||||
|
||||
@@ -332,7 +333,7 @@ def get_file_revision_id_size(repo_id, commit_id, path):
|
||||
|
||||
def new_merge_with_no_conflict(commit):
|
||||
"""Check whether a commit is a new merge, and no conflict.
|
||||
|
||||
|
||||
Arguments:
|
||||
- `commit`:
|
||||
"""
|
||||
@@ -358,7 +359,7 @@ def get_commit_before_new_merge(commit):
|
||||
commit = p1 if p1.ctime > p2.ctime else p2
|
||||
|
||||
assert new_merge_with_no_conflict(commit) is False
|
||||
|
||||
|
||||
return commit
|
||||
|
||||
def gen_inner_file_get_url(token, filename):
|
||||
@@ -386,7 +387,7 @@ def get_max_upload_file_size():
|
||||
Returns ``None`` if this value is not set.
|
||||
"""
|
||||
return seaserv.MAX_UPLOAD_FILE_SIZE
|
||||
|
||||
|
||||
def gen_block_get_url(token, blkid):
|
||||
"""
|
||||
Generate fileserver block url.
|
||||
@@ -425,7 +426,7 @@ def string2list(string):
|
||||
continue
|
||||
s.add(e)
|
||||
return [ x for x in s ]
|
||||
|
||||
|
||||
# def get_cur_ctx(request):
|
||||
# ctx_dict = request.session.get('current_context', {
|
||||
# 'base_template': 'myhome_base.html',
|
||||
@@ -439,12 +440,12 @@ def string2list(string):
|
||||
def is_org_context(request):
|
||||
"""An organization context is a virtual private Seafile instance on cloud
|
||||
service.
|
||||
|
||||
|
||||
Arguments:
|
||||
- `request`:
|
||||
"""
|
||||
return request.cloud_mode and request.user.org is not None
|
||||
|
||||
|
||||
# def check_and_get_org_by_repo(repo_id, user):
|
||||
# """
|
||||
# Check whether repo is org repo, get org info if it is, and set
|
||||
@@ -460,7 +461,7 @@ def is_org_context(request):
|
||||
# else:
|
||||
# org = None
|
||||
# base_template = 'myhome_base.html'
|
||||
|
||||
|
||||
# return org, base_template
|
||||
|
||||
def check_and_get_org_by_group(group_id, user):
|
||||
@@ -478,9 +479,9 @@ def check_and_get_org_by_group(group_id, user):
|
||||
else:
|
||||
org = None
|
||||
base_template = 'myhome_base.html'
|
||||
|
||||
|
||||
return org, base_template
|
||||
|
||||
|
||||
# events related
|
||||
if EVENTS_CONFIG_FILE:
|
||||
import seafevents
|
||||
@@ -510,7 +511,7 @@ if EVENTS_CONFIG_FILE:
|
||||
events = _get_events_inner(ev_session, username, next_start, count)
|
||||
if not events:
|
||||
break
|
||||
|
||||
|
||||
for e1 in events:
|
||||
duplicate = False
|
||||
for e2 in valid_events:
|
||||
@@ -519,13 +520,13 @@ if EVENTS_CONFIG_FILE:
|
||||
new_merge = False
|
||||
if hasattr(e1, 'commit') and new_merge_with_no_conflict(e1.commit):
|
||||
new_merge = True
|
||||
|
||||
|
||||
if not duplicate and not new_merge:
|
||||
valid_events.append(e1)
|
||||
total_used = total_used + 1
|
||||
if len(valid_events) == count:
|
||||
break
|
||||
|
||||
|
||||
if len(valid_events) == count:
|
||||
break
|
||||
next_start = next_start + len(events)
|
||||
@@ -569,14 +570,14 @@ if EVENTS_CONFIG_FILE:
|
||||
break
|
||||
|
||||
if len(valid_events) == limit:
|
||||
break
|
||||
break
|
||||
next_start = next_start + len(valid_events)
|
||||
|
||||
return valid_events
|
||||
|
||||
def get_user_events(username, start, count):
|
||||
"""Return user events list and a new start.
|
||||
|
||||
|
||||
For example:
|
||||
``get_user_events('foo@example.com', 0, 10)`` returns the first 10
|
||||
events.
|
||||
@@ -584,7 +585,7 @@ if EVENTS_CONFIG_FILE:
|
||||
15th events.
|
||||
"""
|
||||
return _get_events(username, start, count)
|
||||
|
||||
|
||||
def get_org_user_events(org_id, username, start, count):
|
||||
return _get_events(username, start, count, org_id=org_id)
|
||||
|
||||
@@ -600,7 +601,7 @@ def calc_file_path_hash(path, bits=12):
|
||||
path = path.encode('UTF-8')
|
||||
|
||||
path_hash = hashlib.md5(urllib2.quote(path)).hexdigest()[:bits]
|
||||
|
||||
|
||||
return path_hash
|
||||
|
||||
def get_service_url():
|
||||
@@ -616,7 +617,7 @@ def get_server_id():
|
||||
def get_site_scheme_and_netloc():
|
||||
"""Return a string contains site scheme and network location part from
|
||||
service url.
|
||||
|
||||
|
||||
For example:
|
||||
>>> get_site_scheme_and_netloc("https://example.com:8000/seafile/")
|
||||
https://example.com:8000
|
||||
@@ -629,7 +630,7 @@ def send_html_email(subject, con_template, con_context, from_email, to_email):
|
||||
"""Send HTML email
|
||||
"""
|
||||
base_context = {
|
||||
'url_base': get_site_scheme_and_netloc(),
|
||||
'url_base': get_site_scheme_and_netloc(),
|
||||
'site_name': SITE_NAME,
|
||||
'media_url': MEDIA_URL,
|
||||
'logo_path': LOGO_PATH,
|
||||
@@ -639,7 +640,7 @@ def send_html_email(subject, con_template, con_context, from_email, to_email):
|
||||
msg = EmailMessage(subject, t.render(Context(con_context)), from_email, to_email)
|
||||
msg.content_subtype = "html"
|
||||
msg.send()
|
||||
|
||||
|
||||
def gen_dir_share_link(token):
|
||||
"""Generate directory share link.
|
||||
"""
|
||||
@@ -727,7 +728,7 @@ def convert_cmmt_desc_link(commit):
|
||||
"""
|
||||
repo_id = commit.repo_id
|
||||
cmmt_id = commit.id
|
||||
conv_link_url = reverse('convert_cmmt_desc_link')
|
||||
conv_link_url = reverse('convert_cmmt_desc_link')
|
||||
|
||||
def link_repl(matchobj):
|
||||
op = matchobj.group(1)
|
||||
@@ -776,7 +777,7 @@ def api_convert_desc_link(e):
|
||||
if file_or_dir not in d.name:
|
||||
# skip to next diff_result if file/folder user clicked does not
|
||||
# match the diff_result
|
||||
continue
|
||||
continue
|
||||
|
||||
if d.status == 'add' or d.status == 'mod':
|
||||
e.link = "api://repo/%s/files/?p=/%s" % (repo_id, d.name)
|
||||
@@ -820,7 +821,7 @@ if EVENTS_CONFIG_FILE:
|
||||
return seafevents.get_office_converter_limit(config)
|
||||
|
||||
HAS_OFFICE_CONVERTER = check_office_converter_enabled()
|
||||
|
||||
|
||||
if HAS_OFFICE_CONVERTER:
|
||||
|
||||
OFFICE_HTML_DIR = get_office_converter_html_dir()
|
||||
@@ -849,7 +850,7 @@ if HAS_OFFICE_CONVERTER:
|
||||
rpc = _get_office_converter_rpc()
|
||||
return rpc.query_file_pages(file_id)
|
||||
|
||||
def get_converted_html_detail(file_id):
|
||||
def get_converted_html_detail(file_id):
|
||||
d = {}
|
||||
outline_file = os.path.join(OFFICE_HTML_DIR, file_id, 'file.outline')
|
||||
|
||||
@@ -945,3 +946,51 @@ def user_traffic_over_limit(username):
|
||||
|
||||
month_traffic = stat['file_view'] + stat['file_download'] + stat['dir_download']
|
||||
return True if month_traffic >= traffic_limit else False
|
||||
|
||||
def is_user_password_strong(password):
|
||||
"""Return ``True`` if user's password is STRONG, otherwise ``False``.
|
||||
STRONG means password has at least USER_PASSWORD_STRENGTH_LEVEL(3) types of the bellow:
|
||||
num, upper letter, lower letter, other symbols
|
||||
"""
|
||||
|
||||
if len(password) < USER_PASSWORD_MIN_LENGTH:
|
||||
return False
|
||||
else:
|
||||
num = 0
|
||||
for letter in password:
|
||||
# get ascii dec
|
||||
# bitwise OR
|
||||
num |= get_char_mode(ord(letter))
|
||||
|
||||
if calculate_bitwise(num) < USER_PASSWORD_STRENGTH_LEVEL:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_char_mode(n):
|
||||
"""Return different num according to the type of given letter:
|
||||
'1': num,
|
||||
'2': upper_letter,
|
||||
'4': lower_letter,
|
||||
'8': other symbols
|
||||
"""
|
||||
if (n >= 48 and n <= 57): #nums
|
||||
return 1;
|
||||
if (n >= 65 and n <= 90): #uppers
|
||||
return 2;
|
||||
if (n >= 97 and n <= 122): #lowers
|
||||
return 4;
|
||||
else:
|
||||
return 8;
|
||||
|
||||
def calculate_bitwise(num):
|
||||
"""Return different level according to the given num:
|
||||
"""
|
||||
level = 0
|
||||
for i in range(4):
|
||||
# bitwise AND
|
||||
if (num&1):
|
||||
level += 1
|
||||
# Right logical shift
|
||||
num = num >> 1
|
||||
return level
|
||||
|
@@ -79,7 +79,7 @@ def root(request):
|
||||
def validate_owner(request, repo_id):
|
||||
"""
|
||||
Check whether user in the request owns the repo.
|
||||
|
||||
|
||||
"""
|
||||
ret = is_repo_owner(request.user.username, repo_id)
|
||||
|
||||
@@ -131,7 +131,7 @@ def get_system_default_repo_id():
|
||||
def check_repo_access_permission(repo_id, user):
|
||||
"""Check repo access permission of a user, always return 'rw' when repo is
|
||||
system repo and user is admin.
|
||||
|
||||
|
||||
Arguments:
|
||||
- `repo_id`:
|
||||
- `user`:
|
||||
@@ -140,13 +140,13 @@ def check_repo_access_permission(repo_id, user):
|
||||
return 'rw'
|
||||
else:
|
||||
return seafile_api.check_repo_access_permission(repo_id, user.username)
|
||||
|
||||
|
||||
def get_file_access_permission(repo_id, path, username):
|
||||
"""Check user has permission to view the file.
|
||||
1. check whether this file is private shared.
|
||||
2. if failed, check whether the parent of this directory is private shared.
|
||||
"""
|
||||
|
||||
|
||||
pfs = PrivateFileDirShare.objects.get_private_share_in_file(username,
|
||||
repo_id, path)
|
||||
if pfs is None:
|
||||
@@ -157,11 +157,11 @@ def get_file_access_permission(repo_id, path, username):
|
||||
return None
|
||||
else:
|
||||
return pfs.permission
|
||||
|
||||
|
||||
def gen_path_link(path, repo_name):
|
||||
"""
|
||||
Generate navigate paths and links in repo page.
|
||||
|
||||
|
||||
"""
|
||||
if path and path[-1] != '/':
|
||||
path += '/'
|
||||
@@ -178,9 +178,9 @@ def gen_path_link(path, repo_name):
|
||||
if repo_name:
|
||||
paths.insert(0, repo_name)
|
||||
links.insert(0, '/')
|
||||
|
||||
|
||||
zipped = zip(paths, links)
|
||||
|
||||
|
||||
return zipped
|
||||
|
||||
def get_repo_dirents(request, repo, commit, path, offset=-1, limit=-1):
|
||||
@@ -584,7 +584,7 @@ def repo_change_passwd(request, repo_id):
|
||||
{'repo_name': repo.name})
|
||||
return HttpResponse(json.dumps({'success': True}),
|
||||
content_type=content_type)
|
||||
|
||||
|
||||
def upload_error_msg (code):
|
||||
err_msg = _(u'Internal Server Error')
|
||||
if (code == 0):
|
||||
@@ -644,7 +644,7 @@ def update_file_error(request, repo_id):
|
||||
'zipped': zipped,
|
||||
'err_msg': err_msg,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def repo_history(request, repo_id):
|
||||
"""
|
||||
@@ -663,8 +663,8 @@ def repo_history(request, repo_id):
|
||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||
except CryptoOptionNotSetError:
|
||||
# Assume server_crypto is ``False`` if this option is not set.
|
||||
server_crypto = False
|
||||
|
||||
server_crypto = False
|
||||
|
||||
password_set = False
|
||||
if repo.props.encrypted and \
|
||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||
@@ -723,8 +723,8 @@ def repo_view_snapshot(request, repo_id):
|
||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||
except CryptoOptionNotSetError:
|
||||
# Assume server_crypto is ``False`` if this option is not set.
|
||||
server_crypto = False
|
||||
|
||||
server_crypto = False
|
||||
|
||||
password_set = False
|
||||
if repo.props.encrypted and \
|
||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||
@@ -779,8 +779,8 @@ def repo_history_revert(request, repo_id):
|
||||
server_crypto = UserOptions.objects.is_server_crypto(username)
|
||||
except CryptoOptionNotSetError:
|
||||
# Assume server_crypto is ``False`` if this option is not set.
|
||||
server_crypto = False
|
||||
|
||||
server_crypto = False
|
||||
|
||||
password_set = False
|
||||
if repo.props.encrypted and \
|
||||
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)):
|
||||
@@ -889,7 +889,7 @@ def create_default_library(request):
|
||||
default_repo, '/', obj_name, username, 0)
|
||||
except SearpcError as e:
|
||||
logger.error(e)
|
||||
return
|
||||
return
|
||||
|
||||
UserOptions.objects.set_default_repo(username, default_repo)
|
||||
|
||||
@@ -984,7 +984,7 @@ def myhome(request):
|
||||
@user_mods_check
|
||||
def starred(request):
|
||||
"""List starred files.
|
||||
|
||||
|
||||
Arguments:
|
||||
- `request`:
|
||||
"""
|
||||
@@ -995,7 +995,7 @@ def starred(request):
|
||||
return render_to_response('starred.html', {
|
||||
"starred_files": starred_files,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@user_mods_check
|
||||
@@ -1007,24 +1007,24 @@ def devices(request):
|
||||
return render_to_response('devices.html', {
|
||||
"devices": user_devices,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@login_required_ajax
|
||||
def unlink_device(request):
|
||||
content_type = 'application/json; charset=utf-8'
|
||||
|
||||
platform = request.POST.get('platform', '')
|
||||
device_id = request.POST.get('device_id', '')
|
||||
|
||||
|
||||
if not platform or not device_id:
|
||||
return HttpResponseBadRequest(json.dumps({'error': _(u'Argument missing')}),
|
||||
content_type=content_type)
|
||||
|
||||
|
||||
try:
|
||||
do_unlink_device(request.user.username, platform, device_id)
|
||||
except:
|
||||
return HttpResponse(json.dumps({'error': _(u'Internal server error')}),
|
||||
status=500, content_type=content_type)
|
||||
|
||||
|
||||
return HttpResponse(json.dumps({'success': True}), content_type=content_type)
|
||||
|
||||
@login_required
|
||||
@@ -1078,7 +1078,7 @@ def unsetinnerpub(request, repo_id):
|
||||
# quota_usage = seafserv_threaded_rpc.get_user_quota_usage(owner_name)
|
||||
|
||||
# user_dict = user_info(request, owner_name)
|
||||
|
||||
|
||||
# return render_to_response('ownerhome.html', {
|
||||
# "owned_repos": owned_repos,
|
||||
# "quota_usage": quota_usage,
|
||||
@@ -1090,10 +1090,10 @@ def unsetinnerpub(request, repo_id):
|
||||
def repo_set_access_property(request, repo_id):
|
||||
ap = request.GET.get('ap', '')
|
||||
seafserv_threaded_rpc.repo_set_access_property(repo_id, ap)
|
||||
|
||||
|
||||
return HttpResponseRedirect(reverse('repo', args=[repo_id]))
|
||||
|
||||
@login_required
|
||||
@login_required
|
||||
def repo_del_file(request, repo_id):
|
||||
if check_repo_access_permission(repo_id, request.user) != 'rw':
|
||||
return render_permission_error(request, _('Failed to delete file.'))
|
||||
@@ -1109,7 +1109,7 @@ def repo_del_file(request, repo_id):
|
||||
|
||||
url = reverse('repo', args=[repo_id]) + ('?p=%s' % urllib2.quote(parent_dir.encode('utf-8')))
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
def repo_access_file(request, repo_id, obj_id):
|
||||
"""Delete or download file.
|
||||
TODO: need to be rewrite.
|
||||
@@ -1190,7 +1190,7 @@ def file_upload_progress_page(request):
|
||||
'upload_progress_con_id': upload_progress_con_id,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
@login_required
|
||||
@login_required
|
||||
def validate_filename(request):
|
||||
repo_id = request.GET.get('repo_id')
|
||||
filename = request.GET.get('filename')
|
||||
@@ -1240,7 +1240,7 @@ def render_file_revisions (request, repo_id):
|
||||
|
||||
if not commits:
|
||||
return render_error(request)
|
||||
|
||||
|
||||
# Check whether user is repo owner
|
||||
if validate_owner(request, repo_id):
|
||||
is_owner = True
|
||||
@@ -1400,10 +1400,10 @@ def view_shared_dir(request, token):
|
||||
repo_id = fileshare.repo_id
|
||||
path = request.GET.get('p', '')
|
||||
path = fileshare.path if not path else path
|
||||
if path[-1] != '/': # Normalize dir path
|
||||
if path[-1] != '/': # Normalize dir path
|
||||
path += '/'
|
||||
|
||||
if not path.startswith(fileshare.path):
|
||||
|
||||
if not path.startswith(fileshare.path):
|
||||
path = fileshare.path # Can not view upper dir of shared dir
|
||||
|
||||
repo = get_repo(repo_id)
|
||||
@@ -1417,13 +1417,13 @@ def view_shared_dir(request, token):
|
||||
zipped = gen_path_link(path, '')
|
||||
|
||||
if path == fileshare.path: # When user view the shared dir..
|
||||
# increase shared link view_cnt,
|
||||
# increase shared link view_cnt,
|
||||
fileshare = FileShare.objects.get(token=token)
|
||||
fileshare.view_cnt = F('view_cnt') + 1
|
||||
fileshare.save()
|
||||
|
||||
traffic_over_limit = user_traffic_over_limit(fileshare.username)
|
||||
|
||||
|
||||
return render_to_response('view_shared_dir.html', {
|
||||
'repo': repo,
|
||||
'token': token,
|
||||
@@ -1461,7 +1461,7 @@ def view_shared_upload_link(request, token):
|
||||
else:
|
||||
return render_to_response('share_access_validation.html', d,
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
username = uploadlink.username
|
||||
repo_id = uploadlink.repo_id
|
||||
path = uploadlink.path
|
||||
@@ -1525,9 +1525,9 @@ def pubrepo(request):
|
||||
"""
|
||||
if not request.user.permissions.can_view_org():
|
||||
raise Http404
|
||||
|
||||
|
||||
username = request.user.username
|
||||
|
||||
|
||||
if request.cloud_mode and request.user.org is not None:
|
||||
org_id = request.user.org.org_id
|
||||
public_repos = seaserv.list_org_inner_pub_repos(org_id, username)
|
||||
@@ -1538,7 +1538,7 @@ def pubrepo(request):
|
||||
'public_repos': public_repos,
|
||||
'create_shared_repo': True,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
if not request.cloud_mode:
|
||||
public_repos = seaserv.list_inner_pub_repos(username)
|
||||
for r in public_repos:
|
||||
@@ -1558,14 +1558,14 @@ def pubgrp(request):
|
||||
"""
|
||||
if not request.user.permissions.can_view_org():
|
||||
raise Http404
|
||||
|
||||
|
||||
if request.cloud_mode and request.user.org is not None:
|
||||
org_id = request.user.org.org_id
|
||||
groups = seaserv.get_org_groups(org_id, -1, -1)
|
||||
return render_to_response('organizations/pubgrp.html', {
|
||||
'groups': groups,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
if not request.cloud_mode:
|
||||
groups = seaserv.get_personal_groups(-1, -1)
|
||||
return render_to_response('pubgrp.html', {
|
||||
@@ -1579,7 +1579,7 @@ def get_pub_users(request, start, limit):
|
||||
url_prefix = request.user.org.url_prefix
|
||||
users_plus_one = seaserv.get_org_users_by_url_prefix(url_prefix,
|
||||
start, limit)
|
||||
|
||||
|
||||
elif request.cloud_mode:
|
||||
raise Http404 # no pubuser in cloud mode
|
||||
|
||||
@@ -1608,7 +1608,7 @@ def pubuser(request):
|
||||
"""
|
||||
if not request.user.permissions.can_view_org():
|
||||
raise Http404
|
||||
|
||||
|
||||
# Make sure page request is an int. If not, deliver first page.
|
||||
try:
|
||||
current_page = int(request.GET.get('page', '1'))
|
||||
@@ -1629,21 +1629,21 @@ def pubuser(request):
|
||||
users = users_plus_one[:per_page]
|
||||
username = request.user.username
|
||||
contacts = Contact.objects.get_contacts_by_user(username)
|
||||
contact_emails = []
|
||||
contact_emails = []
|
||||
for c in contacts:
|
||||
contact_emails.append(c.contact_email)
|
||||
for u in users:
|
||||
if u.email == username or u.email in contact_emails:
|
||||
u.can_be_contact = False
|
||||
else:
|
||||
u.can_be_contact = True
|
||||
u.can_be_contact = True
|
||||
|
||||
return render_to_response('pubuser.html', {
|
||||
'users': users,
|
||||
'current_page': current_page,
|
||||
'has_prev': has_prev,
|
||||
'has_next': has_next,
|
||||
'page_range': page_range,
|
||||
'page_range': page_range,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
@login_required_ajax
|
||||
@@ -1693,7 +1693,7 @@ def repo_download_dir(request, repo_id):
|
||||
dirname = os.path.basename(path.rstrip('/')) # Here use `rstrip` to cut out last '/' in path
|
||||
else:
|
||||
dirname = repo.name
|
||||
|
||||
|
||||
allow_download = False
|
||||
fileshare_token = request.GET.get('t', '')
|
||||
from_shared_link = False
|
||||
@@ -1789,18 +1789,18 @@ def group_events_data(events):
|
||||
utc = dt.replace(tzinfo=timezone.utc)
|
||||
local = timezone.make_naive(utc, tz)
|
||||
return local
|
||||
|
||||
|
||||
event_groups = []
|
||||
for e in events:
|
||||
e.time = utc_to_local(e.timestamp)
|
||||
e.date = e.time.strftime("%Y-%m-%d")
|
||||
e.date = e.time.strftime("%Y-%m-%d")
|
||||
if e.etype == 'repo-update':
|
||||
e.author = e.commit.creator_name
|
||||
elif e.etype == 'repo-create':
|
||||
e.author = e.creator
|
||||
else:
|
||||
e.author = e.repo_owner
|
||||
|
||||
|
||||
if len(event_groups) == 0 or \
|
||||
len(event_groups) > 0 and e.date != event_groups[-1]['date']:
|
||||
event_group = {}
|
||||
@@ -1814,7 +1814,7 @@ def group_events_data(events):
|
||||
|
||||
def pdf_full_view(request):
|
||||
'''For pdf view with pdf.js.'''
|
||||
|
||||
|
||||
repo_id = request.GET.get('repo_id', '')
|
||||
obj_id = request.GET.get('obj_id', '')
|
||||
file_name = request.GET.get('file_name', '')
|
||||
@@ -1840,7 +1840,7 @@ def convert_cmmt_desc_link(request):
|
||||
# perm check
|
||||
if check_repo_access_permission(repo_id, request.user) is None:
|
||||
raise Http404
|
||||
|
||||
|
||||
diff_result = seafserv_threaded_rpc.get_diff(repo_id, '', cmmt_id)
|
||||
if not diff_result:
|
||||
raise Http404
|
||||
@@ -1849,7 +1849,7 @@ def convert_cmmt_desc_link(request):
|
||||
if name not in d.name:
|
||||
# skip to next diff_result if file/folder user clicked does not
|
||||
# match the diff_result
|
||||
continue
|
||||
continue
|
||||
|
||||
if d.status == 'add' or d.status == 'mod': # Add or modify file
|
||||
return HttpResponseRedirect(reverse('repo_view_file', args=[repo_id]) + \
|
||||
@@ -1879,7 +1879,7 @@ def toggle_modules(request):
|
||||
|
||||
referer = request.META.get('HTTP_REFERER', None)
|
||||
next = settings.SITE_ROOT if referer is None else referer
|
||||
|
||||
|
||||
username = request.user.username
|
||||
personal_wiki = request.POST.get('personal_wiki', 'off')
|
||||
if personal_wiki == 'on':
|
||||
|
@@ -9,6 +9,8 @@ from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
|
||||
from registration.backends import get_backend
|
||||
from seahub.settings import USER_PASSWORD_MIN_LENGTH, \
|
||||
USER_STRONG_PASSWORD_REQUIRED, USER_PASSWORD_STRENGTH_LEVEL
|
||||
|
||||
def activate(request, backend,
|
||||
template_name='registration/activate.html',
|
||||
@@ -204,5 +206,8 @@ def register(request, backend, success_url=None, form_class=None,
|
||||
form = form_class(initial={'email': src})
|
||||
|
||||
return render_to_response(template_name,
|
||||
{ 'form': form },
|
||||
context_instance=context)
|
||||
{ 'form': form,
|
||||
'min_len': USER_PASSWORD_MIN_LENGTH,
|
||||
'strong_pwd_required': USER_STRONG_PASSWORD_REQUIRED,
|
||||
'level': USER_PASSWORD_STRENGTH_LEVEL,
|
||||
}, context_instance=context)
|
||||
|
Reference in New Issue
Block a user