Skip to content

Commit cd08e68

Browse files
committed
echochar must be ascii
1 parent 75e37bc commit cd08e68

File tree

2 files changed

+21
-18
lines changed

2 files changed

+21
-18
lines changed

Doc/library/getpass.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ The :mod:`getpass` module provides two functions:
2727

2828
The *echochar* argument controls how user input is displayed while typing.
2929
If *echochar* is ``None`` (default), input remains hidden. If *echochar* is
30-
a string, each typed character is replaced with the given string.
31-
For example, ``echochar='*'`` will display asterisks instead of the actual
32-
input.
30+
a string, each typed character is replaced with the given string. But this
31+
string must be ASCII character. For example, ``echochar='*'`` will display
32+
asterisks instead of the actual input.
3333

3434
If echo free input is unavailable getpass() falls back to printing
3535
a warning message to *stream* and reading from ``sys.stdin`` and

Lib/getpass.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ def unix_getpass(prompt='Password: ', stream=None, *, echochar=None):
4343
4444
Always restores terminal settings before returning.
4545
"""
46-
if echochar and not echochar.isascii():
47-
return ValueError(f"Invalid echochar: {echochar}. "
48-
"ASCII character expected.")
46+
if _is_ascii(echochar):
47+
return ValueError(f"'echochar' must be ASCII, got: {echochar!r}")
4948

5049
passwd = None
5150
with contextlib.ExitStack() as stack:
@@ -82,13 +81,11 @@ def unix_getpass(prompt='Password: ', stream=None, *, echochar=None):
8281
tcsetattr_flags |= termios.TCSASOFT
8382
try:
8483
termios.tcsetattr(fd, tcsetattr_flags, new)
85-
if not echochar:
84+
if echochar:
85+
passwd = _input_with_echochar(prompt, stream, input,
86+
echochar)
87+
else:
8688
passwd = _raw_input(prompt, stream, input=input)
87-
stream.write('\n')
88-
return passwd
89-
90-
passwd = _input_with_echochar(prompt, stream, input,
91-
echochar)
9289
finally:
9390
termios.tcsetattr(fd, tcsetattr_flags, old)
9491
stream.flush() # issue7208
@@ -112,9 +109,8 @@ def win_getpass(prompt='Password: ', stream=None, *, echochar=None):
112109
"""Prompt for password with echo off, using Windows getwch()."""
113110
if sys.stdin is not sys.__stdin__:
114111
return fallback_getpass(prompt, stream)
115-
if echochar and not echochar.isascii():
116-
return ValueError(f"Invalid echochar: {echochar}. "
117-
"ASCII character expected.")
112+
if _is_ascii(echochar):
113+
return ValueError(f"'echochar' must be ASCII, got: {echochar!r}")
118114

119115
for c in prompt:
120116
msvcrt.putwch(c)
@@ -127,9 +123,9 @@ def win_getpass(prompt='Password: ', stream=None, *, echochar=None):
127123
raise KeyboardInterrupt
128124
if c == '\b':
129125
if echochar and pw:
130-
msvcrt.putwch('\b')
131-
msvcrt.putwch(' ')
132-
msvcrt.putwch('\b')
126+
msvcrt.putch('\b')
127+
msvcrt.putch(' ')
128+
msvcrt.putch('\b')
133129
pw = pw[:-1]
134130
else:
135131
pw = pw + c
@@ -150,6 +146,13 @@ def fallback_getpass(prompt='Password: ', stream=None):
150146
return _raw_input(prompt, stream)
151147

152148

149+
def _is_ascii(echochar):
150+
# ASCII excluding control characters
151+
if echochar and not (32 <= ord(echochar) <= 127):
152+
return False
153+
return True
154+
155+
153156
def _raw_input(prompt="", stream=None, input=None):
154157
# This doesn't save the string in the GNU readline history.
155158
if not stream:

0 commit comments

Comments
 (0)