# HG changeset patch # User Søren Løvborg # Date 1487607805 -3600 # Node ID a17c8e5f6712eac28ce9db16d34c9cb41dda56d6 # Parent 3505a6be29884d45115e5d123edfa55ac2dab51a auth: simplify repository permission checks In practice, Kallithea has the 'repository.admin' permission imply the 'repository.write' permission, which again implies 'repository.read'. This codifies/enforces this practice by replacing HasRepoPermissionAny "perm function" with the new HasRepositoryLevel function, reducing the risk of errors and saving quite a lot of typing. diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/admin/repos.py --- a/kallithea/controllers/admin/repos.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/admin/repos.py Mon Feb 20 17:23:25 2017 +0100 @@ -37,7 +37,7 @@ from kallithea.config.routing import url from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, \ - HasRepoPermissionAnyDecorator, NotAnonymous, HasPermissionAny + HasRepoPermissionLevelDecorator, NotAnonymous, HasPermissionAny from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.utils import action_logger from kallithea.lib.vcs import RepositoryError @@ -100,7 +100,7 @@ def index(self, format='html'): _list = Repository.query(sorted=True).all() - c.repos_list = RepoList(_list, perm_set=['repository.admin']) + c.repos_list = RepoList(_list, perm_level='admin') repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list, admin=True, super_user_actions=True) @@ -212,7 +212,7 @@ return {'result': True} return {'result': False} - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def update(self, repo_name): c.repo_info = self._load_repo() self.__load_defaults(c.repo_info) @@ -261,7 +261,7 @@ % repo_name, category='error') raise HTTPFound(location=url('edit_repo', repo_name=changed_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def delete(self, repo_name): repo_model = RepoModel() repo = repo_model.get_by_repo_name(repo_name) @@ -298,7 +298,7 @@ raise HTTPFound(location=url('repos_group_home', group_name=repo.group.group_name)) raise HTTPFound(location=url('repos')) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit(self, repo_name): defaults = self.__load_data() c.repo_fields = RepositoryField.query() \ @@ -312,7 +312,7 @@ encoding="UTF-8", force_defaults=False) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_permissions(self, repo_name): c.repo_info = self._load_repo() repo_model = RepoModel() @@ -363,7 +363,7 @@ category='error') raise HTTPInternalServerError() - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_fields(self, repo_name): c.repo_info = self._load_repo() c.repo_fields = RepositoryField.query() \ @@ -374,7 +374,7 @@ raise HTTPFound(location=url('repo_edit_fields')) return render('admin/repos/repo_edit.html') - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def create_repo_field(self, repo_name): try: form_result = RepoFieldForm()().to_python(dict(request.POST)) @@ -395,7 +395,7 @@ h.flash(msg, category='error') raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def delete_repo_field(self, repo_name, field_id): field = RepositoryField.get_or_404(field_id) try: @@ -407,7 +407,7 @@ h.flash(msg, category='error') raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_advanced(self, repo_name): c.repo_info = self._load_repo() c.default_user_id = User.get_default_user().user_id @@ -416,7 +416,7 @@ .filter(UserFollowing.follows_repository == c.repo_info).scalar() _repos = Repository.query(sorted=True).all() - read_access_repos = RepoList(_repos) + read_access_repos = RepoList(_repos, perm_level='read') c.repos_list = [(None, _('-- Not a fork --'))] c.repos_list += [(x.repo_id, x.repo_name) for x in read_access_repos @@ -435,7 +435,7 @@ encoding="UTF-8", force_defaults=False) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_advanced_journal(self, repo_name): """ Sets this repository to be visible in public journal, @@ -458,7 +458,7 @@ raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_advanced_fork(self, repo_name): """ Mark given repository as a fork of another @@ -483,7 +483,7 @@ raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_advanced_locking(self, repo_name): """ Unlock repository when it is locked ! @@ -504,7 +504,7 @@ category='error') raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @HasRepoPermissionLevelDecorator('write') def toggle_locking(self, repo_name): try: repo = Repository.get_by_repo_name(repo_name) @@ -523,7 +523,7 @@ category='error') raise HTTPFound(location=url('summary_home', repo_name=repo_name)) - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_caches(self, repo_name): c.repo_info = self._load_repo() c.active = 'caches' @@ -541,7 +541,7 @@ raise HTTPFound(location=url('edit_repo_caches', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html') - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_remote(self, repo_name): c.repo_info = self._load_repo() c.active = 'remote' @@ -556,7 +556,7 @@ raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html') - @HasRepoPermissionAnyDecorator('repository.admin') + @HasRepoPermissionLevelDecorator('admin') def edit_statistics(self, repo_name): c.repo_info = self._load_repo() repo = c.repo_info.scm_instance diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/api/api.py --- a/kallithea/controllers/api/api.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/api/api.py Mon Feb 20 17:23:25 2017 +0100 @@ -35,7 +35,7 @@ from kallithea.controllers.api import JSONRPCController, JSONRPCError from kallithea.lib.auth import ( PasswordGenerator, AuthUser, HasPermissionAnyDecorator, - HasPermissionAnyDecorator, HasPermissionAny, HasRepoPermissionAny, + HasPermissionAnyDecorator, HasPermissionAny, HasRepoPermissionLevel, HasRepoGroupPermissionAny, HasUserGroupPermissionAny) from kallithea.lib.utils import map_groups, repo2db_mapper from kallithea.lib.utils2 import ( @@ -277,10 +277,7 @@ """ repo = get_repo_or_error(repoid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - if not HasRepoPermissionAny('repository.admin', - 'repository.write')( - repo_name=repo.repo_name): + if not HasRepoPermissionLevel('write')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) try: @@ -342,8 +339,7 @@ repo = get_repo_or_error(repoid) if HasPermissionAny('hg.admin')(): pass - elif HasRepoPermissionAny('repository.admin', - 'repository.write')(repo_name=repo.repo_name): + elif HasRepoPermissionLevel('write')(repo.repo_name): # make sure normal user does not pass someone else userid, # he is not allowed to do that if not isinstance(userid, Optional) and userid != request.authuser.user_id: @@ -1204,9 +1200,7 @@ repo = get_repo_or_error(repoid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - perms = ('repository.admin', 'repository.write', 'repository.read') - if not HasRepoPermissionAny(*perms)(repo_name=repo.repo_name): + if not HasRepoPermissionLevel('read')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) members = [] @@ -1314,9 +1308,7 @@ repo = get_repo_or_error(repoid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - perms = ('repository.admin', 'repository.write', 'repository.read') - if not HasRepoPermissionAny(*perms)(repo_name=repo.repo_name): + if not HasRepoPermissionLevel('read')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) ret_type = Optional.extract(ret_type) @@ -1492,8 +1484,7 @@ """ repo = get_repo_or_error(repoid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - if not HasRepoPermissionAny('repository.admin')(repo_name=repo.repo_name): + if not HasRepoPermissionLevel('admin')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) if (name != repo.repo_name and @@ -1590,9 +1581,7 @@ if HasPermissionAny('hg.admin')(): pass - elif HasRepoPermissionAny('repository.admin', - 'repository.write', - 'repository.read')(repo_name=repo.repo_name): + elif HasRepoPermissionLevel('read')(repo.repo_name): if not isinstance(owner, Optional): # forbid setting owner for non-admins raise JSONRPCError( @@ -1669,8 +1658,7 @@ repo = get_repo_or_error(repoid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - if not HasRepoPermissionAny('repository.admin')(repo_name=repo.repo_name): + if not HasRepoPermissionLevel('admin')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) try: @@ -1821,10 +1809,7 @@ perm = get_perm_or_error(perm) user_group = get_user_group_or_error(usergroupid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - _perms = ('repository.admin',) - if not HasRepoPermissionAny(*_perms)( - repo_name=repo.repo_name): + if not HasRepoPermissionLevel('admin')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) # check if we have at least read permission for this user group ! @@ -1877,10 +1862,7 @@ repo = get_repo_or_error(repoid) user_group = get_user_group_or_error(usergroupid) if not HasPermissionAny('hg.admin')(): - # check if we have admin permission for this repo ! - _perms = ('repository.admin',) - if not HasRepoPermissionAny(*_perms)( - repo_name=repo.repo_name): + if not HasRepoPermissionLevel('admin')(repo.repo_name): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) # check if we have at least read permission for this user group ! diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/changelog.py --- a/kallithea/controllers/changelog.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/changelog.py Mon Feb 20 17:23:25 2017 +0100 @@ -34,7 +34,7 @@ import kallithea.lib.helpers as h from kallithea.config.routing import url -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib.base import BaseRepoController, render from kallithea.lib.compat import json from kallithea.lib.graphmod import graph_data @@ -92,8 +92,7 @@ raise HTTPBadRequest() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self, repo_name, revision=None, f_path=None): # Fix URL after page size form submission via GET # TODO: Somehow just don't send this extra junk in the GET URL @@ -179,8 +178,7 @@ return render('changelog/changelog.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def changelog_details(self, cs): if request.environ.get('HTTP_X_PARTIAL_XHR'): c.cs = c.db_repo_scm_instance.get_changeset(cs) @@ -188,8 +186,7 @@ raise HTTPNotFound() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def changelog_summary(self, repo_name): if request.environ.get('HTTP_X_PARTIAL_XHR'): _load_changelog_summary() diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/changeset.py --- a/kallithea/controllers/changeset.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/changeset.py Mon Feb 20 17:23:25 2017 +0100 @@ -38,7 +38,7 @@ from kallithea.lib.compat import json import kallithea.lib.helpers as h -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \ NotAnonymous from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.utils import action_logger @@ -337,33 +337,28 @@ return render('changeset/changeset_range.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self, revision, method='show'): return self._index(revision, method=method) @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def changeset_raw(self, revision): return self._index(revision, method='raw') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def changeset_patch(self, revision): return self._index(revision, method='patch') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def changeset_download(self, revision): return self._index(revision, method='download') @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def comment(self, repo_name, revision): assert request.environ.get('HTTP_X_PARTIAL_XHR') @@ -414,15 +409,14 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get_or_404(comment_id) if co.repo.repo_name != repo_name: raise HTTPNotFound() owner = co.author_id == request.authuser.user_id - repo_admin = h.HasRepoPermissionAny('repository.admin')(repo_name) + repo_admin = h.HasRepoPermissionLevel('admin')(repo_name) if h.HasPermissionAny('hg.admin')() or repo_admin or owner: ChangesetCommentsModel().delete(comment=co) Session().commit() @@ -431,8 +425,7 @@ raise HTTPForbidden() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def changeset_info(self, repo_name, revision): if request.is_xhr: @@ -444,8 +437,7 @@ raise HTTPBadRequest() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def changeset_children(self, repo_name, revision): if request.is_xhr: @@ -458,8 +450,7 @@ raise HTTPBadRequest() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def changeset_parents(self, repo_name, revision): if request.is_xhr: diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/compare.py --- a/kallithea/controllers/compare.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/compare.py Mon Feb 20 17:23:25 2017 +0100 @@ -39,7 +39,7 @@ from kallithea.lib.vcs.utils.hgcompat import unionrepo from kallithea.lib import helpers as h from kallithea.lib.base import BaseRepoController, render -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib import diffs from kallithea.model.db import Repository from kallithea.lib.diffs import LimitedDiffContainer @@ -168,16 +168,14 @@ return other_changesets, org_changesets, ancestors @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self, repo_name): c.compare_home = True c.a_ref_name = c.cs_ref_name = _('Select changeset') return render('compare/compare_diff.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type, other_ref_name): org_ref_name = org_ref_name.strip() other_ref_name = other_ref_name.strip() diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/feed.py --- a/kallithea/controllers/feed.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/feed.py Mon Feb 20 17:23:25 2017 +0100 @@ -36,7 +36,7 @@ from kallithea import CONFIG from kallithea.lib import helpers as h -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib.base import BaseRepoController from kallithea.lib.diffs import DiffProcessor, LimitedDiffContainer from kallithea.model.db import CacheInvalidation @@ -52,8 +52,7 @@ class FeedController(BaseRepoController): @LoginRequired(api_access=True) - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def __before__(self): super(FeedController, self).__before__() diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/files.py --- a/kallithea/controllers/files.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/files.py Mon Feb 20 17:23:25 2017 +0100 @@ -44,7 +44,7 @@ from kallithea.lib.compat import OrderedDict from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_str, \ str2bool, safe_int -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.lib.vcs.conf import settings @@ -125,8 +125,7 @@ return file_node @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self, repo_name, revision, f_path, annotate=False): # redirect to given revision from form if given post_revision = request.POST.get('at_rev', None) @@ -199,8 +198,7 @@ return render('files/files.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def history(self, repo_name, revision, f_path): changeset = self.__get_cs(revision) @@ -222,8 +220,7 @@ return data @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def authors(self, repo_name, revision, f_path): changeset = self.__get_cs(revision) _file = changeset.get_node(f_path) @@ -235,8 +232,7 @@ return render('files/files_history_box.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def rawfile(self, repo_name, revision, f_path): cs = self.__get_cs(revision) file_node = self.__get_filenode(cs, f_path) @@ -248,8 +244,7 @@ return file_node.content @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def raw(self, repo_name, revision, f_path): cs = self.__get_cs(revision) file_node = self.__get_filenode(cs, f_path) @@ -295,7 +290,7 @@ return file_node.content @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @HasRepoPermissionLevelDecorator('write') def delete(self, repo_name, revision, f_path): repo = c.db_repo if repo.enable_locking and repo.locked[0]: @@ -355,7 +350,7 @@ return render('files/files_delete.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @HasRepoPermissionLevelDecorator('write') def edit(self, repo_name, revision, f_path): repo = c.db_repo if repo.enable_locking and repo.locked[0]: @@ -421,7 +416,7 @@ return render('files/files_edit.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @HasRepoPermissionLevelDecorator('write') def add(self, repo_name, revision, f_path): repo = c.db_repo @@ -502,8 +497,7 @@ return render('files/files_add.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def archivefile(self, repo_name, fname): fileformat = None revision = None @@ -589,8 +583,7 @@ return get_chunked_archive(archive_path) @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def diff(self, repo_name, f_path): ignore_whitespace = request.GET.get('ignorews') == '1' line_context = safe_int(request.GET.get('context'), 3) @@ -693,8 +686,7 @@ return render('files/file_diff.html') @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def diff_2way(self, repo_name, f_path): diff1 = request.GET.get('diff1', '') diff2 = request.GET.get('diff2', '') @@ -781,8 +773,7 @@ return hist_l, changesets @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def nodelist(self, repo_name, revision, f_path): if request.environ.get('HTTP_X_PARTIAL_XHR'): diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/followers.py --- a/kallithea/controllers/followers.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/followers.py Mon Feb 20 17:23:25 2017 +0100 @@ -29,7 +29,7 @@ from pylons import tmpl_context as c, request -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib.base import BaseRepoController, render from kallithea.lib.page import Page from kallithea.lib.utils2 import safe_int @@ -44,8 +44,7 @@ super(FollowersController, self).__before__() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def followers(self, repo_name): p = safe_int(request.GET.get('page'), 1) repo_id = c.db_repo.repo_id diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/forks.py --- a/kallithea/controllers/forks.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/forks.py Mon Feb 20 17:23:25 2017 +0100 @@ -37,8 +37,8 @@ import kallithea.lib.helpers as h from kallithea.config.routing import url -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ - NotAnonymous, HasRepoPermissionAny, HasPermissionAnyDecorator, HasPermissionAny +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \ + NotAnonymous, HasRepoPermissionLevel, HasPermissionAnyDecorator, HasPermissionAny from kallithea.lib.base import BaseRepoController, render from kallithea.lib.page import Page from kallithea.lib.utils2 import safe_int @@ -108,16 +108,13 @@ return defaults @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def forks(self, repo_name): p = safe_int(request.GET.get('page'), 1) repo_id = c.db_repo.repo_id d = [] for r in Repository.get_repo_forks(repo_id): - if not HasRepoPermissionAny( - 'repository.read', 'repository.write', 'repository.admin' - )(r.repo_name, 'get forks check'): + if not HasRepoPermissionLevel('read')(r.repo_name, 'get forks check'): continue d.append(r) c.forks_pager = Page(d, page=p, items_per_page=20) @@ -130,8 +127,7 @@ @LoginRequired() @NotAnonymous() @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def fork(self, repo_name): c.repo_info = Repository.get_by_repo_name(repo_name) if not c.repo_info: @@ -149,8 +145,7 @@ @LoginRequired() @NotAnonymous() @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository') - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def fork_create(self, repo_name): self.__load_defaults() c.repo_info = Repository.get_by_repo_name(repo_name) diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/home.py --- a/kallithea/controllers/home.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/home.py Mon Feb 20 17:23:25 2017 +0100 @@ -35,7 +35,7 @@ from kallithea.lib.utils import conditional_cache from kallithea.lib.compat import json -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator from kallithea.lib.base import BaseController, render, jsonify from kallithea.model.db import Repository, RepoGroup from kallithea.model.repo import RepoModel @@ -113,8 +113,7 @@ raise HTTPBadRequest() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def repo_refs_data(self, repo_name): repo = Repository.get_by_repo_name(repo_name).scm_instance diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/pullrequests.py --- a/kallithea/controllers/pullrequests.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/pullrequests.py Mon Feb 20 17:23:25 2017 +0100 @@ -37,7 +37,7 @@ from kallithea.config.routing import url from kallithea.lib import helpers as h from kallithea.lib import diffs -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \ NotAnonymous from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.compat import json, OrderedDict @@ -190,8 +190,7 @@ return request.authuser.admin or owner or reviewer @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def show_all(self, repo_name): c.from_ = request.GET.get('from_') or '' c.closed = request.GET.get('closed') or '' @@ -236,8 +235,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self): org_repo = c.db_repo org_scm_instance = org_repo.scm_instance @@ -293,8 +291,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def repo_info(self, repo_name): repo = c.db_repo @@ -307,8 +304,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def create(self, repo_name): repo = c.db_repo try: @@ -513,8 +509,7 @@ # pullrequest_post for PR editing @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def post(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) if pull_request.is_closed(): @@ -522,7 +517,7 @@ assert pull_request.other_repo.repo_name == repo_name #only owner or admin can update it owner = pull_request.owner_id == request.authuser.user_id - repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) + repo_admin = h.HasRepoPermissionLevel('admin')(c.repo_name) if not (h.HasPermissionAny('hg.admin')() or repo_admin or owner): raise HTTPForbidden() @@ -571,8 +566,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def delete(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) @@ -586,8 +580,7 @@ raise HTTPForbidden() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def show(self, repo_name, pull_request_id, extra=None): repo_model = RepoModel() c.users_array = repo_model.get_users_js() @@ -775,8 +768,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def comment(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) @@ -800,8 +792,8 @@ if delete == "delete": if (pull_request.owner_id == request.authuser.user_id or h.HasPermissionAny('hg.admin')() or - h.HasRepoPermissionAny('repository.admin')(pull_request.org_repo.repo_name) or - h.HasRepoPermissionAny('repository.admin')(pull_request.other_repo.repo_name) + h.HasRepoPermissionLevel('admin')(pull_request.org_repo.repo_name) or + h.HasRepoPermissionLevel('admin')(pull_request.other_repo.repo_name) ) and not pull_request.is_closed(): PullRequestModel().delete(pull_request) Session().commit() @@ -861,8 +853,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get(comment_id) @@ -871,7 +862,7 @@ raise HTTPForbidden() owner = co.author_id == request.authuser.user_id - repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) + repo_admin = h.HasRepoPermissionLevel('admin')(c.repo_name) if h.HasPermissionAny('hg.admin')() or repo_admin or owner: ChangesetCommentsModel().delete(comment=co) Session().commit() diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/controllers/summary.py --- a/kallithea/controllers/summary.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/controllers/summary.py Mon Feb 20 17:23:25 2017 +0100 @@ -43,7 +43,7 @@ from kallithea.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP from kallithea.model.db import Statistics, CacheInvalidation, User from kallithea.lib.utils2 import safe_str -from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ +from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator, \ NotAnonymous from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.vcs.backends.base import EmptyChangeset @@ -107,8 +107,7 @@ return _get_readme_from_cache(repo_name, kind) @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def index(self, repo_name): _load_changelog_summary() @@ -161,8 +160,7 @@ @LoginRequired() @NotAnonymous() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') @jsonify def repo_size(self, repo_name): if request.is_xhr: @@ -171,8 +169,7 @@ raise HTTPBadRequest() @LoginRequired() - @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', - 'repository.admin') + @HasRepoPermissionLevelDecorator('read') def statistics(self, repo_name): if c.db_repo.enable_statistics: c.show_stats = True diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/lib/auth.py --- a/kallithea/lib/auth.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/lib/auth.py Mon Feb 20 17:23:25 2017 +0100 @@ -537,6 +537,18 @@ def permissions(self): return self.__get_perms(user=self, cache=False) + def has_repository_permission_level(self, repo_name, level, purpose=None): + required_perms = { + 'read': ['repository.read', 'repository.write', 'repository.admin'], + 'write': ['repository.write', 'repository.admin'], + 'admin': ['repository.admin'], + }[level] + actual_perm = self.permissions['repositories'].get(repo_name) + ok = actual_perm in required_perms + log.debug('Checking if user %r can %r repo %r (%s): %s (has %r)', + self.username, level, repo_name, purpose, ok, actual_perm) + return ok + @property def api_keys(self): return self._get_api_keys() @@ -836,17 +848,15 @@ return any(p in global_permissions for p in self.required_perms) -class HasRepoPermissionAnyDecorator(_PermsDecorator): +class HasRepoPermissionLevelDecorator(_PermsDecorator): """ - Checks the user has any of given permissions for the requested repository. + Checks the user has at least the specified permission level for the requested repository. """ def check_permissions(self, user): repo_name = get_repo_slug(request) - try: - return user.permissions['repositories'][repo_name] in self.required_perms - except KeyError: - return False + (level,) = self.required_perms + return user.has_repository_permission_level(repo_name, level) class HasRepoGroupPermissionAnyDecorator(_PermsDecorator): @@ -908,17 +918,11 @@ return ok -class HasRepoPermissionAny(_PermsFunction): +class HasRepoPermissionLevel(_PermsFunction): def __call__(self, repo_name, purpose=None): - try: - ok = request.user.permissions['repositories'][repo_name] in self.required_perms - except KeyError: - ok = False - - log.debug('Check %s for %s for repo %s (%s): %s' % - (request.user.username, self.required_perms, repo_name, purpose, ok)) - return ok + (level,) = self.required_perms + return request.user.has_repository_permission_level(repo_name, level, purpose) class HasRepoGroupPermissionAny(_PermsFunction): diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/lib/helpers.py --- a/kallithea/lib/helpers.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/lib/helpers.py Mon Feb 20 17:23:25 2017 +0100 @@ -778,7 +778,7 @@ # PERMS #============================================================================== from kallithea.lib.auth import HasPermissionAny, \ - HasRepoPermissionAny, HasRepoGroupPermissionAny + HasRepoPermissionLevel, HasRepoGroupPermissionAny #============================================================================== diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/model/repo.py --- a/kallithea/model/repo.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/model/repo.py Mon Feb 20 17:23:25 2017 +0100 @@ -47,7 +47,7 @@ Statistics, UserGroup, Ui, RepoGroup, RepositoryField from kallithea.lib import helpers as h -from kallithea.lib.auth import HasRepoPermissionAny, HasUserGroupPermissionAny +from kallithea.lib.auth import HasRepoPermissionLevel, HasUserGroupPermissionAny from kallithea.lib.exceptions import AttachedForksError from kallithea.model.scm import UserGroupList @@ -207,10 +207,7 @@ for repo in repos_list: if perm_check: # check permission at this level - if not HasRepoPermissionAny( - 'repository.read', 'repository.write', - 'repository.admin' - )(repo.repo_name, 'get_repos_as_dict check'): + if not HasRepoPermissionLevel('read')(repo.repo_name, 'get_repos_as_dict check'): continue cs_cache = repo.changeset_cache row = { diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/model/scm.py --- a/kallithea/model/scm.py Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/model/scm.py Mon Feb 20 17:23:25 2017 +0100 @@ -49,7 +49,7 @@ from kallithea.lib import helpers as h from kallithea.lib.utils2 import safe_str, safe_unicode, get_server_url, \ _set_extras -from kallithea.lib.auth import HasRepoPermissionAny, HasRepoGroupPermissionAny, \ +from kallithea.lib.auth import HasRepoPermissionLevel, HasRepoGroupPermissionAny, \ HasUserGroupPermissionAny, HasPermissionAny, HasPermissionAny from kallithea.lib.utils import get_filesystem_repos, make_ui, \ action_logger @@ -114,13 +114,10 @@ class RepoList(_PermCheckIterator): - def __init__(self, db_repo_list, perm_set=None, extra_kwargs=None): - if not perm_set: - perm_set = ['repository.read', 'repository.write', 'repository.admin'] - + def __init__(self, db_repo_list, perm_level, extra_kwargs=None): super(RepoList, self).__init__(obj_list=db_repo_list, - obj_attr='repo_name', perm_set=perm_set, - perm_checker=HasRepoPermissionAny, + obj_attr='repo_name', perm_set=[perm_level], + perm_checker=HasRepoPermissionLevel, extra_kwargs=extra_kwargs) @@ -216,7 +213,7 @@ def get_repos(self, repos): """Return the repos the user has access to""" - return RepoList(repos) + return RepoList(repos, perm_level='read') def get_repo_groups(self, groups=None): """Return the repo groups the user has access to diff -r 3505a6be2988 -r a17c8e5f6712 kallithea/templates/base/base.html --- a/kallithea/templates/base/base.html Thu Feb 23 20:26:27 2017 +0100 +++ b/kallithea/templates/base/base.html Mon Feb 20 17:23:25 2017 +0100 @@ -133,13 +133,13 @@