Mercurial > hg
diff mercurial/dispatch.py @ 35170:c9740b69b9b7 stable
dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options
If this feature is enabled, early options are parsed using the global options
table. As the parser stops processing options when non/unknown option is
encountered, it won't mistakenly take an option value as a new early option.
Still "--" can be injected to terminate the parsing (e.g. "hg -R -- log"), I
think it's unlikely to lead to an RCE.
To minimize a risk of this change, new fancyopts.earlygetopt() path is enabled
only when +strictflags is set. Also the strict parser doesn't support '--repo',
a short for '--repository' yet. This limitation will be removed later.
As this feature is backward incompatible, I decided to add a new opt-in
mechanism to HGPLAIN. I'm not pretty sure if this is the right choice, but
I'm thinking of adding +feature/-feature syntax to HGPLAIN. Alternatively,
we could add a new environment variable. Any bikeshedding is welcome.
Note that HGPLAIN=+strictflags doesn't work correctly in chg session since
command arguments are pre-processed in C. This wouldn't be easily fixed.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 23 Nov 2017 22:17:03 +0900 |
parents | 02845f7441af |
children | aef2b98d9352 |
line wrap: on
line diff
--- a/mercurial/dispatch.py Thu Nov 23 22:04:53 2017 +0900 +++ b/mercurial/dispatch.py Thu Nov 23 22:17:03 2017 +0900 @@ -150,6 +150,8 @@ try: if not req.ui: req.ui = uimod.ui.load() + if req.ui.plain('strictflags'): + req.earlyoptions.update(_earlyparseopts(req.args)) if _earlyreqoptbool(req, 'traceback', ['--traceback']): req.ui.setconfig('ui', 'traceback', 'on', '--traceback') @@ -644,6 +646,12 @@ return configs +def _earlyparseopts(args): + options = {} + fancyopts.fancyopts(args, commands.globalopts, options, + gnu=False, early=True) + return options + def _earlygetopt(aliases, args, strip=True): """Return list of values for an option (or aliases). @@ -732,12 +740,16 @@ def _earlyreqopt(req, name, aliases): """Peek a list option without using a full options table""" + if req.ui.plain('strictflags'): + return req.earlyoptions[name] values = _earlygetopt(aliases, req.args, strip=False) req.earlyoptions[name] = values return values def _earlyreqoptstr(req, name, aliases): """Peek a string option without using a full options table""" + if req.ui.plain('strictflags'): + return req.earlyoptions[name] value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] req.earlyoptions[name] = value return value @@ -745,13 +757,15 @@ def _earlyreqoptbool(req, name, aliases): """Peek a boolean option without using a full options table - >>> req = request([b'x', b'--debugger']) + >>> req = request([b'x', b'--debugger'], uimod.ui()) >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) True - >>> req = request([b'x', b'--', b'--debugger']) + >>> req = request([b'x', b'--', b'--debugger'], uimod.ui()) >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) """ + if req.ui.plain('strictflags'): + return req.earlyoptions[name] try: argcount = req.args.index("--") except ValueError: