8

I'm trying make a login window where a user is prompted to enter their Username and Password, although when the password is entered I am looking for asterisks to be printed, like common password entry (i.e. - Sekr3t is echo'd as: * * * * * *).

Here's the code I have so far, and I can't figure out why it doesn't echo asterisks:

import msvcrt
import sys

def login(prompt = '> '):
   write = sys.stdout.write
   
   for x in prompt:
       msvcrt.putch(x)
   passw = ""
   
   while 1:
       x = msvcrt.getch()
       if x == '\r' or x == '\n':
           break
       if x == '\b':
           # position of my error
           passw = passw[:-1]
       else:
           write('*')
           passw = passw + x
   msvcrt.putch('\r')
   msvcrt.putch('\n')
   return passw

Any help would be appreciated.

zk-Jack
  • 83
  • 1
  • 1
  • 9
  • 4
    You should really consider using [`getpass()`](http://docs.python.org/library/getpass.html#getpass.getpass). I realize that you already found this but not echoing anything actually **improves security**. – ThiefMaster Jun 12 '12 at 05:37
  • 3
    @ThiefMaster I can see how it would improve security, but the application is mainly for some of my friends in one of my gaming networks who aren't very computer-adept, so I'm trying to make it somewhere in-between secure and user-friendly -- that's why I chose to try and have asterisks echoed as opposed to nothing. – zk-Jack Jun 12 '12 at 05:48
  • Check out the `curses` module – Joel Cornett Jun 12 '12 at 06:04
  • The security improvement of hiding password length is pretty small, and no response during typing is quite a large usability cost. – Reid Jul 22 '21 at 20:19

3 Answers3

4

You should be able to erase an asterisk by writing the characters \x08 \x08. The \x08 will move the cursor back one position, the space will overwrite the asterisk, then the last \x08 will move the cursor back again, putting it in the correct position to write the next *.

I don't know off the top of my head how to determine when a backspace is typed, but you can do that easily: just add something like print repr(x) after you've called x = msvcrt.getch(), then start your program and hit backspace.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
0

I think this way is very simple and effective

import sys
import msvcrt

passwor = ''
while True:
    x = msvcrt.getch()
    if x == '\r':
        break
    sys.stdout.write('*')
    passwor +=x

print '\n'+passwor
Ahmed ALaa
  • 217
  • 2
  • 3
0

I did all this years ago... in Shell...

For ideas on improving it further... https://antofthy.gitlab.io/info/crypto/passwd_askpass_stars.txt

Final script with many bells and whistles and still evolving https://antofthy.gitlab.io/software/#askpass_stars

Note that you really should not include this directly in your program, but make it a password helper, so that many programs can use it. EG: set a program using an environment variable (like TTY_ASKPASS) or other configuration.

See https://stackoverflow.com/a/67327327/701532

By doing this you are not limiting the user to what YOU provide, but allowing the password to be sourced from other places. "ssh" and even "sudo" also does this.

anthony
  • 7,696
  • 1
  • 17
  • 11