##// END OF EJS Templates
hgweb: fix trust of templates path (BC)...
hgweb: fix trust of templates path (BC) Long ago we disabled trust of the templates path with a comment describing the (insecure) behavior before the change. At some later refactor, the code was apparently changed back to match the comment, unaware that the intent of the comment was to describe the behavior to avoid. This change disables the trust and updates the comment to explicitly say not only what the old problem was, but also that it was in fact a problem and the action taken to prevent it. Impact: prior to this change, if you had a UNIX-based hgweb server where users can write hgrc files, those users could potentially read any file readable by the web server. This is marked as a backwards compatibility issue because people may have configured templates without proper trust settings. Issue spotted by Greg Szorc.

File last commit:

r25186:80c5b266 default
r26120:1a45e49a 3.5.1 stable
Show More
hgcia.py
285 lines | 9.0 KiB | text/x-python | PythonLexer
Brendan Cully
Add hgcia to hgext
r7438 # Copyright (C) 2007-8 Brendan Cully <brendan@kublai.com>
Matt Mackall
Update license to GPLv2+
r10263 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Brendan Cully
Add hgcia to hgext
r7438
Dirkjan Ochtman
extensions: change descriptions for hook-providing extensions...
r8935 """hooks for integrating with the CIA.vc notification service
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: wrap docstrings at 70 characters
r9260 This is meant to be run as a changegroup or incoming hook. To
configure it, set the following options in your hgrc::
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [cia]
# your registered CIA user name
user = foo
# the name of the project in CIA
project = foo
# the module (subproject) (optional)
#module = foo
# Append a diffstat to the log message (optional)
#diffstat = False
# Template to use for log messages (optional)
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 #template = {desc}\\n{baseurl}{webroot}/rev/{node}-- {diffstat}
Martin Geisler
hgcia: use reST syntax for literal block
r9208 # Style to use (optional)
#style = foo
# The URL of the CIA notification service (optional)
Mads Kiilerich
fix trivial spelling errors
r17424 # You can use mailto: URLs to send by email, e.g.
Martin Geisler
hgcia: use reST syntax for literal block
r9208 # mailto:cia@cia.vc
# Make sure to set email.from if you do this.
#url = http://cia.vc/
# print message instead of sending it (optional)
#test = False
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 # number of slashes to strip for url paths
#strip = 0
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [hooks]
# one of these:
changegroup.cia = python:hgcia.hook
#incoming.cia = python:hgcia.hook
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [web]
# If you want hyperlinks (optional)
baseurl = http://server/path/to/repo
Brendan Cully
Add hgcia to hgext
r7438 """
from mercurial.i18n import _
Brodie Rao
hgcia/color: remove star imports...
r11750 from mercurial.node import bin, short
Yuya Nishihara
templater: remove noop calls of parsestring(s, quoted=False) (API)...
r24987 from mercurial import cmdutil, patch, util, mail
Brendan Cully
Add hgcia to hgext
r7438 import email.Parser
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 import socket, xmlrpclib
Brendan Cully
Add hgcia to hgext
r7438 from xml.sax import saxutils
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # Note for extension authors: ONLY specify testedwith = 'internal' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
hgext: mark all first-party extensions as such
r16743 testedwith = 'internal'
Brendan Cully
Add hgcia to hgext
r7438
socket_timeout = 30 # seconds
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 if util.safehasattr(socket, 'setdefaulttimeout'):
Brendan Cully
Add hgcia to hgext
r7438 # set a timeout for the socket so you don't have to wait so looooong
# when cia.vc is having problems. requires python >= 2.3:
socket.setdefaulttimeout(socket_timeout)
HGCIA_VERSION = '0.1'
HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia'
class ciamsg(object):
""" A CIA message """
def __init__(self, cia, ctx):
self.cia = cia
self.ctx = ctx
self.url = self.cia.url
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 if self.url:
self.url += self.cia.root
Brendan Cully
Add hgcia to hgext
r7438
def fileelem(self, path, uri, action):
if uri:
uri = ' uri=%s' % saxutils.quoteattr(uri)
return '<file%s action=%s>%s</file>' % (
uri, saxutils.quoteattr(action), saxutils.escape(path))
def fileelems(self):
n = self.ctx.node()
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 f = self.cia.repo.status(self.ctx.p1().node(), n)
Brendan Cully
Add hgcia to hgext
r7438 url = self.url or ''
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 if url and url[-1] == '/':
url = url[:-1]
Brendan Cully
Add hgcia to hgext
r7438 elems = []
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.modified:
Brendan Cully
Add hgcia to hgext
r7438 uri = '%s/diff/%s/%s' % (url, short(n), path)
elems.append(self.fileelem(path, url and uri, 'modify'))
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.added:
Brendan Cully
Add hgcia to hgext
r7438 # TODO: copy/rename ?
uri = '%s/file/%s/%s' % (url, short(n), path)
elems.append(self.fileelem(path, url and uri, 'add'))
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.removed:
Brendan Cully
Add hgcia to hgext
r7438 elems.append(self.fileelem(path, '', 'remove'))
return '\n'.join(elems)
def sourceelem(self, project, module=None, branch=None):
msg = ['<source>', '<project>%s</project>' % saxutils.escape(project)]
if module:
msg.append('<module>%s</module>' % saxutils.escape(module))
if branch:
msg.append('<branch>%s</branch>' % saxutils.escape(branch))
msg.append('</source>')
return '\n'.join(msg)
def diffstat(self):
Benoit Boissinot
use new style classes
r8778 class patchbuf(object):
Brendan Cully
Add hgcia to hgext
r7438 def __init__(self):
self.lines = []
# diffstat is stupid
self.name = 'cia'
def write(self, data):
Matt Mackall
hgcia: fix diffstat support
r15776 self.lines += data.splitlines(True)
Brendan Cully
Add hgcia to hgext
r7438 def close(self):
pass
n = self.ctx.node()
pbuf = patchbuf()
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 cmdutil.export(self.cia.repo, [n], fp=pbuf)
Brendan Cully
Add hgcia to hgext
r7438 return patch.diffstat(pbuf.lines) or ''
def logmsg(self):
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.cia.diffstat:
diffstat = self.diffstat()
else:
diffstat = ''
Brendan Cully
Add hgcia to hgext
r7438 self.cia.ui.pushbuffer()
self.cia.templater.show(self.ctx, changes=self.ctx.changeset(),
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 baseurl=self.cia.ui.config('web', 'baseurl'),
url=self.url, diffstat=diffstat,
webroot=self.cia.root)
Brendan Cully
Add hgcia to hgext
r7438 return self.cia.ui.popbuffer()
def xml(self):
n = short(self.ctx.node())
src = self.sourceelem(self.cia.project, module=self.cia.module,
branch=self.ctx.branch())
# unix timestamp
dt = self.ctx.date()
timestamp = dt[0]
author = saxutils.escape(self.ctx.user())
rev = '%d:%s' % (self.ctx.rev(), n)
log = saxutils.escape(self.logmsg())
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 url = self.url
if url and url[-1] == '/':
url = url[:-1]
url = url and '<url>%s/rev/%s</url>' % (saxutils.escape(url), n) or ''
Brendan Cully
Add hgcia to hgext
r7438
msg = """
<message>
<generator>
<name>Mercurial (hgcia)</name>
<version>%s</version>
<url>%s</url>
<user>%s</user>
</generator>
%s
<body>
<commit>
<author>%s</author>
<version>%s</version>
<log>%s</log>
%s
<files>%s</files>
</commit>
</body>
<timestamp>%d</timestamp>
</message>
""" % \
(HGCIA_VERSION, saxutils.escape(HGCIA_URL),
saxutils.escape(self.cia.user), src, author, rev, log, url,
self.fileelems(), timestamp)
return msg
class hgcia(object):
""" CIA notification class """
deftemplate = '{desc}'
dstemplate = '{desc}\n-- \n{diffstat}'
def __init__(self, ui, repo):
self.ui = ui
self.repo = repo
self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc')
self.user = self.ui.config('cia', 'user')
self.project = self.ui.config('cia', 'project')
self.module = self.ui.config('cia', 'module')
self.diffstat = self.ui.configbool('cia', 'diffstat')
self.emailfrom = self.ui.config('email', 'from')
self.dryrun = self.ui.configbool('cia', 'test')
self.url = self.ui.config('web', 'baseurl')
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 # Default to -1 for backward compatibility
self.stripcount = int(self.ui.config('cia', 'strip', -1))
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 self.root = self.strip(self.repo.root)
Brendan Cully
Add hgcia to hgext
r7438
style = self.ui.config('cia', 'style')
template = self.ui.config('cia', 'template')
if not template:
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.diffstat:
template = self.dstemplate
else:
template = self.deftemplate
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
Matt Mackall
changeset_templater: remove use_template method
r20667 template, style, False)
Brendan Cully
Add hgcia to hgext
r7438 self.templater = t
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 def strip(self, path):
'''strip leading slashes from local path, turn into web-safe path.'''
path = util.pconvert(path)
count = self.stripcount
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 if count < 0:
return ''
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 while count > 0:
c = path.find('/')
if c == -1:
break
path = path[c + 1:]
count -= 1
return path
Brendan Cully
Add hgcia to hgext
r7438 def sendrpc(self, msg):
srv = xmlrpclib.Server(self.ciaurl)
Brendan Cully
hgcia: report RPC errors
r10529 res = srv.hub.deliver(msg)
Georg Brandl
hgcia: accept "queued." xmlrpc return as success
r13551 if res is not True and res != 'queued.':
Brendan Cully
hgcia: report RPC errors
r10529 raise util.Abort(_('%s returned an error: %s') %
(self.ciaurl, res))
Brendan Cully
Add hgcia to hgext
r7438
def sendemail(self, address, data):
p = email.Parser.Parser()
msg = p.parsestr(data)
msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
msg['To'] = address
msg['From'] = self.emailfrom
msg['Subject'] = 'DeliverXML'
msg['Content-type'] = 'text/xml'
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 msgtext = msg.as_string()
Brendan Cully
Add hgcia to hgext
r7438
self.ui.status(_('hgcia: sending update to %s\n') % address)
mail.sendmail(self.ui, util.email(self.emailfrom),
[address], msgtext)
def hook(ui, repo, hooktype, node=None, url=None, **kwargs):
""" send CIA notification """
def sendmsg(cia, ctx):
msg = ciamsg(cia, ctx).xml()
if cia.dryrun:
ui.write(msg)
elif cia.ciaurl.startswith('mailto:'):
if not cia.emailfrom:
raise util.Abort(_('email.from must be defined when '
'sending by email'))
cia.sendemail(cia.ciaurl[7:], msg)
else:
cia.sendrpc(msg)
n = bin(node)
cia = hgcia(ui, repo)
if not cia.user:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('cia: no user specified')
Brendan Cully
Add hgcia to hgext
r7438 return
if not cia.project:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('cia: no project specified')
Brendan Cully
Add hgcia to hgext
r7438 return
if hooktype == 'changegroup':
start = repo.changelog.rev(n)
end = len(repo.changelog)
for rev in xrange(start, end):
n = repo.changelog.node(rev)
ctx = repo.changectx(n)
sendmsg(cia, ctx)
else:
ctx = repo.changectx(n)
sendmsg(cia, ctx)