1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-18 00:00:00 +00:00

Merge pull request #1198 from haiwen/share-link

update audit when view file via shared dir
This commit is contained in:
xiez
2016-05-19 10:36:47 +08:00
5 changed files with 189 additions and 15 deletions

View File

@@ -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

View File

@@ -87,7 +87,7 @@
<td>
{% if dirent.is_img %}
<a class="normal img-name-link" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_raw_shared_file" token dirent.obj_id dirent.obj_name %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a>
<a class="normal img-name-link" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}&raw=1">{{ dirent.obj_name }}</a>
{% else %}
<a class="normal" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a>
{% endif %}
@@ -125,7 +125,7 @@
{% for dirent in file_list %}
<li class="file-item grid-item" data-name="{{dirent.obj_name}}" title="{{dirent.obj_name}}">
{% if dirent.is_img %}
<a class="img-link img-img-link" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_raw_shared_file" token dirent.obj_id dirent.obj_name %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">
<a class="img-link img-img-link" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}&raw=1">
{% if dirent.encoded_thumbnail_src %}
<img class="thumbnail vam" src="{{ SITE_ROOT }}{{ dirent.encoded_thumbnail_src }}" alt="" />
{% else %}
@@ -139,7 +139,7 @@
{% endif %}
{% if dirent.is_img %}
<a class="normal img-name-link text-link ellipsis" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_raw_shared_file" token dirent.obj_id dirent.obj_name %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a>
<a class="normal img-name-link text-link ellipsis" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}" data-mfp-src="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}&raw=1">{{ dirent.obj_name }}</a>
{% else %}
<a class="normal text-link ellipsis" href="{% url "view_file_via_shared_dir" token %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a>
{% endif %}

View File

@@ -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)

View File

@@ -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('<p class="tip">Please provide your email address to continue.</p>', 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

View File

@@ -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</h2>' % 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</h2>' % 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