11"""Utilities to get a password and/or the current user name.
22
3- getpass(prompt[, stream]) - Prompt for a password, with echo turned off.
3+ getpass(prompt[, stream[, mask]]) - Prompt for a password, with echo
4+ turned off.
45getuser() - Get the user name from the environment or password database.
56
67GetPassWarning - This UserWarning is issued when getpass() cannot prevent
2526class GetPassWarning (UserWarning ): pass
2627
2728
28- def unix_getpass (prompt = 'Password: ' , stream = None ):
29+ def unix_getpass (prompt = 'Password: ' , stream = None , mask = None ):
2930 """Prompt for a password, with echo turned off.
3031
3132 Args:
3233 prompt: Written on stream to ask for the input. Default: 'Password: '
3334 stream: A writable file object to display the prompt. Defaults to
3435 the tty. If no tty is available defaults to sys.stderr.
36+ mask: A string used to mask input (e.g., '*'). If None, input is hidden.
3537 Returns:
3638 The seKr3t input.
3739 Raises:
@@ -40,7 +42,7 @@ def unix_getpass(prompt='Password: ', stream=None):
4042
4143 Always restores terminal settings before returning.
4244 """
43- passwd = None
45+ passwd = ""
4446 with contextlib .ExitStack () as stack :
4547 try :
4648 # Always try reading and writing directly on the tty first.
@@ -68,17 +70,41 @@ def unix_getpass(prompt='Password: ', stream=None):
6870 old = termios .tcgetattr (fd ) # a copy to save
6971 new = old [:]
7072 new [3 ] &= ~ termios .ECHO # 3 == 'lflags'
73+ if mask :
74+ new [3 ] &= ~ termios .ICANON
7175 tcsetattr_flags = termios .TCSAFLUSH
7276 if hasattr (termios , 'TCSASOFT' ):
7377 tcsetattr_flags |= termios .TCSASOFT
7478 try :
7579 termios .tcsetattr (fd , tcsetattr_flags , new )
76- passwd = _raw_input (prompt , stream , input = input )
80+ if not mask :
81+ passwd = _raw_input (prompt , stream , input = input )
82+ stream .write ('\n ' )
83+ return passwd
84+
85+ stream .write (prompt )
86+ stream .flush ()
87+ while True :
88+ char = input .read (1 )
89+ if char == '\n ' or char == '\r ' :
90+ break
91+ if char == '\x03 ' :
92+ raise KeyboardInterrupt
93+ if char == '\x7f ' or char == '\b ' :
94+ if mask and passwd :
95+ stream .write ("\b \b " * len (mask ))
96+ stream .flush ()
97+ passwd = passwd [:- 1 ]
98+ else :
99+ passwd += char
100+ if mask :
101+ stream .write (mask )
102+ stream .flush ()
77103 finally :
78104 termios .tcsetattr (fd , tcsetattr_flags , old )
79105 stream .flush () # issue7208
80106 except termios .error :
81- if passwd is not None :
107+ if passwd :
82108 # _raw_input succeeded. The final tcsetattr failed. Reraise
83109 # instead of leaving the terminal in an unknown state.
84110 raise
@@ -93,7 +119,7 @@ def unix_getpass(prompt='Password: ', stream=None):
93119 return passwd
94120
95121
96- def win_getpass (prompt = 'Password: ' , stream = None ):
122+ def win_getpass (prompt = 'Password: ' , stream = None , mask = None ):
97123 """Prompt for password with echo off, using Windows getwch()."""
98124 if sys .stdin is not sys .__stdin__ :
99125 return fallback_getpass (prompt , stream )
@@ -108,9 +134,16 @@ def win_getpass(prompt='Password: ', stream=None):
108134 if c == '\003 ' :
109135 raise KeyboardInterrupt
110136 if c == '\b ' :
137+ if mask and pw :
138+ for _ in range (len (mask )):
139+ msvcrt .putwch ('\b ' )
140+ msvcrt .putwch (' ' )
141+ msvcrt .putwch ('\b ' )
111142 pw = pw [:- 1 ]
112143 else :
113144 pw = pw + c
145+ if mask :
146+ msvcrt .putwch (mask )
114147 msvcrt .putwch ('\r ' )
115148 msvcrt .putwch ('\n ' )
116149 return pw
0 commit comments