From 160963c2720a173e240545d9969ddcacb9c6f3b6 Mon Sep 17 00:00:00 2001 From: lian Date: Wed, 18 May 2016 17:11:56 +0800 Subject: [PATCH] update audit when view file via shared dir --- seahub/share/decorators.py | 7 +- seahub/templates/view_shared_dir.html | 6 +- seahub/views/file.py | 23 ++-- tests/seahub/share/test_decorators.py | 143 +++++++++++++++++++++ tests/seahub/views/repo/test_shared_dir.py | 25 ++++ 5 files changed, 189 insertions(+), 15 deletions(-) create mode 100644 tests/seahub/share/test_decorators.py diff --git a/seahub/share/decorators.py b/seahub/share/decorators.py index c373aae73f..ef4cac37f5 100644 --- a/seahub/share/decorators.py +++ b/seahub/share/decorators.py @@ -11,9 +11,10 @@ def share_link_audit(func): def _decorated(request, token, *args, **kwargs): assert token is not None # Checked by URLconf - fileshare = FileShare.objects.get_valid_file_link_by_token(token) - if fileshare is None: - fileshare = UploadLinkShare.objects.get_valid_upload_link_by_token(token) + fileshare = FileShare.objects.get_valid_file_link_by_token(token) or \ + FileShare.objects.get_valid_dir_link_by_token(token) or \ + UploadLinkShare.objects.get_valid_upload_link_by_token(token) + if fileshare is None: raise Http404 diff --git a/seahub/templates/view_shared_dir.html b/seahub/templates/view_shared_dir.html index 471025f9bd..46e90d5f0a 100644 --- a/seahub/templates/view_shared_dir.html +++ b/seahub/templates/view_shared_dir.html @@ -87,7 +87,7 @@ {% if dirent.is_img %} - {{ dirent.obj_name }} + {{ dirent.obj_name }} {% else %} {{ dirent.obj_name }} {% endif %} @@ -125,7 +125,7 @@ {% for dirent in file_list %}
  • {% if dirent.is_img %} - + {% if dirent.encoded_thumbnail_src %} {% else %} @@ -139,7 +139,7 @@ {% endif %} {% if dirent.is_img %} - {{ dirent.obj_name }} + {{ dirent.obj_name }} {% else %} {{ dirent.obj_name }} {% endif %} diff --git a/seahub/views/file.py b/seahub/views/file.py index 6a17595618..8981bf7d9a 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -896,14 +896,9 @@ def view_raw_shared_file(request, token, obj_id, file_name): outer_url = gen_file_get_url(token, filename) return HttpResponseRedirect(outer_url) -def view_file_via_shared_dir(request, token): - assert token is not None # Checked by URLconf - - fileshare = FileShare.objects.get_valid_file_link_by_token(token) - if fileshare is None: - raise Http404 - - +@share_link_audit +def view_file_via_shared_dir(request, fileshare): + token = fileshare.token req_path = request.GET.get('p', '').rstrip('/') if not req_path: return HttpResponseRedirect(reverse('view_shared_dir', args=[token])) @@ -941,9 +936,19 @@ def view_file_via_shared_dir(request, token): obj_id = seafile_api.get_file_id_by_path(repo_id, real_path) if not obj_id: return render_error(request, _(u'File does not exist')) - file_size = seafile_api.get_file_size(repo.store_id, repo.version, obj_id) filename = os.path.basename(req_path) + if request.GET.get('raw', '0') == '1': + username = request.user.username + token = seafile_api.get_fileserver_access_token(repo_id, + obj_id, 'view', username, use_onetime=True) + + raw_url = gen_file_get_url(token, filename) + # send stats message + send_file_access_msg(request, repo, real_path, 'share-link') + return HttpResponseRedirect(raw_url) + + file_size = seafile_api.get_file_size(repo.store_id, repo.version, obj_id) filetype, fileext = get_file_type_and_ext(filename) access_token = seafile_api.get_fileserver_access_token(repo.id, obj_id, 'view', '', use_onetime=False) diff --git a/tests/seahub/share/test_decorators.py b/tests/seahub/share/test_decorators.py new file mode 100644 index 0000000000..31ff58fee6 --- /dev/null +++ b/tests/seahub/share/test_decorators.py @@ -0,0 +1,143 @@ +from mock import patch + +from django.core.cache import cache +from django.contrib.auth.models import AnonymousUser +from django.http import HttpResponse, Http404 +from django.test import override_settings +from django.test.client import RequestFactory + +from seahub.test_utils import BaseTestCase +from seahub.share.decorators import share_link_audit +from seahub.share.models import FileShare +from seahub.utils import gen_token, normalize_cache_key + +class ShareLinkAuditTest(BaseTestCase): + def setUp(self): + share_file_info = { + 'username': self.user.username, + 'repo_id': self.repo.id, + 'path': self.file, + 'password': None, + 'expire_date': None, + } + self.fs = FileShare.objects.create_file_link(**share_file_info) + + # Every test needs access to the request factory. + self.factory = RequestFactory() + + @property + def _request(self, session={}): + request = self.factory.get('/rand') + request.user = self.user + request.session = session + return request + + def _anon_request(self, session={}): + request = self.factory.get('/rand') + request.user = AnonymousUser() + request.session = session + request.cloud_mode = False + return request + + def _anon_post_request(self, data={}, session={}): + request = self.factory.post('/rand', data) + request.user = AnonymousUser() + request.session = session + request.cloud_mode = False + return request + + def _fake_view_shared_file(self, request, token): + @share_link_audit + def fake_view_shared_file(request, fileshare): + return HttpResponse() + return fake_view_shared_file(request, token) + + def test_bad_share_token(self): + @share_link_audit + def a_view(request, fileshare): + return HttpResponse() + + request = self.factory.get('/rand') + request.user = self.user + + self.assertRaises(Http404, a_view, request, 'xxx') + + def test_non_pro_version(self): + """ + Check that share_link_audit works as nomal view_shared_file on + non-pro version. + """ + resp = self._fake_view_shared_file(self._request, self.fs.token) + self.assertEqual(resp.status_code, 200) + + def test_shared_link_audit_not_enabled(self): + resp = self._fake_view_shared_file(self._request, self.fs.token) + self.assertEqual(resp.status_code, 200) + + @override_settings(ENABLE_SHARE_LINK_AUDIT=True) + @patch('seahub.share.decorators.is_pro_version') + def test_audit_authenticated_user(self, mock_is_pro_version): + mock_is_pro_version.return_value = True + + resp = self._fake_view_shared_file(self._request, self.fs.token) + self.assertEqual(resp.status_code, 200) + + @override_settings(ENABLE_SHARE_LINK_AUDIT=True) + @patch('seahub.share.decorators.is_pro_version') + def test_audit_anonymous_user_with_mail_in_session(self, mock_is_pro_version): + mock_is_pro_version.return_value = True + + anon_req = self._anon_request(session={'anonymous_email': 'a@a.com'}) + resp = self._fake_view_shared_file(anon_req, self.fs.token) + self.assertEqual(resp.status_code, 200) + + @override_settings(ENABLE_SHARE_LINK_AUDIT=True) + @patch('seahub.share.decorators.is_pro_version') + def test_audit_anonymous_user_without_mail_in_session(self, mock_is_pro_version): + """ + Check that share_link_audit works on pro version and setting enabled, + which show a page that let user input email and verification code. + """ + mock_is_pro_version.return_value = True + + anon_req = self._anon_request() + resp = self._fake_view_shared_file(anon_req, self.fs.token) + self.assertEqual(resp.status_code, 200) + self.assertIn('

    Please provide your email address to continue.

    ', resp.content) + + @override_settings(ENABLE_SHARE_LINK_AUDIT=True) + @patch('seahub.share.decorators.is_pro_version') + def test_anonymous_user_post_wrong_token(self, mock_is_pro_version): + """ + Check that anonnymous user input email and wrong verification code. + """ + mock_is_pro_version.return_value = True + + anon_req = self._anon_post_request(data={'code': 'xx'}, session={}) + self.assertEqual(anon_req.session.get('anonymous_email'), None) + resp = self._fake_view_shared_file(anon_req, self.fs.token) + + self.assertEqual(resp.status_code, 200) + self.assertIn('Invalid token, please try again.', resp.content) + + @override_settings(ENABLE_SHARE_LINK_AUDIT=True) + @patch('seahub.share.decorators.is_pro_version') + def test_anonymous_user_post_correct_token(self, mock_is_pro_version): + """ + Check that anonnymous user input email and correct verification code. + """ + mock_is_pro_version.return_value = True + + code = gen_token(max_length=6) + email = 'a@a.com' + cache_key = normalize_cache_key(email, 'share_link_audit_') + cache.set(cache_key, code, timeout=60) + assert cache.get(cache_key) == code + + anon_req = self._anon_post_request(data={'code': code, 'email': email}) + self.assertEqual(anon_req.session.get('anonymous_email'), None) + resp = self._fake_view_shared_file(anon_req, self.fs.token) + + self.assertEqual(resp.status_code, 200) + self.assertEqual(anon_req.session.get('anonymous_email'), email) # email is set in session + assert cache.get(cache_key) is None # token is delete after used diff --git a/tests/seahub/views/repo/test_shared_dir.py b/tests/seahub/views/repo/test_shared_dir.py index 48a5428b79..e278c3d33e 100644 --- a/tests/seahub/views/repo/test_shared_dir.py +++ b/tests/seahub/views/repo/test_shared_dir.py @@ -38,6 +38,13 @@ class SharedDirTest(TestCase, Fixtures): self.assertEqual(302, resp.status_code) assert '8082/files/' in resp.get('location') + def test_view_raw_file_via_shared_dir(self): + resp = self.client.get( + reverse('view_file_via_shared_dir', args=[self.fs.token]) + '?p=' + self.file + '&raw=1' + ) + + assert '8082' in resp['location'] + class EncryptSharedDirTest(TestCase, Fixtures): def setUp(self): share_file_info = { @@ -124,6 +131,24 @@ class EncryptSharedDirTest(TestCase, Fixtures): self.assertTemplateUsed(resp, 'shared_file_view.html') self.assertContains(resp, '%s' % self.filename) + def test_view_raw_file_via_shared_dir(self): + resp = self.client.post( + reverse('view_file_via_shared_dir', args=[self.fs.token]) + '?p=' + self.sub_file, { + 'password': '12345678' + } + ) + + self.assertEqual(200, resp.status_code) + self.assertTemplateNotUsed(resp, 'share_access_validation.html') + self.assertTemplateUsed(resp, 'shared_file_view.html') + self.assertContains(resp, '%s' % self.filename) + + resp = self.client.get( + reverse('view_file_via_shared_dir', args=[self.fs.token]) + '?p=' + self.sub_file + '&raw=1' + ) + + assert '8082' in resp['location'] + def test_view_file_via_shared_dir_without_password(self): resp = self.client.get( reverse('view_file_via_shared_dir', args=[self.fs.token]) + '?p=' + self.sub_file