##// END OF EJS Templates
repo-forks: stable, security, fix issue when forging fork_repo_id could allow reading other people forks.
marcink -
r2195:af6ecbb0 stable
parent child Browse files
Show More
@@ -1,196 +1,199 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 forks controller for rhodecode
23 23 """
24 24
25 25 import formencode
26 26 import logging
27 27 from formencode import htmlfill
28 28
29 29 from pylons import tmpl_context as c, request, url
30 30 from pylons.controllers.util import redirect
31 31 from pylons.i18n.translation import _
32 32
33 33 import rhodecode.lib.helpers as h
34 34
35 35 from rhodecode.lib import auth
36 36 from rhodecode.lib.helpers import Page
37 37 from rhodecode.lib.auth import (
38 38 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
39 39 HasRepoPermissionAny, HasPermissionAnyDecorator, HasAcceptedRepoType)
40 40 from rhodecode.lib.base import BaseRepoController, render
41 41 from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User
42 42 from rhodecode.model.repo import RepoModel
43 43 from rhodecode.model.forms import RepoForkForm
44 44 from rhodecode.model.scm import ScmModel, RepoGroupList
45 45 from rhodecode.lib.utils2 import safe_int
46 46
47 47 log = logging.getLogger(__name__)
48 48
49 49
50 50 class ForksController(BaseRepoController):
51 51
52 52 def __before__(self):
53 53 super(ForksController, self).__before__()
54 54
55 55 def __load_defaults(self):
56 56 acl_groups = RepoGroupList(
57 57 RepoGroup.query().all(),
58 58 perm_set=['group.write', 'group.admin'])
59 59 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
60 60 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
61 61 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
62 62 c.landing_revs_choices = choices
63 63 c.personal_repo_group = c.rhodecode_user.personal_repo_group
64 64
65 65 def __load_data(self, repo_name=None):
66 66 """
67 67 Load defaults settings for edit, and update
68 68
69 69 :param repo_name:
70 70 """
71 71 self.__load_defaults()
72 72
73 73 c.repo_info = Repository.get_by_repo_name(repo_name)
74 74 repo = c.repo_info.scm_instance()
75 75
76 76 if c.repo_info is None:
77 77 h.not_mapped_error(repo_name)
78 78 return redirect(url('repos'))
79 79
80 80 c.default_user_id = User.get_default_user().user_id
81 81 c.in_public_journal = UserFollowing.query()\
82 82 .filter(UserFollowing.user_id == c.default_user_id)\
83 83 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
84 84
85 85 if c.repo_info.stats:
86 86 last_rev = c.repo_info.stats.stat_on_revision+1
87 87 else:
88 88 last_rev = 0
89 89 c.stats_revision = last_rev
90 90
91 91 c.repo_last_rev = repo.count()
92 92
93 93 if last_rev == 0 or c.repo_last_rev == 0:
94 94 c.stats_percentage = 0
95 95 else:
96 96 c.stats_percentage = '%.2f' % ((float((last_rev)) /
97 97 c.repo_last_rev) * 100)
98 98
99 99 defaults = RepoModel()._get_defaults(repo_name)
100 100 # alter the description to indicate a fork
101 101 defaults['description'] = ('fork of repository: %s \n%s'
102 102 % (defaults['repo_name'],
103 103 defaults['description']))
104 104 # add suffix to fork
105 105 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
106 106
107 107 return defaults
108 108
109 109 @LoginRequired()
110 110 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
111 111 'repository.admin')
112 112 @HasAcceptedRepoType('git', 'hg')
113 113 def forks(self, repo_name):
114 114 p = safe_int(request.GET.get('page', 1), 1)
115 115 repo_id = c.rhodecode_db_repo.repo_id
116 116 d = []
117 117 for r in Repository.get_repo_forks(repo_id):
118 118 if not HasRepoPermissionAny(
119 119 'repository.read', 'repository.write', 'repository.admin'
120 120 )(r.repo_name, 'get forks check'):
121 121 continue
122 122 d.append(r)
123 123 c.forks_pager = Page(d, page=p, items_per_page=20)
124 124
125 125 c.forks_data = render('/forks/forks_data.mako')
126 126
127 127 if request.environ.get('HTTP_X_PJAX'):
128 128 return c.forks_data
129 129
130 130 return render('/forks/forks.mako')
131 131
132 132 @LoginRequired()
133 133 @NotAnonymous()
134 134 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
135 135 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
136 136 'repository.admin')
137 137 @HasAcceptedRepoType('git', 'hg')
138 138 def fork(self, repo_name):
139 139 c.repo_info = Repository.get_by_repo_name(repo_name)
140 140 if not c.repo_info:
141 141 h.not_mapped_error(repo_name)
142 142 return redirect(h.route_path('home'))
143 143
144 144 defaults = self.__load_data(repo_name)
145 145
146 146 return htmlfill.render(
147 147 render('forks/fork.mako'),
148 148 defaults=defaults,
149 149 encoding="UTF-8",
150 150 force_defaults=False
151 151 )
152 152
153 153 @LoginRequired()
154 154 @NotAnonymous()
155 155 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
156 156 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
157 157 'repository.admin')
158 158 @HasAcceptedRepoType('git', 'hg')
159 159 @auth.CSRFRequired()
160 160 def fork_create(self, repo_name):
161 161 self.__load_defaults()
162 162 c.repo_info = Repository.get_by_repo_name(repo_name)
163 163 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
164 164 repo_groups=c.repo_groups_choices,
165 165 landing_revs=c.landing_revs_choices)()
166 post_data = dict(request.POST)
167 post_data['fork_parent_id'] = c.repo_info.repo_id
168
166 169 form_result = {}
167 170 task_id = None
168 171 try:
169 form_result = _form.to_python(dict(request.POST))
172 form_result = _form.to_python(post_data)
170 173 # create fork is done sometimes async on celery, db transaction
171 174 # management is handled there.
172 175 task = RepoModel().create_fork(
173 176 form_result, c.rhodecode_user.user_id)
174 177 from celery.result import BaseAsyncResult
175 178 if isinstance(task, BaseAsyncResult):
176 179 task_id = task.task_id
177 180 except formencode.Invalid as errors:
178 181 c.new_repo = errors.value['repo_name']
179 182 return htmlfill.render(
180 183 render('forks/fork.mako'),
181 184 defaults=errors.value,
182 185 errors=errors.error_dict or {},
183 186 prefix_error=False,
184 187 encoding="UTF-8",
185 188 force_defaults=False)
186 189 except Exception:
187 190 log.exception(
188 191 u'Exception while trying to fork the repository %s', repo_name)
189 192 msg = (
190 193 _('An error occurred during repository forking %s') %
191 194 (repo_name, ))
192 195 h.flash(msg, category='error')
193 196
194 197 return redirect(h.url('repo_creating_home',
195 198 repo_name=form_result['repo_name_full'],
196 199 task_id=task_id))
General Comments 0
You need to be logged in to leave comments. Login now