-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
gh-77065: Add optional keyword-only argument echo_char for getpass.getpass
#130496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
d2b3f74
8d9d83d
413a9ff
9ac2ae2
0ae2b81
da00d07
6c71075
946d718
e2351ab
75e37bc
cd08e68
bcdf95a
501d704
b6b822f
affd84a
977389a
59da53c
3c027d4
81e71a9
ba236ee
c608b7a
17a5891
08e8686
4319f23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||
| """Utilities to get a password and/or the current user name. | ||||||||||||||
|
|
||||||||||||||
| getpass(prompt[, stream]) - Prompt for a password, with echo turned off. | ||||||||||||||
| getpass(prompt[, stream[, echochar]]) - Prompt for a password, with echo | ||||||||||||||
| turned off and optional keyboard feedback. | ||||||||||||||
| getuser() - Get the user name from the environment or password database. | ||||||||||||||
|
|
||||||||||||||
| GetPassWarning - This UserWarning is issued when getpass() cannot prevent | ||||||||||||||
|
|
@@ -25,13 +26,15 @@ | |||||||||||||
| class GetPassWarning(UserWarning): pass | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def unix_getpass(prompt='Password: ', stream=None): | ||||||||||||||
| def unix_getpass(prompt='Password: ', stream=None, *, echochar=None): | ||||||||||||||
| """Prompt for a password, with echo turned off. | ||||||||||||||
|
|
||||||||||||||
| Args: | ||||||||||||||
| prompt: Written on stream to ask for the input. Default: 'Password: ' | ||||||||||||||
| stream: A writable file object to display the prompt. Defaults to | ||||||||||||||
| the tty. If no tty is available defaults to sys.stderr. | ||||||||||||||
| echochar: A string used to mask input (e.g., '*'). If None, input is | ||||||||||||||
| hidden. | ||||||||||||||
| Returns: | ||||||||||||||
| The seKr3t input. | ||||||||||||||
| Raises: | ||||||||||||||
|
|
@@ -40,6 +43,10 @@ def unix_getpass(prompt='Password: ', stream=None): | |||||||||||||
|
|
||||||||||||||
| Always restores terminal settings before returning. | ||||||||||||||
| """ | ||||||||||||||
| if echochar and not echochar.isascii(): | ||||||||||||||
| return ValueError(f"Invalid echochar: {echochar}. " | ||||||||||||||
| "ASCII character expected.") | ||||||||||||||
donBarbos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| passwd = None | ||||||||||||||
| with contextlib.ExitStack() as stack: | ||||||||||||||
| try: | ||||||||||||||
|
|
@@ -68,12 +75,20 @@ def unix_getpass(prompt='Password: ', stream=None): | |||||||||||||
| old = termios.tcgetattr(fd) # a copy to save | ||||||||||||||
| new = old[:] | ||||||||||||||
| new[3] &= ~termios.ECHO # 3 == 'lflags' | ||||||||||||||
| if echochar: | ||||||||||||||
| new[3] &= ~termios.ICANON | ||||||||||||||
donBarbos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| 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) | ||||||||||||||
| if not echochar: | ||||||||||||||
| passwd = _raw_input(prompt, stream, input=input) | ||||||||||||||
| stream.write('\n') | ||||||||||||||
donBarbos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| return passwd | ||||||||||||||
|
|
||||||||||||||
| passwd = _input_with_echochar(prompt, stream, input, | ||||||||||||||
| echochar) | ||||||||||||||
| finally: | ||||||||||||||
| termios.tcsetattr(fd, tcsetattr_flags, old) | ||||||||||||||
| stream.flush() # issue7208 | ||||||||||||||
|
|
@@ -93,10 +108,13 @@ def unix_getpass(prompt='Password: ', stream=None): | |||||||||||||
| return passwd | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def win_getpass(prompt='Password: ', stream=None): | ||||||||||||||
| def win_getpass(prompt='Password: ', stream=None, *, echochar=None): | ||||||||||||||
| """Prompt for password with echo off, using Windows getwch().""" | ||||||||||||||
| if sys.stdin is not sys.__stdin__: | ||||||||||||||
| return fallback_getpass(prompt, stream) | ||||||||||||||
donBarbos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| if echochar and not echochar.isascii(): | ||||||||||||||
| return ValueError(f"Invalid echochar: {echochar}. " | ||||||||||||||
| "ASCII character expected.") | ||||||||||||||
donBarbos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| for c in prompt: | ||||||||||||||
| msvcrt.putwch(c) | ||||||||||||||
|
|
@@ -108,9 +126,15 @@ def win_getpass(prompt='Password: ', stream=None): | |||||||||||||
| if c == '\003': | ||||||||||||||
| raise KeyboardInterrupt | ||||||||||||||
| if c == '\b': | ||||||||||||||
| if echochar and pw: | ||||||||||||||
| msvcrt.putwch('\b') | ||||||||||||||
| msvcrt.putwch(' ') | ||||||||||||||
| msvcrt.putwch('\b') | ||||||||||||||
|
||||||||||||||
| msvcrt.putwch('\b') | |
| msvcrt.putwch(' ') | |
| msvcrt.putwch('\b') | |
| msvcrt.putch('\b') | |
| msvcrt.putch(' ') | |
| msvcrt.putch('\b') |
Those are not wide chars, so we don't need to use putwch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@picnixz I apologize again, as I was so eager to add this to 3.14, but I only have Windows now
the thing is that putch does not accept control characters, so you need to use putwch.
you can easily check this by simply trying to erase the character, and it will immediately give you an error:
msvcrt.putch('\b')
~~~~~~~~~~~~~^^^^^^
TypeError: putch() argument must be a byte string of length 1, not str
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad!
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than duplicating so much of _raw_input's logic, I suggest making a _readline_with_echochar() function and just conditionally calling that vs the existing input.readline() call within _raw_input().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds reasonable, please check my diff
donBarbos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
picnixz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Add keyword-only optional argument *echochar* for :meth:`getpass.getpass` | ||
| for optional visual keyboard feedback support. Patch by Semyon Moroz. |
Uh oh!
There was an error while loading. Please reload this page.