##// END OF EJS Templates
Don't always return action, raise an Exception if we cannot check what the action is
marcink -
r2525:c35980ae beta
parent child Browse files
Show More
@@ -1,260 +1,259
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.hooks
3 rhodecode.lib.hooks
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Hooks runned by rhodecode
6 Hooks runned by rhodecode
7
7
8 :created_on: Aug 6, 2010
8 :created_on: Aug 6, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import sys
26 import sys
27 import binascii
27 import binascii
28 from inspect import isfunction
28 from inspect import isfunction
29
29
30 from mercurial.scmutil import revrange
30 from mercurial.scmutil import revrange
31 from mercurial.node import nullrev
31 from mercurial.node import nullrev
32
32
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.lib.utils import action_logger
34 from rhodecode.lib.utils import action_logger
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
36
36
37
37
38 def _get_scm_size(alias, root_path):
38 def _get_scm_size(alias, root_path):
39
39
40 if not alias.startswith('.'):
40 if not alias.startswith('.'):
41 alias += '.'
41 alias += '.'
42
42
43 size_scm, size_root = 0, 0
43 size_scm, size_root = 0, 0
44 for path, dirs, files in os.walk(root_path):
44 for path, dirs, files in os.walk(root_path):
45 if path.find(alias) != -1:
45 if path.find(alias) != -1:
46 for f in files:
46 for f in files:
47 try:
47 try:
48 size_scm += os.path.getsize(os.path.join(path, f))
48 size_scm += os.path.getsize(os.path.join(path, f))
49 except OSError:
49 except OSError:
50 pass
50 pass
51 else:
51 else:
52 for f in files:
52 for f in files:
53 try:
53 try:
54 size_root += os.path.getsize(os.path.join(path, f))
54 size_root += os.path.getsize(os.path.join(path, f))
55 except OSError:
55 except OSError:
56 pass
56 pass
57
57
58 size_scm_f = h.format_byte_size(size_scm)
58 size_scm_f = h.format_byte_size(size_scm)
59 size_root_f = h.format_byte_size(size_root)
59 size_root_f = h.format_byte_size(size_root)
60 size_total_f = h.format_byte_size(size_root + size_scm)
60 size_total_f = h.format_byte_size(size_root + size_scm)
61
61
62 return size_scm_f, size_root_f, size_total_f
62 return size_scm_f, size_root_f, size_total_f
63
63
64
64
65 def repo_size(ui, repo, hooktype=None, **kwargs):
65 def repo_size(ui, repo, hooktype=None, **kwargs):
66 """
66 """
67 Presents size of repository after push
67 Presents size of repository after push
68
68
69 :param ui:
69 :param ui:
70 :param repo:
70 :param repo:
71 :param hooktype:
71 :param hooktype:
72 """
72 """
73
73
74 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
74 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
75
75
76 last_cs = repo[len(repo) - 1]
76 last_cs = repo[len(repo) - 1]
77
77
78 msg = ('Repository size .hg:%s repo:%s total:%s\n'
78 msg = ('Repository size .hg:%s repo:%s total:%s\n'
79 'Last revision is now r%s:%s\n') % (
79 'Last revision is now r%s:%s\n') % (
80 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
80 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
81 )
81 )
82
82
83 sys.stdout.write(msg)
83 sys.stdout.write(msg)
84
84
85
85
86 def log_pull_action(ui, repo, **kwargs):
86 def log_pull_action(ui, repo, **kwargs):
87 """
87 """
88 Logs user last pull action
88 Logs user last pull action
89
89
90 :param ui:
90 :param ui:
91 :param repo:
91 :param repo:
92 """
92 """
93
94 extras = dict(repo.ui.configitems('rhodecode_extras'))
93 extras = dict(repo.ui.configitems('rhodecode_extras'))
95 username = extras['username']
94 username = extras['username']
96 repository = extras['repository']
95 repository = extras['repository']
97 scm = extras['scm']
96 scm = extras['scm']
98 action = 'pull'
97 action = 'pull'
99
98
100 action_logger(username, action, repository, extras['ip'], commit=True)
99 action_logger(username, action, repository, extras['ip'], commit=True)
101 # extension hook call
100 # extension hook call
102 from rhodecode import EXTENSIONS
101 from rhodecode import EXTENSIONS
103 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
102 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
104
103
105 if isfunction(callback):
104 if isfunction(callback):
106 kw = {}
105 kw = {}
107 kw.update(extras)
106 kw.update(extras)
108 callback(**kw)
107 callback(**kw)
109 return 0
108 return 0
110
109
111
110
112 def log_push_action(ui, repo, **kwargs):
111 def log_push_action(ui, repo, **kwargs):
113 """
112 """
114 Maps user last push action to new changeset id, from mercurial
113 Maps user last push action to new changeset id, from mercurial
115
114
116 :param ui:
115 :param ui:
117 :param repo: repo object containing the `ui` object
116 :param repo: repo object containing the `ui` object
118 """
117 """
119
118
120 extras = dict(repo.ui.configitems('rhodecode_extras'))
119 extras = dict(repo.ui.configitems('rhodecode_extras'))
121 username = extras['username']
120 username = extras['username']
122 repository = extras['repository']
121 repository = extras['repository']
123 action = extras['action'] + ':%s'
122 action = extras['action'] + ':%s'
124 scm = extras['scm']
123 scm = extras['scm']
125
124
126 if scm == 'hg':
125 if scm == 'hg':
127 node = kwargs['node']
126 node = kwargs['node']
128
127
129 def get_revs(repo, rev_opt):
128 def get_revs(repo, rev_opt):
130 if rev_opt:
129 if rev_opt:
131 revs = revrange(repo, rev_opt)
130 revs = revrange(repo, rev_opt)
132
131
133 if len(revs) == 0:
132 if len(revs) == 0:
134 return (nullrev, nullrev)
133 return (nullrev, nullrev)
135 return (max(revs), min(revs))
134 return (max(revs), min(revs))
136 else:
135 else:
137 return (len(repo) - 1, 0)
136 return (len(repo) - 1, 0)
138
137
139 stop, start = get_revs(repo, [node + ':'])
138 stop, start = get_revs(repo, [node + ':'])
140 h = binascii.hexlify
139 h = binascii.hexlify
141 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
140 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
142 elif scm == 'git':
141 elif scm == 'git':
143 revs = kwargs.get('_git_revs', [])
142 revs = kwargs.get('_git_revs', [])
144 if '_git_revs' in kwargs:
143 if '_git_revs' in kwargs:
145 kwargs.pop('_git_revs')
144 kwargs.pop('_git_revs')
146
145
147 action = action % ','.join(revs)
146 action = action % ','.join(revs)
148
147
149 action_logger(username, action, repository, extras['ip'], commit=True)
148 action_logger(username, action, repository, extras['ip'], commit=True)
150
149
151 # extension hook call
150 # extension hook call
152 from rhodecode import EXTENSIONS
151 from rhodecode import EXTENSIONS
153 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
152 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
154 if isfunction(callback):
153 if isfunction(callback):
155 kw = {'pushed_revs': revs}
154 kw = {'pushed_revs': revs}
156 kw.update(extras)
155 kw.update(extras)
157 callback(**kw)
156 callback(**kw)
158 return 0
157 return 0
159
158
160
159
161 def log_create_repository(repository_dict, created_by, **kwargs):
160 def log_create_repository(repository_dict, created_by, **kwargs):
162 """
161 """
163 Post create repository Hook. This is a dummy function for admins to re-use
162 Post create repository Hook. This is a dummy function for admins to re-use
164 if needed. It's taken from rhodecode-extensions module and executed
163 if needed. It's taken from rhodecode-extensions module and executed
165 if present
164 if present
166
165
167 :param repository: dict dump of repository object
166 :param repository: dict dump of repository object
168 :param created_by: username who created repository
167 :param created_by: username who created repository
169 :param created_date: date of creation
168 :param created_date: date of creation
170
169
171 available keys of repository_dict:
170 available keys of repository_dict:
172
171
173 'repo_type',
172 'repo_type',
174 'description',
173 'description',
175 'private',
174 'private',
176 'created_on',
175 'created_on',
177 'enable_downloads',
176 'enable_downloads',
178 'repo_id',
177 'repo_id',
179 'user_id',
178 'user_id',
180 'enable_statistics',
179 'enable_statistics',
181 'clone_uri',
180 'clone_uri',
182 'fork_id',
181 'fork_id',
183 'group_id',
182 'group_id',
184 'repo_name'
183 'repo_name'
185
184
186 """
185 """
187 from rhodecode import EXTENSIONS
186 from rhodecode import EXTENSIONS
188 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
187 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
189 if isfunction(callback):
188 if isfunction(callback):
190 kw = {}
189 kw = {}
191 kw.update(repository_dict)
190 kw.update(repository_dict)
192 kw.update({'created_by': created_by})
191 kw.update({'created_by': created_by})
193 kw.update(kwargs)
192 kw.update(kwargs)
194 return callback(**kw)
193 return callback(**kw)
195
194
196 return 0
195 return 0
197
196
198
197
199 def handle_git_post_receive(repo_path, revs, env):
198 def handle_git_post_receive(repo_path, revs, env):
200 """
199 """
201 A really hacky method that is runned by git post-receive hook and logs
200 A really hacky method that is runned by git post-receive hook and logs
202 an push action together with pushed revisions. It's executed by subprocess
201 an push action together with pushed revisions. It's executed by subprocess
203 thus needs all info to be able to create a on the fly pylons enviroment,
202 thus needs all info to be able to create a on the fly pylons enviroment,
204 connect to database and run the logging code. Hacky as sh*t but works.
203 connect to database and run the logging code. Hacky as sh*t but works.
205
204
206 :param repo_path:
205 :param repo_path:
207 :type repo_path:
206 :type repo_path:
208 :param revs:
207 :param revs:
209 :type revs:
208 :type revs:
210 :param env:
209 :param env:
211 :type env:
210 :type env:
212 """
211 """
213 from paste.deploy import appconfig
212 from paste.deploy import appconfig
214 from sqlalchemy import engine_from_config
213 from sqlalchemy import engine_from_config
215 from rhodecode.config.environment import load_environment
214 from rhodecode.config.environment import load_environment
216 from rhodecode.model import init_model
215 from rhodecode.model import init_model
217 from rhodecode.model.db import RhodeCodeUi
216 from rhodecode.model.db import RhodeCodeUi
218 from rhodecode.lib.utils import make_ui
217 from rhodecode.lib.utils import make_ui
219 from rhodecode.model.db import Repository
218 from rhodecode.model.db import Repository
220
219
221 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
220 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
222 conf = appconfig('config:%s' % ini_name, relative_to=path)
221 conf = appconfig('config:%s' % ini_name, relative_to=path)
223 load_environment(conf.global_conf, conf.local_conf)
222 load_environment(conf.global_conf, conf.local_conf)
224
223
225 engine = engine_from_config(conf, 'sqlalchemy.db1.')
224 engine = engine_from_config(conf, 'sqlalchemy.db1.')
226 init_model(engine)
225 init_model(engine)
227
226
228 baseui = make_ui('db')
227 baseui = make_ui('db')
229 repo = Repository.get_by_full_path(repo_path)
228 repo = Repository.get_by_full_path(repo_path)
230
229
231 _hooks = dict(baseui.configitems('hooks')) or {}
230 _hooks = dict(baseui.configitems('hooks')) or {}
232 # if push hook is enabled via web interface
231 # if push hook is enabled via web interface
233 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
232 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
234
233
235 extras = {
234 extras = {
236 'username': env['RHODECODE_USER'],
235 'username': env['RHODECODE_USER'],
237 'repository': repo.repo_name,
236 'repository': repo.repo_name,
238 'scm': 'git',
237 'scm': 'git',
239 'action': 'push',
238 'action': 'push',
240 'ip': env['RHODECODE_CONFIG_IP'],
239 'ip': env['RHODECODE_CONFIG_IP'],
241 }
240 }
242 for k, v in extras.items():
241 for k, v in extras.items():
243 baseui.setconfig('rhodecode_extras', k, v)
242 baseui.setconfig('rhodecode_extras', k, v)
244 repo = repo.scm_instance
243 repo = repo.scm_instance
245 repo.ui = baseui
244 repo.ui = baseui
246 old_rev, new_rev, ref = revs
245 old_rev, new_rev, ref = revs
247 if old_rev == EmptyChangeset().raw_id:
246 if old_rev == EmptyChangeset().raw_id:
248 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
247 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
249 heads = repo.run_git_command(cmd)[0]
248 heads = repo.run_git_command(cmd)[0]
250 heads = heads.replace(ref, '')
249 heads = heads.replace(ref, '')
251 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
250 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
252 heads.splitlines()))
251 heads.splitlines()))
253 cmd = ('log ' + new_rev +
252 cmd = ('log ' + new_rev +
254 ' --reverse --pretty=format:"%H" --not ' + heads)
253 ' --reverse --pretty=format:"%H" --not ' + heads)
255 else:
254 else:
256 cmd = ('log ' + old_rev + '..' + new_rev +
255 cmd = ('log ' + old_rev + '..' + new_rev +
257 ' --reverse --pretty=format:"%H"')
256 ' --reverse --pretty=format:"%H"')
258 git_revs = repo.run_git_command(cmd)[0].splitlines()
257 git_revs = repo.run_git_command(cmd)[0].splitlines()
259
258
260 log_push_action(baseui, repo, _git_revs=git_revs)
259 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -1,255 +1,258
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.middleware.simplehg
3 rhodecode.lib.middleware.simplehg
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 SimpleHG middleware for handling mercurial protocol request
6 SimpleHG middleware for handling mercurial protocol request
7 (push/clone etc.). It's implemented with basic auth function
7 (push/clone etc.). It's implemented with basic auth function
8
8
9 :created_on: Apr 28, 2010
9 :created_on: Apr 28, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import urllib
30 import urllib
31
31
32 from mercurial.error import RepoError
32 from mercurial.error import RepoError
33 from mercurial.hgweb import hgweb_mod
33 from mercurial.hgweb import hgweb_mod
34
34
35 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
35 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
36
36
37 from rhodecode.lib.utils2 import safe_str
37 from rhodecode.lib.utils2 import safe_str
38 from rhodecode.lib.base import BaseVCSController
38 from rhodecode.lib.base import BaseVCSController
39 from rhodecode.lib.auth import get_container_username
39 from rhodecode.lib.auth import get_container_username
40 from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections
40 from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections
41 from rhodecode.model.db import User
41 from rhodecode.model.db import User
42
42
43 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
43 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 def is_mercurial(environ):
48 def is_mercurial(environ):
49 """
49 """
50 Returns True if request's target is mercurial server - header
50 Returns True if request's target is mercurial server - header
51 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
51 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
52 """
52 """
53 http_accept = environ.get('HTTP_ACCEPT')
53 http_accept = environ.get('HTTP_ACCEPT')
54 path_info = environ['PATH_INFO']
54 path_info = environ['PATH_INFO']
55 if http_accept and http_accept.startswith('application/mercurial'):
55 if http_accept and http_accept.startswith('application/mercurial'):
56 ishg_path = True
56 ishg_path = True
57 else:
57 else:
58 ishg_path = False
58 ishg_path = False
59
59
60 log.debug('pathinfo: %s detected as HG %s' % (
60 log.debug('pathinfo: %s detected as HG %s' % (
61 path_info, ishg_path)
61 path_info, ishg_path)
62 )
62 )
63 return ishg_path
63 return ishg_path
64
64
65
65
66 class SimpleHg(BaseVCSController):
66 class SimpleHg(BaseVCSController):
67
67
68 def _handle_request(self, environ, start_response):
68 def _handle_request(self, environ, start_response):
69 if not is_mercurial(environ):
69 if not is_mercurial(environ):
70 return self.application(environ, start_response)
70 return self.application(environ, start_response)
71
71
72 ipaddr = self._get_ip_addr(environ)
72 ipaddr = self._get_ip_addr(environ)
73 username = None
73 username = None
74 # skip passing error to error controller
74 # skip passing error to error controller
75 environ['pylons.status_code_redirect'] = True
75 environ['pylons.status_code_redirect'] = True
76
76
77 #======================================================================
77 #======================================================================
78 # EXTRACT REPOSITORY NAME FROM ENV
78 # EXTRACT REPOSITORY NAME FROM ENV
79 #======================================================================
79 #======================================================================
80 try:
80 try:
81 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
81 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
82 log.debug('Extracted repo name is %s' % repo_name)
82 log.debug('Extracted repo name is %s' % repo_name)
83 except:
83 except:
84 return HTTPInternalServerError()(environ, start_response)
84 return HTTPInternalServerError()(environ, start_response)
85
85
86 # quick check if that dir exists...
86 # quick check if that dir exists...
87 if is_valid_repo(repo_name, self.basepath) is False:
87 if is_valid_repo(repo_name, self.basepath) is False:
88 return HTTPNotFound()(environ, start_response)
88 return HTTPNotFound()(environ, start_response)
89
89
90 #======================================================================
90 #======================================================================
91 # GET ACTION PULL or PUSH
91 # GET ACTION PULL or PUSH
92 #======================================================================
92 #======================================================================
93 action = self.__get_action(environ)
93 action = self.__get_action(environ)
94
94
95 #======================================================================
95 #======================================================================
96 # CHECK ANONYMOUS PERMISSION
96 # CHECK ANONYMOUS PERMISSION
97 #======================================================================
97 #======================================================================
98 if action in ['pull', 'push']:
98 if action in ['pull', 'push']:
99 anonymous_user = self.__get_user('default')
99 anonymous_user = self.__get_user('default')
100 username = anonymous_user.username
100 username = anonymous_user.username
101 anonymous_perm = self._check_permission(action, anonymous_user,
101 anonymous_perm = self._check_permission(action, anonymous_user,
102 repo_name)
102 repo_name)
103
103
104 if anonymous_perm is not True or anonymous_user.active is False:
104 if anonymous_perm is not True or anonymous_user.active is False:
105 if anonymous_perm is not True:
105 if anonymous_perm is not True:
106 log.debug('Not enough credentials to access this '
106 log.debug('Not enough credentials to access this '
107 'repository as anonymous user')
107 'repository as anonymous user')
108 if anonymous_user.active is False:
108 if anonymous_user.active is False:
109 log.debug('Anonymous access is disabled, running '
109 log.debug('Anonymous access is disabled, running '
110 'authentication')
110 'authentication')
111 #==============================================================
111 #==============================================================
112 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
112 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
113 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
113 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
114 #==============================================================
114 #==============================================================
115
115
116 # Attempting to retrieve username from the container
116 # Attempting to retrieve username from the container
117 username = get_container_username(environ, self.config)
117 username = get_container_username(environ, self.config)
118
118
119 # If not authenticated by the container, running basic auth
119 # If not authenticated by the container, running basic auth
120 if not username:
120 if not username:
121 self.authenticate.realm = \
121 self.authenticate.realm = \
122 safe_str(self.config['rhodecode_realm'])
122 safe_str(self.config['rhodecode_realm'])
123 result = self.authenticate(environ)
123 result = self.authenticate(environ)
124 if isinstance(result, str):
124 if isinstance(result, str):
125 AUTH_TYPE.update(environ, 'basic')
125 AUTH_TYPE.update(environ, 'basic')
126 REMOTE_USER.update(environ, result)
126 REMOTE_USER.update(environ, result)
127 username = result
127 username = result
128 else:
128 else:
129 return result.wsgi_application(environ, start_response)
129 return result.wsgi_application(environ, start_response)
130
130
131 #==============================================================
131 #==============================================================
132 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
132 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
133 #==============================================================
133 #==============================================================
134 try:
134 try:
135 user = self.__get_user(username)
135 user = self.__get_user(username)
136 if user is None or not user.active:
136 if user is None or not user.active:
137 return HTTPForbidden()(environ, start_response)
137 return HTTPForbidden()(environ, start_response)
138 username = user.username
138 username = user.username
139 except:
139 except:
140 log.error(traceback.format_exc())
140 log.error(traceback.format_exc())
141 return HTTPInternalServerError()(environ, start_response)
141 return HTTPInternalServerError()(environ, start_response)
142
142
143 #check permissions for this repository
143 #check permissions for this repository
144 perm = self._check_permission(action, user, repo_name)
144 perm = self._check_permission(action, user, repo_name)
145 if perm is not True:
145 if perm is not True:
146 return HTTPForbidden()(environ, start_response)
146 return HTTPForbidden()(environ, start_response)
147
147
148 # extras are injected into mercurial UI object and later available
148 # extras are injected into mercurial UI object and later available
149 # in hg hooks executed by rhodecode
149 # in hg hooks executed by rhodecode
150 extras = {
150 extras = {
151 'ip': ipaddr,
151 'ip': ipaddr,
152 'username': username,
152 'username': username,
153 'action': action,
153 'action': action,
154 'repository': repo_name,
154 'repository': repo_name,
155 'scm': 'hg',
155 'scm': 'hg',
156 }
156 }
157
157
158 #======================================================================
158 #======================================================================
159 # MERCURIAL REQUEST HANDLING
159 # MERCURIAL REQUEST HANDLING
160 #======================================================================
160 #======================================================================
161 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
161 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
162 log.debug('Repository path is %s' % repo_path)
162 log.debug('Repository path is %s' % repo_path)
163
163
164 baseui = make_ui('db')
164 baseui = make_ui('db')
165 self.__inject_extras(repo_path, baseui, extras)
165 self.__inject_extras(repo_path, baseui, extras)
166
166
167 try:
167 try:
168 # invalidate cache on push
168 # invalidate cache on push
169 if action == 'push':
169 if action == 'push':
170 self._invalidate_cache(repo_name)
170 self._invalidate_cache(repo_name)
171 log.info('%s action on HG repo "%s"' % (action, repo_name))
171 log.info('%s action on HG repo "%s"' % (action, repo_name))
172 app = self.__make_app(repo_path, baseui, extras)
172 app = self.__make_app(repo_path, baseui, extras)
173 return app(environ, start_response)
173 return app(environ, start_response)
174 except RepoError, e:
174 except RepoError, e:
175 if str(e).find('not found') != -1:
175 if str(e).find('not found') != -1:
176 return HTTPNotFound()(environ, start_response)
176 return HTTPNotFound()(environ, start_response)
177 except Exception:
177 except Exception:
178 log.error(traceback.format_exc())
178 log.error(traceback.format_exc())
179 return HTTPInternalServerError()(environ, start_response)
179 return HTTPInternalServerError()(environ, start_response)
180
180
181 def __make_app(self, repo_name, baseui, extras):
181 def __make_app(self, repo_name, baseui, extras):
182 """
182 """
183 Make an wsgi application using hgweb, and inject generated baseui
183 Make an wsgi application using hgweb, and inject generated baseui
184 instance, additionally inject some extras into ui object
184 instance, additionally inject some extras into ui object
185 """
185 """
186 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
186 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
187
187
188 def __get_repository(self, environ):
188 def __get_repository(self, environ):
189 """
189 """
190 Get's repository name out of PATH_INFO header
190 Get's repository name out of PATH_INFO header
191
191
192 :param environ: environ where PATH_INFO is stored
192 :param environ: environ where PATH_INFO is stored
193 """
193 """
194 try:
194 try:
195 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
195 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
196 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
196 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
197 if repo_name.endswith('/'):
197 if repo_name.endswith('/'):
198 repo_name = repo_name.rstrip('/')
198 repo_name = repo_name.rstrip('/')
199 except:
199 except:
200 log.error(traceback.format_exc())
200 log.error(traceback.format_exc())
201 raise
201 raise
202
202
203 return repo_name
203 return repo_name
204
204
205 def __get_user(self, username):
205 def __get_user(self, username):
206 return User.get_by_username(username)
206 return User.get_by_username(username)
207
207
208 def __get_action(self, environ):
208 def __get_action(self, environ):
209 """
209 """
210 Maps mercurial request commands into a clone,pull or push command.
210 Maps mercurial request commands into a clone,pull or push command.
211 This should always return a valid command string
211 This should always return a valid command string
212
212
213 :param environ:
213 :param environ:
214 """
214 """
215 mapping = {'changegroup': 'pull',
215 mapping = {'changegroup': 'pull',
216 'changegroupsubset': 'pull',
216 'changegroupsubset': 'pull',
217 'stream_out': 'pull',
217 'stream_out': 'pull',
218 'listkeys': 'pull',
218 'listkeys': 'pull',
219 'unbundle': 'push',
219 'unbundle': 'push',
220 'pushkey': 'push', }
220 'pushkey': 'push', }
221 for qry in environ['QUERY_STRING'].split('&'):
221 for qry in environ['QUERY_STRING'].split('&'):
222 if qry.startswith('cmd'):
222 if qry.startswith('cmd'):
223 cmd = qry.split('=')[-1]
223 cmd = qry.split('=')[-1]
224 if cmd in mapping:
224 if cmd in mapping:
225 return mapping[cmd]
225 return mapping[cmd]
226
226
227 return 'pull'
227 return 'pull'
228
228
229 raise Exception('Unable to detect pull/push action !!'
230 'Are you using non standard command or client ?')
231
229 def __inject_extras(self, repo_path, baseui, extras={}):
232 def __inject_extras(self, repo_path, baseui, extras={}):
230 """
233 """
231 Injects some extra params into baseui instance
234 Injects some extra params into baseui instance
232
235
233 also overwrites global settings with those takes from local hgrc file
236 also overwrites global settings with those takes from local hgrc file
234
237
235 :param baseui: baseui instance
238 :param baseui: baseui instance
236 :param extras: dict with extra params to put into baseui
239 :param extras: dict with extra params to put into baseui
237 """
240 """
238
241
239 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
242 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
240
243
241 # make our hgweb quiet so it doesn't print output
244 # make our hgweb quiet so it doesn't print output
242 baseui.setconfig('ui', 'quiet', 'true')
245 baseui.setconfig('ui', 'quiet', 'true')
243
246
244 #inject some additional parameters that will be available in ui
247 #inject some additional parameters that will be available in ui
245 #for hooks
248 #for hooks
246 for k, v in extras.items():
249 for k, v in extras.items():
247 baseui.setconfig('rhodecode_extras', k, v)
250 baseui.setconfig('rhodecode_extras', k, v)
248
251
249 repoui = make_ui('file', hgrc, False)
252 repoui = make_ui('file', hgrc, False)
250
253
251 if repoui:
254 if repoui:
252 #overwrite our ui instance with the section from hgrc file
255 #overwrite our ui instance with the section from hgrc file
253 for section in ui_sections:
256 for section in ui_sections:
254 for k, v in repoui.configitems(section):
257 for k, v in repoui.configitems(section):
255 baseui.setconfig(section, k, v)
258 baseui.setconfig(section, k, v)
General Comments 0
You need to be logged in to leave comments. Login now