1 # -*- coding: utf-8 -*-
2 from ConfigObject import ConfigObject
3 from mercurial import config
4 from mercurial import ui
6 from hgapp import config as hgconfig
12 log = logging.getLogger(__name__)
14 def check_perm(req, op):
15 '''Check permission for operation based on request data (including
16 authentication info). Return if op allowed, else raise an ErrorResponse
19 user = req.environ.get('REMOTE_USER')
20 c = req.environ['baseui']
21 credentials = req.environ.get('repoze.what.credentials', {})
22 permissions = credentials.get('permissions', ())
24 if user and permissions:
25 log.debug('%(PATH_INFO)s: %(REMOTE_USER)s - %(repoze.what.credentials)s',
28 log.debug('%(PATH_INFO)s: %(REMOTE_USER)s', req.environ)
32 value = c.configlist('web', option)
34 value = ' '.join([i for i in value if i and i not in '-'])
35 log.debug('Setting value %s to %r', option, value)
36 c.setconfig('web', option, value)
38 if user and 'allow_read' in permissions:
40 elif user and 'allow_read' not in permissions:
41 deny_read = c.configlist('web', 'deny_read')
42 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
43 log.debug('deny_read success')
44 resp = exc.HTTPUnauthorized()
45 resp.status = '%s %s' % (resp.code, 'read not authorized')
48 allow_read = c.configlist('web', 'allow_read')
49 result = (not allow_read) or (allow_read == ['*'])
50 if not (result or user in allow_read):
51 resp = exc.HTTPUnauthorized()
52 resp.status = '%s %s' % (resp.code, 'read not authorized')
55 allow_read = c.configlist('web', 'allow_read')
56 if allow_read != ['*'] and user not in allow_read:
57 log.debug('allow_read failed')
58 resp = exc.HTTPUnauthorized()
59 resp.status = '%s %s' % (resp.code, 'read not authorized')
62 if op == 'pull' and not c.configbool('web', 'allowpull', True):
63 log.debug('allow_pull failed')
64 resp = exc.HTTPUnauthorized()
65 resp.status = '%s %s' % (resp.code, 'pull not authorized')
67 elif op == 'pull' or op is None: # op is None for interface requests
70 # enforce that you can only push using POST requests
71 if req.environ['REQUEST_METHOD'] != 'POST':
72 resp = exc.HTTPUnauthorized()
73 resp.status = '%s %s' % (resp.code, 'push requires POST request')
76 # require ssl by default for pushing, auth info cannot be sniffed
78 if c.configbool('web', 'push_ssl', True) and req.scheme != 'https':
79 log.debug('puch_ssl fail')
80 resp = exc.HTTPMethodNotAllowed()
81 resp.status = '%s %s' % (resp.code, 'ssl required')
85 resp = exc.HTTPUnauthorized()
86 resp.status = '%s %s' % (resp.code, 'push not allowed')
89 if 'allow_push' in permissions:
91 elif 'allow_push' not in permissions:
92 deny = c.configlist('web', 'deny_push')
93 if deny and (not user or deny == ['*'] or user in deny):
94 log.debug('deny_push success')
95 resp = exc.HTTPUnauthorized()
96 resp.status = '%s %s' % (resp.code, 'push not allowed')
99 allow = c.configlist('web', 'allow_push')
100 result = allow and (allow == ['*'] or user in allow)
102 log.debug('allow_push fail')
103 resp = exc.HTTPUnauthorized()
104 resp.status = '%s %s' % (resp.code, 'push not allowed')
107 allow_push = c.configlist('web', 'allow_push')
108 if allow_push != ['*'] and user not in allow_read:
111 def get_binary(suffix=None):
112 binary = os.path.abspath(sys.argv[0])
113 dirname = os.path.dirname(binary)
114 if os.path.isfile(os.path.join(dirname, 'hgapp')):
115 binary = os.path.join(dirname, 'hgapp')
117 binary = binary.split('-')[0]
119 binary += '-%s' % suffix
122 def cmd(*args, **kwargs):
123 binary = kwargs.get('binary', get_binary())
125 os.chdir(kwargs.get('dirname', os.getcwd()))
126 cmd = [binary]+list(args)
127 if subprocess.call(cmd) != 0:
128 print 'Error while running %s' % ' '.join(cmd)
131 def run(*args, **kwargs):
133 os.chdir(kwargs.get('dirname', os.getcwd()))
134 if subprocess.call(list(args)) != 0:
135 print 'Error while running %s' % ' '.join(cmd)
139 filename = os.path.join(dirname, '.hg', 'hgrc')
142 def is_repository(dirname):
143 for name in ('data', 'store'):
144 exist = os.path.join(dirname, '.hg', name)
145 if os.path.isdir(exist):
149 def get_repo(path_info, user=None, cmd=''):
150 path_info = path_info.strip('/')
152 name, path_info = path_info.split('/', 1)
157 return None, None, None
161 userdir = hgconfig['hg:config'].userdir
163 home = os.path.join(userdir, user)
164 if not os.path.isdir(home):
167 cfg.web = dict(allow_read='*', allow_push=user)
168 fd = open(os.path.join(home, '.hgrc'), 'w')
171 userdir = os.path.join(userdir, name)
173 if userdir and os.path.isdir(userdir):
174 c = hgconfig['hg:%s' % name]
179 c = hgconfig['hg:%s' % name]
182 c.path_info = path_info
183 if c.get('hgweb', None) and c.hgweb.endswith(path_info):
185 elif c.get('hgwebdir', None):
186 path = os.path.join(c.hgwebdir, path_info)
187 if is_repository(path):
189 elif cmd.startswith('hg init'):
199 baseui.setconfig('ui', 'username', 'unknown')
200 for k in ('report_untrusted', 'interactive'):
201 baseui.setconfig('ui', k, section.get(k, 'off').as_bool('on', 'off'))
203 baseui.setconfig('web', 'style', 'gitweb')
204 baseui.setconfig('web', 'encoding', 'utf-8')
205 baseui.setconfig('web', 'push_ssl', section.push_ssl.as_bool('on', 'off'))
206 baseui.setconfig('web', 'allowpull', section.get('allowpull', 'on').as_bool('on', 'off'))
208 for k in ('allow_read', 'allow_push', 'deny_read', 'deny_push'):
209 v = section.get(k).as_list(sep=' ')
211 baseui.setconfig('web', k, ' '.join(v))
213 baseui.setconfig('hooks', 'changegroup.hgapp_sphinx',
214 'python:hgapp.hooks.sphinx_update')
218 filename = isfile(hgrc(section.hgweb))
219 elif section.hgwebdir:
220 filename = isfile(section.hgwebdir, '.hgrc')
221 sphinxroot = os.path.join(section.hgwebdir, '.sphinx')
222 baseui.setconfig('hgapp', 'sphinxroot', sphinxroot)
223 section.sphinx_docs = os.path.join(sphinxroot, 'html')
226 cfg = config.config()
228 for k, v in cfg.items('web'):
229 baseui.setconfig('web', k, v)
234 filename = os.path.join(*args)
235 filename = os.path.realpath(filename)
236 if os.path.isfile(filename):
240 def load_config(*filenames):
242 filenames = ['/etc/hgapp/hgapp.ini', os.path.expanduser('~/hgapp.ini'), 'hgapp.ini']
243 filenames = [filename for filename in filenames if os.path.isfile(filename)]
245 raise RuntimeError("Cannot find a hgapp.ini")
246 filename = os.path.abspath(filenames[-1])
247 cfg = ConfigObject(dict(here=os.path.dirname(filename),
250 cfg.__file__ = filename