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

[api2] Clarify 403 error message

This commit is contained in:
zhengxie
2013-09-05 17:25:52 +08:00
parent 3a61898dec
commit 179c7a70dc
2 changed files with 101 additions and 22 deletions

30
seahub/api2/utils.py Normal file
View File

@@ -0,0 +1,30 @@
# Utility functions for api2
from seaserv import seafile_api
def is_repo_writable(repo_id, username):
"""Check whether a user has write permission to a repo.
Arguments:
- `repo_id`:
- `username`:
"""
if seafile_api.check_repo_access_permission(repo_id, username) == 'rw':
return True
else:
return False
def is_repo_accessible(repo_id, username):
"""Check whether a user can read or write to a repo.
Arguments:
- `repo_id`:
- `username`:
"""
if seafile_api.check_repo_access_permission(repo_id, username) is None:
return False
else:
return True

View File

@@ -19,8 +19,8 @@ from django.http import HttpResponse
from models import Token from models import Token
from authentication import TokenAuthentication from authentication import TokenAuthentication
from permissions import IsRepoWritable, IsRepoAccessible, IsRepoOwner
from serializers import AuthTokenSerializer from serializers import AuthTokenSerializer
from utils import is_repo_writable, is_repo_accessible
from seahub.base.accounts import User from seahub.base.accounts import User
from seahub.base.models import FileDiscuss, UserStarredFiles from seahub.base.models import FileDiscuss, UserStarredFiles
from seahub.share.models import FileShare from seahub.share.models import FileShare
@@ -340,7 +340,7 @@ def check_repo_access_permission(request, repo):
class Repo(APIView): class Repo(APIView):
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoAccessible, ) permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, ) throttle_classes = (UserRateThrottle, )
def get(self, request, repo_id, format=None): def get(self, request, repo_id, format=None):
@@ -348,6 +348,11 @@ class Repo(APIView):
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
username = request.user.username
if not is_repo_accessible(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to get repo.')
# check whether user is repo owner # check whether user is repo owner
if validate_owner(request, repo_id): if validate_owner(request, repo_id):
owner = "self" owner = "self"
@@ -373,7 +378,7 @@ class Repo(APIView):
"encrypted":repo.encrypted, "encrypted":repo.encrypted,
"encversion":r.encversion, "encversion":r.encversion,
"root":root_id, "root":root_id,
"permission": check_permission(repo.id, request.user.username), "permission": check_permission(repo.id, username),
} }
return Response(repo_json) return Response(repo_json)
@@ -408,10 +413,15 @@ class Repo(APIView):
class DownloadRepo(APIView): class DownloadRepo(APIView):
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoAccessible, ) permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, ) throttle_classes = (UserRateThrottle, )
def get(self, request, repo_id, format=None): def get(self, request, repo_id, format=None):
username = request.user.username
if not is_repo_accessible(repo_id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to get repo.')
return repo_download_info(request, repo_id) return repo_download_info(request, repo_id)
class UploadLinkView(APIView): class UploadLinkView(APIView):
@@ -606,13 +616,18 @@ class OpDeleteView(APIView):
Delete a file. Delete a file.
""" """
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoWritable, ) permission_classes = (IsAuthenticated, )
def post(self, request, repo_id, format=None): def post(self, request, repo_id, format=None):
repo = get_repo(repo_id) repo = get_repo(repo_id)
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
username = request.user.username
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to delete file.')
resp = check_repo_access_permission(request, repo) resp = check_repo_access_permission(request, repo)
if resp: if resp:
return resp return resp
@@ -628,7 +643,7 @@ class OpDeleteView(APIView):
file_name = unquote(file_name.encode('utf-8')) file_name = unquote(file_name.encode('utf-8'))
try: try:
seafserv_threaded_rpc.del_file(repo_id, parent_dir, seafserv_threaded_rpc.del_file(repo_id, parent_dir,
file_name, request.user.username) file_name, username)
except SearpcError,e: except SearpcError,e:
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
"Failed to delete file.") "Failed to delete file.")
@@ -707,7 +722,7 @@ class FileView(APIView):
""" """
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoWritable, ) permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, ) throttle_classes = (UserRateThrottle, )
def get(self, request, repo_id, format=None): def get(self, request, repo_id, format=None):
@@ -740,7 +755,7 @@ class FileView(APIView):
return get_repo_file(request, repo_id, file_id, file_name, op) return get_repo_file(request, repo_id, file_id, file_name, op)
def post(self, request, repo_id, format=None): def post(self, request, repo_id, format=None):
# rename or move file # rename, move or create file
repo = get_repo(repo_id) repo = get_repo(repo_id)
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
@@ -754,8 +769,13 @@ class FileView(APIView):
return api_error(status.HTTP_400_BAD_REQUEST, return api_error(status.HTTP_400_BAD_REQUEST,
'Path is missing or invalid.') 'Path is missing or invalid.')
username = request.user.username
operation = request.POST.get('operation', '') operation = request.POST.get('operation', '')
if operation.lower() == 'rename': if operation.lower() == 'rename':
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to rename file.')
newname = request.POST.get('newname', '') newname = request.POST.get('newname', '')
if not newname: if not newname:
return api_error(status.HTTP_400_BAD_REQUEST, return api_error(status.HTTP_400_BAD_REQUEST,
@@ -777,7 +797,7 @@ class FileView(APIView):
try: try:
seafserv_threaded_rpc.rename_file (repo_id, parent_dir_utf8, seafserv_threaded_rpc.rename_file (repo_id, parent_dir_utf8,
oldname_utf8, newname, oldname_utf8, newname,
request.user.username) username)
except SearpcError,e: except SearpcError,e:
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
"Failed to rename file: %s" % e) "Failed to rename file: %s" % e)
@@ -791,6 +811,10 @@ class FileView(APIView):
return resp return resp
elif operation.lower() == 'move': elif operation.lower() == 'move':
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to move file.')
src_dir = os.path.dirname(path) src_dir = os.path.dirname(path)
src_dir_utf8 = src_dir.encode('utf-8') src_dir_utf8 = src_dir.encode('utf-8')
src_repo_id = repo_id src_repo_id = repo_id
@@ -826,7 +850,7 @@ class FileView(APIView):
seafserv_threaded_rpc.move_file(src_repo_id, src_dir_utf8, seafserv_threaded_rpc.move_file(src_repo_id, src_dir_utf8,
filename_utf8, dst_repo_id, filename_utf8, dst_repo_id,
dst_dir_utf8, new_filename_utf8, dst_dir_utf8, new_filename_utf8,
request.user.username) username)
except SearpcError, e: except SearpcError, e:
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
"SearpcError:" + e.msg) "SearpcError:" + e.msg)
@@ -839,6 +863,10 @@ class FileView(APIView):
resp['Location'] = uri + '?p=' + quote(dst_dir_utf8) + quote(new_filename_utf8) resp['Location'] = uri + '?p=' + quote(dst_dir_utf8) + quote(new_filename_utf8)
return resp return resp
elif operation.lower() == 'create': elif operation.lower() == 'create':
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to create file.')
parent_dir = os.path.dirname(path) parent_dir = os.path.dirname(path)
parent_dir_utf8 = parent_dir.encode('utf-8') parent_dir_utf8 = parent_dir.encode('utf-8')
new_file_name = os.path.basename(path) new_file_name = os.path.basename(path)
@@ -848,11 +876,10 @@ class FileView(APIView):
try: try:
seafserv_threaded_rpc.post_empty_file(repo_id, parent_dir, seafserv_threaded_rpc.post_empty_file(repo_id, parent_dir,
new_file_name, new_file_name, username)
request.user.username)
except SearpcError, e: except SearpcError, e:
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
'Failed to make directory.') 'Failed to create file.')
if request.GET.get('reloaddir', '').lower() == 'true': if request.GET.get('reloaddir', '').lower() == 'true':
return reloaddir(request, repo_id, parent_dir) return reloaddir(request, repo_id, parent_dir)
@@ -877,6 +904,11 @@ class FileView(APIView):
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
username = request.user.username
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to delete file.')
resp = check_repo_access_permission(request, repo) resp = check_repo_access_permission(request, repo)
if resp: if resp:
return resp return resp
@@ -948,7 +980,7 @@ class DirView(APIView):
create/delete/rename/list, etc. create/delete/rename/list, etc.
""" """
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoWritable, ) permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, ) throttle_classes = (UserRateThrottle, )
def get(self, request, repo_id, format=None): def get(self, request, repo_id, format=None):
@@ -993,18 +1025,22 @@ class DirView(APIView):
resp = check_repo_access_permission(request, repo) resp = check_repo_access_permission(request, repo)
if resp: if resp:
return resp return resp
path = request.GET.get('p', '') path = request.GET.get('p', '')
if not path or path[0] != '/': if not path or path[0] != '/':
return api_error(status.HTTP_400_BAD_REQUEST, "Path is missing.") return api_error(status.HTTP_400_BAD_REQUEST, "Path is missing.")
if path == '/': # Can not make root dir. if path == '/': # Can not make root dir.
return api_error(status.HTTP_400_BAD_REQUEST, "Path is invalid.") return api_error(status.HTTP_400_BAD_REQUEST, "Path is invalid.")
if path[-1] == '/': # Cut out last '/' if possible. if path[-1] == '/': # Cut out last '/' if possible.
path = path[:-1] path = path[:-1]
username = request.user.username
operation = request.POST.get('operation', '') operation = request.POST.get('operation', '')
if operation.lower() == 'mkdir': if operation.lower() == 'mkdir':
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to create folder.')
parent_dir = os.path.dirname(path) parent_dir = os.path.dirname(path)
parent_dir_utf8 = parent_dir.encode('utf-8') parent_dir_utf8 = parent_dir.encode('utf-8')
new_dir_name = os.path.basename(path) new_dir_name = os.path.basename(path)
@@ -1014,8 +1050,7 @@ class DirView(APIView):
try: try:
seafserv_threaded_rpc.post_dir(repo_id, parent_dir, seafserv_threaded_rpc.post_dir(repo_id, parent_dir,
new_dir_name, new_dir_name, username)
request.user.username)
except SearpcError, e: except SearpcError, e:
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
'Failed to make directory.') 'Failed to make directory.')
@@ -1042,6 +1077,11 @@ class DirView(APIView):
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
username = request.user.username
if not is_repo_writable(repo.id, username):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to delete folder.')
resp = check_repo_access_permission(request, repo) resp = check_repo_access_permission(request, repo)
if resp: if resp:
return resp return resp
@@ -1062,8 +1102,7 @@ class DirView(APIView):
try: try:
seafserv_threaded_rpc.del_file(repo_id, parent_dir_utf8, seafserv_threaded_rpc.del_file(repo_id, parent_dir_utf8,
file_name_utf8, file_name_utf8, username)
request.user.username)
except SearpcError, e: except SearpcError, e:
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
"Failed to delete file.") "Failed to delete file.")
@@ -1138,13 +1177,18 @@ class SharedRepo(APIView):
Support uniform interface for shared libraries. Support uniform interface for shared libraries.
""" """
authentication_classes = (TokenAuthentication, ) authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated, IsRepoOwner) permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, ) throttle_classes = (UserRateThrottle, )
def delete(self, request, repo_id, format=None): def delete(self, request, repo_id, format=None):
""" """
Unshare a library. Only repo owner can perform this operation. Unshare a library. Only repo owner can perform this operation.
""" """
username = request.user.username
if not seafile_api.is_repo_owner(username, repo_id):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to unshare library.')
share_type = request.GET.get('share_type', '') share_type = request.GET.get('share_type', '')
user = request.GET.get('user', '') user = request.GET.get('user', '')
group_id = request.GET.get('group_id', '') group_id = request.GET.get('group_id', '')
@@ -1153,7 +1197,7 @@ class SharedRepo(APIView):
'share_type and user and group_id is required.') 'share_type and user and group_id is required.')
if share_type == 'personal': if share_type == 'personal':
remove_share(repo_id, request.user.username, user) remove_share(repo_id, username, user)
elif share_type == 'group': elif share_type == 'group':
unshare_group_repo(repo_id, group_id, user) unshare_group_repo(repo_id, group_id, user)
elif share_type == 'public': elif share_type == 'public':
@@ -1168,6 +1212,11 @@ class SharedRepo(APIView):
""" """
Share a repo to users/groups/public. Share a repo to users/groups/public.
""" """
username = request.user.username
if not seafile_api.is_repo_owner(username, repo_id):
return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to share library.')
share_type = request.GET.get('share_type') share_type = request.GET.get('share_type')
user = request.GET.get('user') user = request.GET.get('user')
group_id = request.GET.get('group_id') group_id = request.GET.get('group_id')