diff --git a/seahub/settings.py b/seahub/settings.py index 503fb2adc0..67b22a1997 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -437,9 +437,6 @@ SESSION_COOKIE_AGE = 24 * 60 * 60 # Days of remembered login info (deafult: 7 days) LOGIN_REMEMBER_DAYS = 7 -#Share Access -SHARE_ACCESS_PASSWD_TIMEOUT = 60 * 60 - SEAFILE_VERSION = '5.0.0' # Compress static files(css, js) diff --git a/seahub/share/models.py b/seahub/share/models.py index 4d7b4e269c..3ee1afbac3 100644 --- a/seahub/share/models.py +++ b/seahub/share/models.py @@ -1,14 +1,16 @@ import datetime -from django.core.cache import cache +import logging + from django.db import models from django.utils import timezone from django.contrib.auth.hashers import make_password from seahub.base.fields import LowerCaseCharField -from seahub.utils import normalize_file_path, normalize_dir_path, gen_token, \ - normalize_cache_key -from seahub.utils.ip import get_remote_ip -from seahub.settings import SHARE_ACCESS_PASSWD_TIMEOUT +from seahub.utils import normalize_file_path, normalize_dir_path, gen_token + +# Get an instance of a logger +logger = logging.getLogger(__name__) + class AnonymousShare(models.Model): """ @@ -19,37 +21,31 @@ class AnonymousShare(models.Model): anonymous_email = LowerCaseCharField(max_length=255) token = models.CharField(max_length=25, unique=True) -def _get_cache_key(request, prefix, token): - """Return cache key of certain ``prefix``. If user is logged in, use - username and token, otherwise use combination of request ip and user agent - and token. +def _get_link_key(token, is_upload_link=False): + return 'visited_ufs_' + token if is_upload_link else \ + 'visited_fs_' + token - Arguments: - - `prefix`: - """ - 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 +def set_share_link_access(request, token, is_upload_link=False): + """Remember which shared download/upload link user can access without providing password. """ - key = _get_cache_key(request, 'SharedLink_', token) - cache.set(key, True, SHARE_ACCESS_PASSWD_TIMEOUT) + if request.session: + 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): - """Check whether user can access share link without providing password. +def check_share_link_access(request, token, is_upload_link=False): + """Check whether user can access shared download/upload link without + providing password. """ - key = _get_cache_key(request, 'SharedLink_', token) - return cache.get(key, False) + link_key = _get_link_key(token, is_upload_link) + if request.session.get(link_key, False): + return True + else: + return False class FileShareManager(models.Manager): def _add_file_share(self, username, repo_id, path, s_type, diff --git a/seahub/templates/share_access_validation.html b/seahub/templates/share_access_validation.html index 7cceec216b..a09bb0f129 100644 --- a/seahub/templates/share_access_validation.html +++ b/seahub/templates/share_access_validation.html @@ -3,7 +3,7 @@ {% block main_panel %}
-

{% 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." %}

+

{% trans "Please input the password if you want to browse the shared file/directory." %}

{% csrf_token %} diff --git a/seahub/views/repo.py b/seahub/views/repo.py index f0e9425351..1c3ef378da 100644 --- a/seahub/views/repo.py +++ b/seahub/views/repo.py @@ -519,7 +519,8 @@ def view_shared_upload_link(request, token): if uploadlink is None: 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', } if request.method == 'POST': post_values = request.POST.copy() @@ -527,7 +528,7 @@ def view_shared_upload_link(request, token): form = SharedLinkPasswordForm(post_values) d['form'] = form if form.is_valid(): - set_share_link_access(request, token) + set_share_link_access(request, token, is_upload_link=True) else: return render_to_response('share_access_validation.html', d, context_instance=RequestContext(request)) diff --git a/tests/seahub/views/test_shared_file.py b/tests/seahub/views/test_shared_file.py index 6a41740460..8e841156c5 100644 --- a/tests/seahub/views/test_shared_file.py +++ b/tests/seahub/views/test_shared_file.py @@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse from django.test import TestCase import requests -from seahub.share.models import FileShare, PrivateFileDirShare +from seahub.share.models import FileShare from seahub.test_utils import Fixtures @@ -13,7 +13,7 @@ class SharedFileTest(TestCase, Fixtures): def setUp(self): share_file_info = { - 'username': 'test@test.com', + 'username': self.user, 'repo_id': self.repo.id, 'path': self.file, 'password': None, @@ -21,6 +21,13 @@ class SharedFileTest(TestCase, Fixtures): } 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): self.remove_repo() @@ -99,6 +106,47 @@ class SharedFileTest(TestCase, Fixtures): resp = self.client.get(reverse('view_shared_file', args=[fs.token])) 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 = '' + 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): def setUp(self): diff --git a/tests/seahub/views/test_shared_upload_link.py b/tests/seahub/views/test_shared_upload_link.py new file mode 100644 index 0000000000..9f57a7cc2a --- /dev/null +++ b/tests/seahub/views/test_shared_upload_link.py @@ -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')