ui: ensure `getpass()` returns bytes stable
authorMatt Harbison <matt_harbison@yahoo.com>
Mon, 23 Nov 2020 11:47:06 -0500
branchstable
changeset 45777 07b0a687c01a
parent 45776 139b334c9392
child 45778 27c23c8f14da
ui: ensure `getpass()` returns bytes Previously, this could return either bytes or str. I'm not sure which direction we should go in, but since the input is bytes, I guess bytes makes sense as output. `debuguigetpass` crashed because it assumed bytes would be returned, `sslcontext.load_cert_chain()` is happy with bytes or str if the type info in PyCharm is correct, and `smtplib.SMTP.login()` wants str. I couldn't figure out how to test this, because the test stalls for input with `echo test | hg debuguigetpass --config ui.interactive=1`, likely because it drains stdin before prompting. The custom input reading with `ui.nontty=1` does not. I'm also a bit concerned with all of this encoding/decoding. The existing code in the mail module uses `encoding.strfromlocal()`, but the username and password are ascii encoded/decoded in `mercurial.url.passwordmgr.find_user_password()` with `pycompat.{str,bytes}url()`. I'm not sure if this inconsistency could cause subtle compatability issues. Differential Revision: https://phab.mercurial-scm.org/D9375
mercurial/debugcommands.py
mercurial/mail.py
mercurial/ui.py
--- a/mercurial/debugcommands.py	Thu Nov 26 02:28:42 2020 -0500
+++ b/mercurial/debugcommands.py	Mon Nov 23 11:47:06 2020 -0500
@@ -3787,6 +3787,10 @@
 def debuguigetpass(ui, prompt=b''):
     """show prompt to type password"""
     r = ui.getpass(prompt)
+    if r is not None:
+        r = encoding.strtolocal(r)
+    else:
+        r = b"<default response>"
     ui.writenoi18n(b'response: %s\n' % r)
 
 
--- a/mercurial/mail.py	Thu Nov 26 02:28:42 2020 -0500
+++ b/mercurial/mail.py	Mon Nov 23 11:47:06 2020 -0500
@@ -157,6 +157,8 @@
             password = encoding.strfromlocal(password)
         else:
             password = ui.getpass()
+            if password is not None:
+                password = encoding.strfromlocal(password)
     if username and password:
         ui.note(_(b'(authenticating to mail server as %s)\n') % username)
         username = encoding.strfromlocal(username)
--- a/mercurial/ui.py	Thu Nov 26 02:28:42 2020 -0500
+++ b/mercurial/ui.py	Mon Nov 23 11:47:06 2020 -0500
@@ -1735,7 +1735,7 @@
                         raise EOFError
                     return l.rstrip(b'\n')
                 else:
-                    return getpass.getpass('')
+                    return encoding.strtolocal(getpass.getpass(''))
         except EOFError:
             raise error.ResponseExpected()