[PATCH STABLE] cmdserver: forcibly use L channel to read password input (issue3161)
Augie Fackler
raf at durin42.com
Tue Apr 29 10:20:17 CDT 2014
On Sun, Apr 27, 2014 at 05:11:02PM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya at tcha.org>
> # Date 1398503586 -32400
> # Sat Apr 26 18:13:06 2014 +0900
> # Branch stable
> # Node ID 6a43c60ad9af8d7524740a9ae185970759235eab
> # Parent faf1ce941b0cc2e699929d33ac494b5e934146c4
> cmdserver: forcibly use L channel to read password input (issue3161)
This all looks reasonable to me on a high-level pass, but I'll defer
to mpm as to wether it belongs in stable this late in the cycle.
>
> Command server is designed to use the channel protocol even if the server
> process is accessible to tty, whereas vanilla hg should be able to read
> password from tty in that case. So it isn't enough to swap sys.stdin:
>
> # works only if the server process is detached from the console
> sys.stdin = self.fin
> getpass.getpass('')
> sys.stdin = oldin
>
> or test isatty:
>
> # vanilla hg can't talk to tty if stdin is redirected
> if self._isatty(self.fin):
> return getpass.getpass('')
> else:
> ...
>
> Since ui.nontty flag is undocumented and command-server channels don't provide
> isatty(), this change won't affect the other uses of ui._isatty().
>
> issue3161 also suggests to provide some context of messages. I think it can
> be implemented by using the generic templating function.
>
> diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py
> --- a/mercurial/commandserver.py
> +++ b/mercurial/commandserver.py
> @@ -187,14 +187,20 @@ class server(object):
> # copy the uis so changes (e.g. --config or --verbose) don't
> # persist between requests
> copiedui = self.ui.copy()
> + uis = [copiedui]
> if self.repo:
> self.repo.baseui = copiedui
> # clone ui without using ui.copy because this is protected
> repoui = self.repoui.__class__(self.repoui)
> repoui.copy = copiedui.copy # redo copy protection
> + uis.append(repoui)
> self.repo.ui = self.repo.dirstate._ui = repoui
> self.repo.invalidateall()
>
> + for ui in uis:
> + # any kind of interaction must use server channels
> + ui.setconfig('ui', 'nontty', 'true', 'commandserver')
> +
> req = dispatch.request(args[:], copiedui, self.repo, self.cin,
> self.cout, self.cerr)
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -689,7 +689,12 @@ class ui(object):
> return default
> try:
> self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
> - return getpass.getpass('')
> + # disable getpass() only if explicitly specified. it's still valid
> + # to interact with tty even if fin is not a tty.
> + if self.configbool('ui', 'nontty'):
> + return self.fin.readline().rstrip('\n')
> + else:
> + return getpass.getpass('')
> except EOFError:
> raise util.Abort(_('response expected'))
> def status(self, *msg, **opts):
> diff --git a/tests/test-commandserver.py b/tests/test-commandserver.py
> --- a/tests/test-commandserver.py
> +++ b/tests/test-commandserver.py
> @@ -294,6 +294,11 @@ def mqoutsidechanges(server):
> # repo.mq should be recreated to point to new queue
> runcommand(server, ['qqueue', '--active'])
>
> +def getpass(server):
> + readchannel(server)
> + runcommand(server, ['debuggetpass', '--config', 'ui.interactive=True'],
> + input=cStringIO.StringIO('1234\n'))
> +
> def startwithoutrepo(server):
> readchannel(server)
> runcommand(server, ['init', 'repo2'])
> @@ -334,6 +339,19 @@ if __name__ == '__main__':
> hgrc.write('[extensions]\nmq=\n')
> hgrc.close()
> check(mqoutsidechanges)
> + dbg = open('dbgui.py', 'w')
> + dbg.write('from mercurial import cmdutil, commands\n'
> + 'commands.norepo += " debuggetpass"\n'
> + 'cmdtable = {}\n'
> + 'command = cmdutil.command(cmdtable)\n'
> + '@command("debuggetpass")\n'
> + 'def debuggetpass(ui):\n'
> + ' ui.write("%s\\n" % ui.getpass())\n')
> + dbg.close()
> + hgrc = open('.hg/hgrc', 'a')
> + hgrc.write('[extensions]\ndbgui=dbgui.py\n')
> + hgrc.close()
> + check(getpass)
>
> os.chdir('..')
> check(hellomessage)
> diff --git a/tests/test-commandserver.py.out b/tests/test-commandserver.py.out
> --- a/tests/test-commandserver.py.out
> +++ b/tests/test-commandserver.py.out
> @@ -81,6 +81,7 @@ defaults.tag=-d "0 0"
> ui.slash=True
> ui.interactive=False
> ui.foo=bar
> +ui.nontty=true
> runcommand init foo
> runcommand -R foo showconfig ui defaults
> defaults.backout=-d "0 0"
> @@ -89,6 +90,7 @@ defaults.shelve=--date "0 0"
> defaults.tag=-d "0 0"
> ui.slash=True
> ui.interactive=False
> +ui.nontty=true
>
> testing hookoutput:
>
> @@ -238,6 +240,11 @@ patch queue now empty
> runcommand qqueue --active
> foo
>
> +testing getpass:
> +
> + runcommand debuggetpass --config ui.interactive=True
> +password: 1234
> +
> testing hellomessage:
>
> o, 'capabilities: getencoding runcommand\nencoding: ***'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list