mirror of
https://github.com/python/cpython.git
synced 2025-07-30 14:44:10 +00:00
#18116: backport fix to 3.3 since real-world failure mode demonstrated.
In issue 20074 it was pointed out that getpass would fail with a traceback if stdin was, for example /dev/null, which is a non-unlikely scenario. Also backported the tests from issue 17484 as modified by issue 18116. (What I really did was copy getpass.py and test_getpass.py from their state on tip as of 17bd04fbf3d3).
This commit is contained in:
parent
5eb01530b2
commit
ecff5e51a5
4 changed files with 213 additions and 45 deletions
|
@ -15,7 +15,11 @@ On the Mac EasyDialogs.AskPassword is used, if available.
|
|||
# Guido van Rossum (Windows support and cleanup)
|
||||
# Gregory P. Smith (tty support & GetPassWarning)
|
||||
|
||||
import os, sys, warnings
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
__all__ = ["getpass","getuser","GetPassWarning"]
|
||||
|
||||
|
@ -38,52 +42,57 @@ def unix_getpass(prompt='Password: ', stream=None):
|
|||
|
||||
Always restores terminal settings before returning.
|
||||
"""
|
||||
fd = None
|
||||
tty = None
|
||||
try:
|
||||
# Always try reading and writing directly on the tty first.
|
||||
fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
|
||||
tty = os.fdopen(fd, 'w+', 1)
|
||||
input = tty
|
||||
if not stream:
|
||||
stream = tty
|
||||
except EnvironmentError as e:
|
||||
# If that fails, see if stdin can be controlled.
|
||||
passwd = None
|
||||
with contextlib.ExitStack() as stack:
|
||||
try:
|
||||
fd = sys.stdin.fileno()
|
||||
except (AttributeError, ValueError):
|
||||
passwd = fallback_getpass(prompt, stream)
|
||||
input = sys.stdin
|
||||
if not stream:
|
||||
stream = sys.stderr
|
||||
|
||||
if fd is not None:
|
||||
passwd = None
|
||||
try:
|
||||
old = termios.tcgetattr(fd) # a copy to save
|
||||
new = old[:]
|
||||
new[3] &= ~termios.ECHO # 3 == 'lflags'
|
||||
tcsetattr_flags = termios.TCSAFLUSH
|
||||
if hasattr(termios, 'TCSASOFT'):
|
||||
tcsetattr_flags |= termios.TCSASOFT
|
||||
# Always try reading and writing directly on the tty first.
|
||||
fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
|
||||
tty = io.FileIO(fd, 'w+')
|
||||
stack.enter_context(tty)
|
||||
input = io.TextIOWrapper(tty)
|
||||
stack.enter_context(input)
|
||||
if not stream:
|
||||
stream = input
|
||||
except OSError as e:
|
||||
# If that fails, see if stdin can be controlled.
|
||||
stack.close()
|
||||
try:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, new)
|
||||
passwd = _raw_input(prompt, stream, input=input)
|
||||
finally:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, old)
|
||||
stream.flush() # issue7208
|
||||
except termios.error:
|
||||
if passwd is not None:
|
||||
# _raw_input succeeded. The final tcsetattr failed. Reraise
|
||||
# instead of leaving the terminal in an unknown state.
|
||||
raise
|
||||
# We can't control the tty or stdin. Give up and use normal IO.
|
||||
# fallback_getpass() raises an appropriate warning.
|
||||
del input, tty # clean up unused file objects before blocking
|
||||
passwd = fallback_getpass(prompt, stream)
|
||||
fd = sys.stdin.fileno()
|
||||
except (AttributeError, ValueError):
|
||||
fd = None
|
||||
passwd = fallback_getpass(prompt, stream)
|
||||
input = sys.stdin
|
||||
if not stream:
|
||||
stream = sys.stderr
|
||||
|
||||
stream.write('\n')
|
||||
return passwd
|
||||
if fd is not None:
|
||||
try:
|
||||
old = termios.tcgetattr(fd) # a copy to save
|
||||
new = old[:]
|
||||
new[3] &= ~termios.ECHO # 3 == 'lflags'
|
||||
tcsetattr_flags = termios.TCSAFLUSH
|
||||
if hasattr(termios, 'TCSASOFT'):
|
||||
tcsetattr_flags |= termios.TCSASOFT
|
||||
try:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, new)
|
||||
passwd = _raw_input(prompt, stream, input=input)
|
||||
finally:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, old)
|
||||
stream.flush() # issue7208
|
||||
except termios.error:
|
||||
if passwd is not None:
|
||||
# _raw_input succeeded. The final tcsetattr failed. Reraise
|
||||
# instead of leaving the terminal in an unknown state.
|
||||
raise
|
||||
# We can't control the tty or stdin. Give up and use normal IO.
|
||||
# fallback_getpass() raises an appropriate warning.
|
||||
if stream is not input:
|
||||
# clean up unused file objects before blocking
|
||||
stack.close()
|
||||
passwd = fallback_getpass(prompt, stream)
|
||||
|
||||
stream.write('\n')
|
||||
return passwd
|
||||
|
||||
|
||||
def win_getpass(prompt='Password: ', stream=None):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue