mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-16 15:19:06 +00:00
[share] Update share link passwd
This commit is contained in:
@@ -437,9 +437,6 @@ SESSION_COOKIE_AGE = 24 * 60 * 60
|
|||||||
# Days of remembered login info (deafult: 7 days)
|
# Days of remembered login info (deafult: 7 days)
|
||||||
LOGIN_REMEMBER_DAYS = 7
|
LOGIN_REMEMBER_DAYS = 7
|
||||||
|
|
||||||
#Share Access
|
|
||||||
SHARE_ACCESS_PASSWD_TIMEOUT = 60 * 60
|
|
||||||
|
|
||||||
SEAFILE_VERSION = '5.0.0'
|
SEAFILE_VERSION = '5.0.0'
|
||||||
|
|
||||||
# Compress static files(css, js)
|
# Compress static files(css, js)
|
||||||
|
@@ -1,14 +1,16 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from django.core.cache import cache
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
|
|
||||||
from seahub.base.fields import LowerCaseCharField
|
from seahub.base.fields import LowerCaseCharField
|
||||||
from seahub.utils import normalize_file_path, normalize_dir_path, gen_token, \
|
from seahub.utils import normalize_file_path, normalize_dir_path, gen_token
|
||||||
normalize_cache_key
|
|
||||||
from seahub.utils.ip import get_remote_ip
|
# Get an instance of a logger
|
||||||
from seahub.settings import SHARE_ACCESS_PASSWD_TIMEOUT
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AnonymousShare(models.Model):
|
class AnonymousShare(models.Model):
|
||||||
"""
|
"""
|
||||||
@@ -19,37 +21,31 @@ class AnonymousShare(models.Model):
|
|||||||
anonymous_email = LowerCaseCharField(max_length=255)
|
anonymous_email = LowerCaseCharField(max_length=255)
|
||||||
token = models.CharField(max_length=25, unique=True)
|
token = models.CharField(max_length=25, unique=True)
|
||||||
|
|
||||||
def _get_cache_key(request, prefix, token):
|
def _get_link_key(token, is_upload_link=False):
|
||||||
"""Return cache key of certain ``prefix``. If user is logged in, use
|
return 'visited_ufs_' + token if is_upload_link else \
|
||||||
username and token, otherwise use combination of request ip and user agent
|
'visited_fs_' + token
|
||||||
and token.
|
|
||||||
|
|
||||||
Arguments:
|
def set_share_link_access(request, token, is_upload_link=False):
|
||||||
- `prefix`:
|
"""Remember which shared download/upload link user can access without
|
||||||
"""
|
|
||||||
if request.user.is_authenticated():
|
|
||||||
key = normalize_cache_key(request.user.username, 'SharedLink_', token)
|
|
||||||
else:
|
|
||||||
ip = get_remote_ip(request)
|
|
||||||
# Memcached key length limit is 250 chars, and user agent sometimes may
|
|
||||||
# be long which will cause error.
|
|
||||||
agent = request.META.get('HTTP_USER_AGENT', '')[:150]
|
|
||||||
key = normalize_cache_key(ip + agent, 'SharedLink_', token)
|
|
||||||
|
|
||||||
return key
|
|
||||||
|
|
||||||
def set_share_link_access(request, token):
|
|
||||||
"""Remember which share download/upload links user can access without
|
|
||||||
providing password.
|
providing password.
|
||||||
"""
|
"""
|
||||||
key = _get_cache_key(request, 'SharedLink_', token)
|
if request.session:
|
||||||
cache.set(key, True, SHARE_ACCESS_PASSWD_TIMEOUT)
|
link_key = _get_link_key(token, is_upload_link)
|
||||||
|
request.session[link_key] = True
|
||||||
|
else:
|
||||||
|
# should never reach here in normal case
|
||||||
|
logger.warn('Failed to remember shared link password, request.session'
|
||||||
|
' is None when set shared link access.')
|
||||||
|
|
||||||
def check_share_link_access(request, token):
|
def check_share_link_access(request, token, is_upload_link=False):
|
||||||
"""Check whether user can access share link without providing password.
|
"""Check whether user can access shared download/upload link without
|
||||||
|
providing password.
|
||||||
"""
|
"""
|
||||||
key = _get_cache_key(request, 'SharedLink_', token)
|
link_key = _get_link_key(token, is_upload_link)
|
||||||
return cache.get(key, False)
|
if request.session.get(link_key, False):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
class FileShareManager(models.Manager):
|
class FileShareManager(models.Manager):
|
||||||
def _add_file_share(self, username, repo_id, path, s_type,
|
def _add_file_share(self, username, repo_id, path, s_type,
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
{% block main_panel %}
|
{% block main_panel %}
|
||||||
<div class="wide-panel">
|
<div class="wide-panel">
|
||||||
<p class="access-notice">{% trans "Please input the password if you want to browse the shared file/directory. And the password will be kept on the server for only 1 hour." %}</p>
|
<p class="access-notice">{% trans "Please input the password if you want to browse the shared file/directory." %}</p>
|
||||||
<form action="{% url view_name token %}" method="post" id="share-passwd-form">{% csrf_token %}
|
<form action="{% url view_name token %}" method="post" id="share-passwd-form">{% csrf_token %}
|
||||||
<label>{% trans "Password: " %}</label>
|
<label>{% trans "Password: " %}</label>
|
||||||
<input type="password" name="password" autofocus />
|
<input type="password" name="password" autofocus />
|
||||||
|
@@ -519,7 +519,8 @@ def view_shared_upload_link(request, token):
|
|||||||
if uploadlink is None:
|
if uploadlink is None:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
if uploadlink.is_encrypted() and not check_share_link_access(request, token):
|
if uploadlink.is_encrypted() and not check_share_link_access(
|
||||||
|
request, token, is_upload_link=True):
|
||||||
d = {'token': token, 'view_name': 'view_shared_upload_link', }
|
d = {'token': token, 'view_name': 'view_shared_upload_link', }
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
post_values = request.POST.copy()
|
post_values = request.POST.copy()
|
||||||
@@ -527,7 +528,7 @@ def view_shared_upload_link(request, token):
|
|||||||
form = SharedLinkPasswordForm(post_values)
|
form = SharedLinkPasswordForm(post_values)
|
||||||
d['form'] = form
|
d['form'] = form
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
set_share_link_access(request, token)
|
set_share_link_access(request, token, is_upload_link=True)
|
||||||
else:
|
else:
|
||||||
return render_to_response('share_access_validation.html', d,
|
return render_to_response('share_access_validation.html', d,
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
@@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from seahub.share.models import FileShare, PrivateFileDirShare
|
from seahub.share.models import FileShare
|
||||||
from seahub.test_utils import Fixtures
|
from seahub.test_utils import Fixtures
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ class SharedFileTest(TestCase, Fixtures):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
share_file_info = {
|
share_file_info = {
|
||||||
'username': 'test@test.com',
|
'username': self.user,
|
||||||
'repo_id': self.repo.id,
|
'repo_id': self.repo.id,
|
||||||
'path': self.file,
|
'path': self.file,
|
||||||
'password': None,
|
'password': None,
|
||||||
@@ -21,6 +21,13 @@ class SharedFileTest(TestCase, Fixtures):
|
|||||||
}
|
}
|
||||||
self.fs = FileShare.objects.create_file_link(**share_file_info)
|
self.fs = FileShare.objects.create_file_link(**share_file_info)
|
||||||
|
|
||||||
|
share_file_info.update({'password': '12345678'})
|
||||||
|
self.enc_fs = FileShare.objects.create_file_link(**share_file_info)
|
||||||
|
share_file_info.update({'password': '12345678'})
|
||||||
|
self.enc_fs2 = FileShare.objects.create_file_link(**share_file_info)
|
||||||
|
|
||||||
|
assert self.enc_fs.token != self.enc_fs2.token
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.remove_repo()
|
self.remove_repo()
|
||||||
|
|
||||||
@@ -99,6 +106,47 @@ class SharedFileTest(TestCase, Fixtures):
|
|||||||
resp = self.client.get(reverse('view_shared_file', args=[fs.token]))
|
resp = self.client.get(reverse('view_shared_file', args=[fs.token]))
|
||||||
self.assertEqual(200, resp.status_code)
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
def _assert_redirect_to_password_page(self, fs):
|
||||||
|
resp = self.client.get(reverse('view_shared_file', args=[fs.token]))
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'share_access_validation.html')
|
||||||
|
|
||||||
|
def _assert_render_file_page_when_input_passwd(self, fs):
|
||||||
|
resp = self.client.post(reverse('view_shared_file', args=[fs.token]), {
|
||||||
|
'password': '12345678',
|
||||||
|
})
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'shared_file_view.html')
|
||||||
|
self.assertContains(resp, os.path.basename(self.file))
|
||||||
|
dl_url_tag = '<a href="?dl=1" class="obv-btn">'
|
||||||
|
self.assertContains(resp, dl_url_tag)
|
||||||
|
|
||||||
|
def _assert_render_file_page_without_passwd(self, fs):
|
||||||
|
resp = self.client.get(reverse('view_shared_file', args=[fs.token]))
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'shared_file_view.html')
|
||||||
|
|
||||||
|
def test_can_view_enc(self):
|
||||||
|
self._assert_redirect_to_password_page(self.enc_fs)
|
||||||
|
self._assert_render_file_page_when_input_passwd(self.enc_fs)
|
||||||
|
|
||||||
|
def test_can_view_enc_link_without_passwd(self):
|
||||||
|
self._assert_redirect_to_password_page(self.enc_fs)
|
||||||
|
self._assert_render_file_page_when_input_passwd(self.enc_fs)
|
||||||
|
self._assert_render_file_page_without_passwd(self.enc_fs)
|
||||||
|
|
||||||
|
def test_can_view_multiple_enc_links_without_passwd(self):
|
||||||
|
# first shared link
|
||||||
|
self._assert_redirect_to_password_page(self.enc_fs)
|
||||||
|
self._assert_render_file_page_when_input_passwd(self.enc_fs)
|
||||||
|
|
||||||
|
# second shared link
|
||||||
|
self._assert_redirect_to_password_page(self.enc_fs2)
|
||||||
|
self._assert_render_file_page_when_input_passwd(self.enc_fs2)
|
||||||
|
|
||||||
|
self._assert_render_file_page_without_passwd(self.enc_fs)
|
||||||
|
self._assert_render_file_page_without_passwd(self.enc_fs2)
|
||||||
|
|
||||||
|
|
||||||
class FileViaSharedDirTest(TestCase, Fixtures):
|
class FileViaSharedDirTest(TestCase, Fixtures):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
51
tests/seahub/views/test_shared_upload_link.py
Normal file
51
tests/seahub/views/test_shared_upload_link.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from seahub.share.models import UploadLinkShare
|
||||||
|
from seahub.test_utils import BaseTestCase
|
||||||
|
|
||||||
|
class SharedUploadLinkTest(BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
share_file_info = {
|
||||||
|
'username': self.user,
|
||||||
|
'repo_id': self.repo.id,
|
||||||
|
'path': '/',
|
||||||
|
'password': None,
|
||||||
|
'expire_date': None,
|
||||||
|
}
|
||||||
|
self.fs = UploadLinkShare.objects.create_upload_link_share(**share_file_info)
|
||||||
|
|
||||||
|
share_file_info.update({'password': '12345678'})
|
||||||
|
self.enc_fs = UploadLinkShare.objects.create_upload_link_share(**share_file_info)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.remove_repo()
|
||||||
|
|
||||||
|
def test_can_render(self):
|
||||||
|
resp = self.client.get(
|
||||||
|
reverse('view_shared_upload_link', args=[self.fs.token])
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'view_shared_upload_link.html')
|
||||||
|
self.assertContains(resp, "Add Files")
|
||||||
|
|
||||||
|
def test_can_render_enc(self):
|
||||||
|
resp = self.client.get(
|
||||||
|
reverse('view_shared_upload_link', args=[self.enc_fs.token])
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'share_access_validation.html')
|
||||||
|
|
||||||
|
resp = self.client.post(reverse('view_shared_upload_link',
|
||||||
|
args=[self.enc_fs.token]), {
|
||||||
|
'password': '12345678',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'view_shared_upload_link.html')
|
||||||
|
self.assertContains(resp, "Add Files")
|
||||||
|
|
||||||
|
resp = self.client.get(
|
||||||
|
reverse('view_shared_upload_link', args=[self.enc_fs.token])
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assertTemplateUsed(resp, 'view_shared_upload_link.html')
|
Reference in New Issue
Block a user