def test_reshare_to_user_group_after_transfer_repo(self): tmp_user = '******' User.objects.create_user(tmp_user) # add admin user to group ccnet_api.group_add_member(self.group_id, self.user_name, self.admin.username) # share user's repo to tmp_user with 'rw' permission seafile_api.share_repo(self.user_repo_id, self.user.username, tmp_user, 'rw') # share user's repo to group with 'r' permission seafile_api.set_group_repo(self.user_repo_id, self.group_id, self.user_name, 'r') group_repos = seafile_api.get_repos_by_group(self.group_id) assert group_repos[0].permission == 'r' assert seafile_api.check_permission_by_path(self.user_repo_id, '/', tmp_user) == 'rw' self.login_as(self.user) url = reverse("api2-repo-owner", args=[self.user_repo_id]) data = 'owner=%s' % self.admin.email # transfer repo to admin resp = self.client.put(url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) group_repos = seafile_api.get_repos_by_group(self.group_id) assert group_repos[0].permission == 'r' assert seafile_api.check_permission_by_path(self.user_repo_id, '/', tmp_user) == 'rw'
def test_can_update_user_share_perm(self): self.share_repo_to_user() assert seafile_api.check_permission_by_path( self.repo_id, '/', self.admin_name) == 'rw' self.login_as(self.user) url = reverse('api-v2.1-shared-repo', args=[self.repo_id]) data = 'permission=r&share_type=personal&user=%s' % self.admin_name resp = self.client.put(url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) assert seafile_api.check_permission_by_path( self.repo_id, '/', self.admin_name) == 'r'
def handleMove(self, destPath): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) parts = destPath.strip("/").split("/", 1) if len(parts) <= 1: raise DAVError(HTTP_BAD_REQUEST) repo_name = parts[0] rel_path = parts[1] dest_dir, dest_file = os.path.split(rel_path) dest_repo = getRepoByName(repo_name, self.username, self.org_id, self.is_guest) if seafile_api.check_permission_by_path(dest_repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) src_dir, src_file = os.path.split(self.rel_path) if not src_file: raise DAVError(HTTP_BAD_REQUEST) if not seafile_api.is_valid_filename(dest_repo.id, dest_file): raise DAVError(HTTP_BAD_REQUEST) # some clients such as GoodReader requires "overwrite" semantics file_id_dest = seafile_api.get_file_id_by_path(dest_repo.id, rel_path) if file_id_dest != None: seafile_api.del_file(dest_repo.id, dest_dir, dest_file, self.username) seafile_api.move_file(self.repo.id, src_dir, src_file, dest_repo.id, dest_dir, dest_file, self.username, NEED_PROGRESS, SYNCHRONOUS) return True
def test_create_file_with_invalid_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit sub-folder with 'r' permission assert seafile_api.check_permission_by_path(self.repo_id, self.folder_path, self.admin_name) == 'r' # login as admin, then create file in a 'r' permission folder self.login_as(self.admin) new_name = randstring(6) new_file_path = posixpath.join(self.folder_path, new_name) data = { 'operation': 'create', } resp = self.client.post(self.url + '?p=' + new_file_path, data) self.assertEqual(403, resp.status_code)
def test_rename_file_with_invalid_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # create a file as old file in user repo sub-folder old_file_name = randstring(6) seafile_api.post_empty_file(repo_id=self.repo_id, parent_dir=self.folder_path, filename=old_file_name, username=self.user_name) # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit old file with 'r' permission old_file_path = posixpath.join(self.folder_path, old_file_name) assert seafile_api.check_permission_by_path(self.repo_id, old_file_path, self.admin_name) == 'r' # login as admin, then rename a 'r' permission old file self.login_as(self.admin) new_name = randstring(6) data = {'operation': 'rename', 'newname': new_name} resp = self.client.post(self.url + '?p=' + old_file_path, data) self.assertEqual(403, resp.status_code)
def handle_copy(self, dest_path, depth_infinity): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) parts = dest_path.strip("/").split("/", 1) if len(parts) <= 1: raise DAVError(HTTP_BAD_REQUEST) repo_name = parts[0] rel_path = parts[1] dest_dir, dest_file = os.path.split(rel_path) dest_repo = getRepoByName(repo_name, self.username, self.org_id, self.is_guest) if seafile_api.check_permission_by_path(dest_repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) src_dir, src_file = os.path.split(self.rel_path) if not src_file: raise DAVError(HTTP_BAD_REQUEST) if not seafile_api.is_valid_filename(dest_repo.id, dest_file): raise DAVError(HTTP_BAD_REQUEST) seafile_api.copy_file(self.repo.id, src_dir, src_file, dest_repo.id, dest_dir, dest_file, self.username, NEED_PROGRESS, SYNCHRONOUS) return True
def handleCopy(self, destPath, depthInfinity): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) parts = destPath.strip("/").split("/", 1) if len(parts) <= 1: raise DAVError(HTTP_BAD_REQUEST) repo_name = parts[0] rel_path = parts[1] dest_dir, dest_file = os.path.split(rel_path) dest_repo = getRepoByName(repo_name, self.username, self.org_id, self.is_guest) if seafile_api.check_permission_by_path(dest_repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) src_dir, src_file = os.path.split(self.rel_path) if not src_file: raise DAVError(HTTP_BAD_REQUEST) if not seafile_api.is_valid_filename(dest_repo.id, dest_file): raise DAVError(HTTP_BAD_REQUEST) seafile_api.copy_file(self.repo.id, src_dir, src_file, dest_repo.id, dest_dir, dest_file, self.username, NEED_PROGRESS, SYNCHRONOUS) return True
def create_empty_resource(self, name): """Create an empty (length-0) resource. See DAVResource.createEmptyResource() """ assert not "/" in name if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_quota(self.repo.id) < 0: raise DAVError(HTTP_FORBIDDEN, "The quota of the repo owner is exceeded") try: seafile_api.post_empty_file(self.repo.id, self.rel_path, name, self.username) except SearpcError as e: if e.msg == 'Invalid file name': raise DAVError(HTTP_BAD_REQUEST) raise # Repo was updated, can't use self.repo repo = seafile_api.get_repo(self.repo.id) if not repo: raise DAVError(HTTP_INTERNAL_ERROR) member_rel_path = "/".join([self.rel_path, name]) member_path = "/".join([self.path, name]) obj = resolveRepoPath(repo, member_rel_path) if not obj or not isinstance(obj, SeafFile): raise DAVError(HTTP_INTERNAL_ERROR) return SeafileResource(member_path, repo, member_rel_path, obj, self.environ)
def test_rename_folder_with_invalid_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit sub-folder with 'r' permission assert seafile_api.check_permission_by_path(self.repo_id, self.folder_path, self.admin_name) == 'r' # login as admin, then rename a 'r' permission folder self.login_as(self.admin) new_name = randstring(6) data = {'operation': 'rename', 'newname': new_name} resp = self.client.post(self.url + '?p=' + self.folder_path, data) self.assertEqual(403, resp.status_code)
def group_wiki_pages(request, group): """ List wiki pages in group. """ username = request.user.username try: repo = get_group_wiki_repo(group, username) pages = get_wiki_pages(repo) except SearpcError: return render_error(request, _('Internal Server Error')) except WikiDoesNotExist: return render_error(request, _('Wiki does not exists.')) if is_registered_user(username): repo_perm = seafile_api.check_permission_by_path( repo.id, '/', username) else: # when anonymous user visit public group wiki, set permission as 'r' repo_perm = 'r' mods_available = get_available_mods_by_group(group.id) mods_enabled = get_enabled_mods_by_group(group.id) return render_to_response("group/group_wiki_pages.html", { "group": group, "pages": pages, "is_staff": group.is_staff, "repo_id": repo.id, "search_repo_id": repo.id, "search_wiki": True, "repo_perm": repo_perm, "mods_enabled": mods_enabled, "mods_available": mods_available, }, context_instance=RequestContext(request))
def handle_move(self, dest_path): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) parts = dest_path.strip("/").split("/", 1) if len(parts) <= 1: raise DAVError(HTTP_BAD_REQUEST) repo_name = parts[0] rel_path = parts[1] dest_dir, dest_file = os.path.split(rel_path) dest_repo = getRepoByName(repo_name, self.username, self.org_id, self.is_guest) if seafile_api.check_permission_by_path(dest_repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) src_dir, src_file = os.path.split(self.rel_path) if not src_file: raise DAVError(HTTP_BAD_REQUEST) if not seafile_api.is_valid_filename(dest_repo.id, dest_file): raise DAVError(HTTP_BAD_REQUEST) # some clients such as GoodReader requires "overwrite" semantics file_id_dest = seafile_api.get_file_id_by_path(dest_repo.id, rel_path) if file_id_dest != None: seafile_api.del_file(dest_repo.id, dest_dir, dest_file, self.username) seafile_api.move_file(self.repo.id, src_dir, src_file, dest_repo.id, dest_dir, dest_file, 1, self.username, NEED_PROGRESS, SYNCHRONOUS) return True
def group_wiki_pages(request, group): """ List wiki pages in group. """ username = request.user.username try: repo = get_group_wiki_repo(group, username) pages = get_wiki_pages(repo) except SearpcError: return render_error(request, _('Internal Server Error')) except WikiDoesNotExist: return render_error(request, _('Wiki does not exists.')) if is_registered_user(username): repo_perm = seafile_api.check_permission_by_path(repo.id, '/', username) else: # when anonymous user visit public group wiki, set permission as 'r' repo_perm = 'r' mods_available = get_available_mods_by_group(group.id) mods_enabled = get_enabled_mods_by_group(group.id) return render_to_response("group/group_wiki_pages.html", { "group": group, "pages": pages, "is_staff": group.is_staff, "repo_id": repo.id, "search_repo_id": repo.id, "search_wiki": True, "repo_perm": repo_perm, "mods_enabled": mods_enabled, "mods_available": mods_available, }, context_instance=RequestContext(request))
def test_delete_file_with_invalid_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # create a file in user repo sub-folder file_name = randstring(6) seafile_api.post_empty_file(repo_id=self.repo_id, parent_dir=self.folder_path, filename=file_name, username=self.user_name) # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit file with 'r' permission file_path = posixpath.join(self.folder_path, file_name) assert seafile_api.check_permission_by_path(self.repo_id, file_path, self.admin_name) == 'r' # login as admin, then delete a 'r' permission file self.login_as(self.admin) resp = self.client.delete(self.url + '?p=' + file_path, {}, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code)
def group_wiki_pages(request, group): """ List wiki pages in group. """ username = request.user.username try: repo = get_group_wiki_repo(group, username) pages = get_wiki_pages(repo) except SearpcError: return render_error(request, _("Internal Server Error")) except WikiDoesNotExist: return render_error(request, _("Wiki does not exists.")) repo_perm = seafile_api.check_permission_by_path(repo.id, "/", username) mods_available = get_available_mods_by_group(group.id) mods_enabled = get_enabled_mods_by_group(group.id) return render_to_response( "group/group_wiki_pages.html", { "group": group, "pages": pages, "is_staff": group.is_staff, "repo_id": repo.id, "search_repo_id": repo.id, "search_wiki": True, "repo_perm": repo_perm, "mods_enabled": mods_enabled, "mods_available": mods_available, }, context_instance=RequestContext(request), )
def test_delete_user_share(self): self.share_repo_to_user() # admin user can view repo assert seafile_api.check_permission_by_path( self.repo_id, '/', self.admin_name) == 'rw' self.login_as(self.user) args = '?share_type=personal&user=%s' % self.admin_name url = reverse('api-v2.1-shared-repo', args=[self.repo_id]) + args resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) # admin user can NOT view repo assert seafile_api.check_permission_by_path( self.repo_id, '/', self.admin_name) == None
def test_delete_user_share(self): self.share_repo_to_user() # admin user can view repo assert seafile_api.check_permission_by_path(self.repo_id, '/', self.admin_name) == 'rw' self.login_as(self.user) args = '?share_type=personal&user=%s' % self.admin_name url = reverse('api-v2.1-shared-repo', args=[self.repo_id]) + args resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) # admin user can NOT view repo assert seafile_api.check_permission_by_path(self.repo_id, '/', self.admin_name) == None
def test_delete_repo_user_share_permission(self): # user share repo to tmp user init_permission = 'rw' seafile_api.share_repo(self.repo_id, self.user_name, self.tmp_user_email, init_permission) assert seafile_api.check_permission_by_path(self.repo_id, \ '/', self.tmp_user_email) == init_permission self.login_as(self.admin) data = 'repo_id=%s&share_type=%s&share_to=%s' % \ (self.repo_id, 'user', self.tmp_user_email) resp = self.client.delete(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) assert seafile_api.check_permission_by_path(self.repo_id, \ '/', self.tmp_user_email) is None
def put(self, request, token): """ This api only used for refresh OnlineOffice lock when user edit office file via share link. Permission checking: 1, If enable SHARE_LINK_LOGIN_REQUIRED, user must have been authenticated. 2, Share link should have can_edit permission. 3, File must have been locked by OnlineOffice. """ if SHARE_LINK_LOGIN_REQUIRED and \ not request.user.is_authenticated(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: share_link = FileShare.objects.get(token=token) except FileShare.DoesNotExist: error_msg = 'Share link %s not found.' % token return api_error(status.HTTP_404_NOT_FOUND, error_msg) if share_link.is_expired(): error_msg = 'Share link %s is expired.' % token return api_error(status.HTTP_400_BAD_REQUEST, error_msg) shared_by = share_link.username repo_id = share_link.repo_id path = normalize_file_path(share_link.path) parent_dir = os.path.dirname(path) if seafile_api.check_permission_by_path( repo_id, parent_dir, shared_by) != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) permissions = share_link.get_permissions() can_edit = permissions['can_edit'] if not can_edit: error_msg = 'Share link %s has no edit permission.' % token return api_error(status.HTTP_403_FORBIDDEN, error_msg) locked_by_online_office = if_locked_by_online_office(repo_id, path) if locked_by_online_office: # refresh lock file try: seafile_api.refresh_file_lock(repo_id, path) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) else: error_msg = _("You can not refresh this file's lock.") return api_error(status.HTTP_403_FORBIDDEN, error_msg) return Response({'success': True})
def handle_delete(self): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) parent, filename = os.path.split(self.rel_path) seafile_api.del_file(self.repo.id, parent, filename, self.username) return True
def handleDelete(self): if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) parent, filename = os.path.split(self.rel_path) seafile_api.del_file(self.repo.id, parent, filename, self.username) return True
def get(self, request, repo_id, format=None): # list dir repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) path = request.GET.get('p', '/') if path[-1] != '/': path = path + '/' try: dir_id = seafile_api.get_dir_id_by_path(repo_id, path) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not dir_id: error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if check_folder_permission(request, repo_id, path) is None: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) old_oid = request.GET.get('oid', None) if old_oid and old_oid == dir_id: resp = Response({'success': True}) resp["oid"] = dir_id return resp else: request_type = request.GET.get('t', None) if request_type and request_type not in ('f', 'd'): error_msg = "'t'(type) should be 'f' or 'd'." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if request_type == 'd': recursive = request.GET.get('recursive', '0') if recursive not in ('1', '0'): error_msg = "If you want to get recursive dir entries, you should set 'recursive' argument as '1'." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if recursive == '1': username = request.user.username dir_list = get_dir_recursively(username, repo_id, path, []) dir_list.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower())) resp = Response(dir_list) resp["oid"] = dir_id resp["dir_perm"] = seafile_api.check_permission_by_path(repo_id, path, username) return resp return get_dir_entrys_by_id(request, repo, path, dir_id, request_type)
def test_reshare_to_user_after_transfer_repo(self): tmp_user = '******' User.objects.create_user(tmp_user) # share user's repo to tmp_user with 'rw' permission seafile_api.share_repo(self.user_repo_id, self.user.username, tmp_user, 'rw') assert seafile_api.check_permission_by_path(self.user_repo_id, '/', tmp_user) == 'rw' self.login_as(self.user) url = reverse("api2-repo-owner", args=[self.user_repo_id]) data = 'owner=%s' % self.admin.email resp = self.client.put(url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) assert seafile_api.check_permission_by_path(self.user_repo_id, '/', tmp_user) == 'rw'
def set_user_folder_rw_permission_to_admin(self): # share user's repo to admin with 'r' permission seafile_api.share_repo(self.repo.id, self.user.username, self.admin.username, 'r') # set user sub-folder 'rw' permisson to admin seafile_api.add_folder_user_perm(self.repo.id, self.folder, 'rw', self.admin.username) # admin can visit user sub-folder with 'rw' permission assert seafile_api.check_permission_by_path(self.repo.id, self.folder, self.admin.username) == 'rw'
def post(self, request, repo_id, format=None): """Post a participant of a file. """ # argument check path = request.data.get('path') if not path: return api_error(status.HTTP_400_BAD_REQUEST, 'path invalid.') path = normalize_file_path(path) email = request.data.get('email') if not email or not is_valid_username(email): return api_error(status.HTTP_400_BAD_REQUEST, 'email invalid.') # resource check file_id = seafile_api.get_file_id_by_path(repo_id, path) if not file_id: return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found.' % path) try: user = User.objects.get(email=email) except User.DoesNotExist: return api_error(status.HTTP_404_NOT_FOUND, 'User %s not found.' % email) # permission check if not check_folder_permission(request, repo_id, '/'): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') if not seafile_api.check_permission_by_path(repo_id, '/', user.username): return api_error(status.HTTP_403_FORBIDDEN, _('%s Permission denied.') % email) # main try: file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap_by_path( repo_id, path, False) if FileParticipant.objects.get_participant(file_uuid, email): return api_error(status.HTTP_409_CONFLICT, _('Participant %s already exists.') % email) FileParticipant.objects.add_participant(file_uuid, email) participant = get_user_common_info(email) except Exception as e: logger.error(e) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error.') return Response(participant, status=201)
def check_folder_permission(request, repo_id, path): """Check repo/folder/file access permission of a user, always return 'rw' when repo is system repo and user is admin. Arguments: - `request`: - `repo_id`: - `path`: """ username = request.user.username if request.user.is_staff and get_system_default_repo_id() == repo_id: return 'rw' return seafile_api.check_permission_by_path(repo_id, path, username)
def test_update_perm_if_not_owner(self): self.share_repo_to_user() # admin can view repo but NOT owner assert seafile_api.check_permission_by_path(self.repo_id, '/', self.admin_name) == 'rw' self.login_as(self.admin) url = reverse('api-v2.1-shared-repo', args=[self.repo_id]) data = 'permission=r&share_type=personal' resp = self.client.put(url, data, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code)
def test_update_perm_if_not_owner(self): self.share_repo_to_user() # admin can view repo but NOT owner assert seafile_api.check_permission_by_path( self.repo_id, '/', self.admin_name) == 'rw' self.login_as(self.admin) url = reverse('api-v2.1-shared-repo', args=[self.repo_id]) data = 'permission=r&share_type=personal' resp = self.client.put(url, data, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code)
def view_shared_upload_link(request, uploadlink): token = uploadlink.token password_check_passed, err_msg = check_share_link_common(request, uploadlink, is_upload_link=True) if not password_check_passed: d = {'token': token, 'view_name': 'view_shared_upload_link', 'err_msg': err_msg} return render(request, 'share_access_validation.html', d) username = uploadlink.username repo_id = uploadlink.repo_id repo = get_repo(repo_id) if not repo: raise Http404 path = uploadlink.path if path == '/': # use repo name as dir name if share whole library dir_name = repo.name else: dir_name = os.path.basename(path[:-1]) repo = get_repo(repo_id) if not repo: raise Http404 if repo.encrypted or \ seafile_api.check_permission_by_path(repo_id, '/', username) != 'rw': return render_error(request, _('Permission denied')) uploadlink.view_cnt = F('view_cnt') + 1 uploadlink.save() no_quota = True if seaserv.check_quota(repo_id) < 0 else False return render(request, 'view_shared_upload_link_react.html', { #return render(request, 'view_shared_upload_link.html', { 'repo': repo, 'path': path, 'username': username, 'dir_name': dir_name, 'max_upload_file_size': seaserv.MAX_UPLOAD_FILE_SIZE, 'no_quota': no_quota, 'uploadlink': uploadlink, 'enable_upload_folder': ENABLE_UPLOAD_FOLDER, 'enable_resumable_fileupload': ENABLE_RESUMABLE_FILEUPLOAD, 'max_number_of_files_for_fileupload': MAX_NUMBER_OF_FILES_FOR_FILEUPLOAD, })
def put(self, request, token): """ This api only used for refresh OnlineOffice lock when user edit office file via share link. Permission checking: 1, If enable SHARE_LINK_LOGIN_REQUIRED, user must have been authenticated. 2, Share link should have can_edit permission. 3, File must have been locked by OnlineOffice. """ if SHARE_LINK_LOGIN_REQUIRED and \ not request.user.is_authenticated(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: share_link = FileShare.objects.get(token=token) except FileShare.DoesNotExist: error_msg = 'Share link %s not found.' % token return api_error(status.HTTP_404_NOT_FOUND, error_msg) if share_link.is_expired(): error_msg = 'Share link %s is expired.' % token return api_error(status.HTTP_400_BAD_REQUEST, error_msg) shared_by = share_link.username repo_id = share_link.repo_id path = normalize_file_path(share_link.path) parent_dir = os.path.dirname(path) if seafile_api.check_permission_by_path(repo_id, parent_dir, shared_by) != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) permissions = share_link.get_permissions() can_edit = permissions['can_edit'] if not can_edit: error_msg = 'Share link %s has no edit permission.' % token return api_error(status.HTTP_403_FORBIDDEN, error_msg) locked_by_online_office = if_locked_by_online_office(repo_id, path) if locked_by_online_office: # refresh lock file try: seafile_api.refresh_file_lock(repo_id, path) except SearpcError, e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
def get(self, request, token): """ Get file upload url according to upload link token. Permission checking: 1. anyone has the upload link token can perform this action; """ try: uls = UploadLinkShare.objects.get(token=token) except UploadLinkShare.DoesNotExist: error_msg = 'token %s not found.' % token return api_error(status.HTTP_404_NOT_FOUND, error_msg) # currently not support encrypted upload link if uls.is_encrypted(): error_msg = 'Upload link %s is encrypted.' % token return api_error(status.HTTP_403_FORBIDDEN, error_msg) repo_id = uls.repo_id repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) path = uls.path dir_id = seafile_api.get_dir_id_by_path(repo_id, path) if not dir_id: error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if repo.encrypted or \ seafile_api.check_permission_by_path(repo_id, '/', uls.username) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) obj_id = json.dumps({'parent_dir': path}) token = seafile_api.get_fileserver_access_token(repo_id, obj_id, 'upload-link', uls.username, use_onetime=False) if not token: error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) result = {} result['upload_link'] = gen_file_upload_url(token, 'upload-api') return Response(result)
def test_unshare_with_invalid_ownership(self): self.share_repo_to_user_and_group() # admin can visit user sub-folder with 'rw' permission assert seafile_api.check_permission_by_path(self.repo.id, '/', self.admin.username) == 'rw' self.login_as(self.admin) resp = self.client.delete('/api2/repos/%s/dir/shared_items/?p=/&share_type=user&username=%s' % ( self.repo.id, self.admin.username )) self.assertEqual(403, resp.status_code)
def get_folder_permission_recursively(username, repo_id, path): """ Get folder permission recursively Ger permission from the innermost layer of subdirectories to root directory. """ if not path or not isinstance(path, basestring): raise Exception('path invalid.') if not seafile_api.get_dir_id_by_path(repo_id, path): # get current folder's parent directory path = os.path.dirname(path.rstrip('/')) return get_folder_permission_recursively(username, repo_id, path) else: return seafile_api.check_permission_by_path(repo_id, path, username)
def view_shared_upload_link(request, uploadlink): token = uploadlink.token password_check_passed, err_msg = check_share_link_common(request, uploadlink, is_upload_link=True) if not password_check_passed: d = {'token': token, 'view_name': 'view_shared_upload_link', 'err_msg': err_msg} return render(request, 'share_access_validation.html', d) username = uploadlink.username repo_id = uploadlink.repo_id repo = get_repo(repo_id) if not repo: raise Http404 path = uploadlink.path if path == '/': # use repo name as dir name if share whole library dir_name = repo.name else: dir_name = os.path.basename(path[:-1]) repo = get_repo(repo_id) if not repo: raise Http404 if repo.encrypted or \ seafile_api.check_permission_by_path(repo_id, '/', username) != 'rw': return render_error(request, _(u'Permission denied')) uploadlink.view_cnt = F('view_cnt') + 1 uploadlink.save() no_quota = True if seaserv.check_quota(repo_id) < 0 else False return render(request, 'view_shared_upload_link.html', { 'repo': repo, 'path': path, 'username': username, 'dir_name': dir_name, 'max_upload_file_size': seaserv.MAX_UPLOAD_FILE_SIZE, 'no_quota': no_quota, 'uploadlink': uploadlink, 'enable_upload_folder': ENABLE_UPLOAD_FOLDER, 'enable_resumable_fileupload': ENABLE_RESUMABLE_FILEUPLOAD, 'max_number_of_files_for_fileupload': MAX_NUMBER_OF_FILES_FOR_FILEUPLOAD, })
def test_share_with_invalid_ownership(self): self.share_repo_to_user_and_group() # admin can visit user sub-folder with 'rw' permission assert seafile_api.check_permission_by_path(self.repo.id, '/', self.admin.username) == 'rw' self.login_as(self.admin) resp = self.client.put( '/api2/repos/%s/dir/shared_items/?p=/' % self.repo.id, "share_type=user&username=%s" % self.admin.username, 'application/x-www-form-urlencoded', ) self.assertEqual(403, resp.status_code)
def create_collection(self, name): """Create a new collection as member of self. See DAVResource.createCollection() """ assert not "/" in name if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if not seafile_api.is_valid_filename(self.repo.id, name): raise DAVError(HTTP_BAD_REQUEST) seafile_api.post_dir(self.repo.id, self.rel_path, name, self.username)
def createCollection(self, name): """Create a new collection as member of self. See DAVResource.createCollection() """ assert not "/" in name if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if not seafile_api.is_valid_filename(self.repo.id, name): raise DAVError(HTTP_BAD_REQUEST) seafile_api.post_dir(self.repo.id, self.rel_path, name, self.username)
def get(self, request, token): """ Get file upload url according to upload link token. Permission checking: 1. anyone has the upload link token can perform this action; """ try: uls = UploadLinkShare.objects.get(token=token) except UploadLinkShare.DoesNotExist: error_msg = 'token %s not found.' % token return api_error(status.HTTP_404_NOT_FOUND, error_msg) # currently not support encrypted upload link if uls.is_encrypted(): error_msg = 'Upload link %s is encrypted.' % token return api_error(status.HTTP_403_FORBIDDEN, error_msg) repo_id = uls.repo_id repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) path = uls.path dir_id = seafile_api.get_dir_id_by_path(repo_id, path) if not dir_id: error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if repo.encrypted or \ seafile_api.check_permission_by_path(repo_id, '/', uls.username) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) token = seafile_api.get_fileserver_access_token(repo_id, dir_id, 'upload-link', uls.username, use_onetime=False) if not token: error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) result = {} result['upload_link'] = gen_file_upload_url(token, 'upload-api') return Response(result)
def beginWrite(self, contentType=None, isnewfile=True, contentlength=-1): """Open content as a stream for writing. See DAVResource.beginWrite() """ assert not self.isCollection if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if not self.check_repo_owner_quota(isnewfile, contentlength): raise DAVError(HTTP_FORBIDDEN, "The quota of the repo owner is exceeded") fd, path = tempfile.mkstemp(dir=self.provider.tmpdir) self.tmpfile_path = path return os.fdopen(fd, "wb")
def begin_write(self, content_type=None, isnewfile=True, contentlength=-1): """Open content as a stream for writing. See DAVResource.beginWrite() """ assert not self.is_collection if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if not self.check_repo_owner_quota(isnewfile, contentlength): raise DAVError(HTTP_FORBIDDEN, "The quota of the repo owner is exceeded") fd, path = tempfile.mkstemp(dir=self.provider.tmpdir) self.tmpfile_path = path return os.fdopen(fd, "wb")
def createEmptyResource(self, name): """Create an empty (length-0) resource. See DAVResource.createEmptyResource() """ assert not "/" in name if self.provider.readonly: raise DAVError(HTTP_FORBIDDEN) if seafile_api.check_permission_by_path(self.repo.id, self.rel_path, self.username) != "rw": raise DAVError(HTTP_FORBIDDEN) if check_repo_quota(self.repo.id) < 0: raise DAVError(HTTP_FORBIDDEN, "The quota of the repo owner is exceeded") try: seafile_api.post_empty_file(self.repo.id, self.rel_path, name, self.username) except SearpcError, e: if e.msg == 'Invalid file name': raise DAVError(HTTP_BAD_REQUEST) raise
def test_modify_repo_user_share_permission_to_admin(self): # user share repo to tmp user init_permission = 'rw' seafile_api.share_repo(self.repo_id, self.user_name, self.tmp_user_email, init_permission) assert seafile_api.check_permission_by_path(self.repo_id, \ '/', self.tmp_user_email) == init_permission self.login_as(self.admin) modified_perm = 'admin' data = 'repo_id=%s&share_type=%s&permission=%s&share_to=%s' % \ (self.repo_id, 'user', modified_perm, self.tmp_user_email) resp = self.client.put(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) json_resp = json.loads(resp.content) assert json_resp['permission'] == 'rw' assert json_resp['is_admin'] == True assert json_resp['user_email'] == self.tmp_user_email
def test_copy_file_with_invalid_dst_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit sub-folder with 'r' permission assert seafile_api.check_permission_by_path(self.repo_id, self.folder_path, self.admin_name) == 'r' # create a file for admin repo admin_repo_id = self.admin_create_new_repo() admin_file_name = randstring(6) seafile_api.post_empty_file(repo_id=admin_repo_id, parent_dir='/', filename=admin_file_name, username=self.admin_name) # login as admin, then move file to a 'r' permission folder self.login_as(self.admin) # create new repo for admin data = { 'operation': 'copy', 'dst_repo': self.repo_id, 'dst_dir': self.folder_path, } url = reverse('api-v2.1-file-view', args=[admin_repo_id]) resp = self.client.post(url + '?p=/' + admin_file_name, data) self.assertEqual(403, resp.status_code)
def test_delete_folder_with_invalid_folder_perm(self): if not LOCAL_PRO_DEV_ENV: return # share user's repo to admin with 'rw' permission seafile_api.share_repo(self.repo_id, self.user_name, self.admin_name, 'rw') # set sub-folder permisson as 'r' for admin seafile_api.add_folder_user_perm(self.repo_id, self.folder_path, 'r', self.admin_name) # admin can visit sub-folder with 'r' permission assert seafile_api.check_permission_by_path(self.repo_id, self.folder_path, self.admin_name) == 'r' # login as admin, then delete a 'r' permission folder self.login_as(self.admin) resp = self.client.delete(self.url + '?p=' + self.folder_path, {}, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code)
def delete(self, request, repo_id, format=None): username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) path = request.GET.get('p', '/') if seafile_api.get_dir_id_by_path(repo.id, path) is None: return api_error(status.HTTP_404_NOT_FOUND, 'Folder %s not found.' % path) if username != self.get_repo_owner(request, repo_id): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') shared_to_user, shared_to_group = self.handle_shared_to_args(request) if path == '/': shared_repo = repo else: try: sub_repo = self.get_sub_repo_by_path(request, repo, path) if sub_repo: shared_repo = sub_repo else: return api_error(status.HTTP_404_NOT_FOUND, 'Sub-library not found.') except SearpcError as e: logger.error(e) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Failed to get sub-library.') if shared_to_user: shared_to = request.GET.get('username') if shared_to is None or not is_valid_username(shared_to): return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % shared_to) try: User.objects.get(email=shared_to) except User.DoesNotExist: return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid user, should be registered') if is_org_context(request): org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.org_remove_share( org_id, shared_repo.id, username, shared_to) else: seaserv.remove_share(shared_repo.id, username, shared_to) permission = seafile_api.check_permission_by_path(repo.id, path, shared_to) send_perm_audit_msg('delete-repo-perm', username, shared_to, repo_id, path, permission) if shared_to_group: group_id = request.GET.get('group_id') try: group_id = int(group_id) except ValueError: return api_error(status.HTTP_400_BAD_REQUEST, 'group_id %s invalid' % group_id) # hacky way to get group repo permission permission = '' for e in seafile_api.list_repo_shared_group_by_user(username, shared_repo.id): if e.group_id == group_id: permission = e.perm break if is_org_context(request): org_id = request.user.org.org_id seaserv.del_org_group_repo(shared_repo.id, org_id, group_id) else: seafile_api.unset_group_repo(shared_repo.id, group_id, username) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, path, permission) return HttpResponse(json.dumps({'success': True}), status=200, content_type=json_content_type)
def delete(self, request, repo_id, format=None): """ Unshare a repo. Permission checking: 1. Only repo owner can unshare a library. """ # argument check share_type = request.GET.get('share_type', None) if not share_type: error_msg = 'share_type invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if share_type not in ('personal', 'group', 'public'): error_msg = "share_type can only be 'personal' or 'group' or 'public'." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) # permission check username = request.user.username if is_org_context(request): repo_owner = seafile_api.get_org_repo_owner(repo_id) else: repo_owner = seafile_api.get_repo_owner(repo_id) if username != repo_owner: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # delete share org_id = None if is_org_context(request): org_id = request.user.org.org_id if share_type == 'personal': user = request.GET.get('user', None) if not user or not is_valid_username(user): error_msg = 'user invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # if user not found, permission will be None permission = seafile_api.check_permission_by_path( repo_id, '/', user) try: if org_id: seafile_api.org_remove_share(org_id, repo_id, username, user) else: seafile_api.remove_share(repo_id, username, user) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, user, repo_id, '/', permission) if share_type == 'group': group_id = request.GET.get('group_id', None) if not group_id: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: group_id = int(group_id) except ValueError: error_msg = 'group_id must be integer.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # hacky way to get group repo permission permission = '' if org_id: for e in seafile_api.list_org_repo_shared_group( org_id, username, repo_id): if e.group_id == group_id: permission = e.perm break else: for e in seafile_api.list_repo_shared_group_by_user(username, repo_id): if e.group_id == group_id: permission = e.perm break try: if org_id: seaserv.del_org_group_repo(repo_id, org_id, group_id) else: seafile_api.unset_group_repo(repo_id, group_id, username) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, '/', permission) if share_type == 'public': pub_repos = [] if org_id: pub_repos = seaserv.list_org_inner_pub_repos(org_id, username) if not request.cloud_mode: pub_repos = seaserv.list_inner_pub_repos(username) try: if org_id: seaserv.seafserv_threaded_rpc.unset_org_inner_pub_repo(org_id, repo_id) else: seafile_api.remove_inner_pub_repo(repo_id) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) permission = '' for repo in pub_repos: if repo.repo_id == repo_id: permission = repo.permission break if permission: send_perm_audit_msg('delete-repo-perm', username, 'all', repo_id, '/', permission) return Response({'success': True})
else: is_owner = False cur_path = path for commit in commits: commit.path = cur_path if commit.rev_renamed_old_path: cur_path = '/' + commit.rev_renamed_old_path zipped = gen_path_link(path, repo.name) can_revert_file = True username = request.user.username is_locked, locked_by_me = check_file_lock(repo_id, path, username) if seafile_api.check_permission_by_path(repo_id, path, username) != 'rw' or \ (is_locked and not locked_by_me): can_revert_file = False return render_to_response('file_revisions.html', { 'repo': repo, 'path': path, 'u_filename': u_filename, 'zipped': zipped, 'commits': commits, 'is_owner': is_owner, 'can_compare': can_compare, 'can_revert_file': can_revert_file, 'days': days, }, context_instance=RequestContext(request))