Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Adding the ability for getpass to print asterisks when password is typed #77065

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

Closed
MatanyaStroh mannequin opened this issue Feb 20, 2018 · 20 comments
Closed

Adding the ability for getpass to print asterisks when password is typed #77065

MatanyaStroh mannequin opened this issue Feb 20, 2018 · 20 comments
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@MatanyaStroh
Copy link
Mannequin

MatanyaStroh mannequin commented Feb 20, 2018

BPO 32884
Nosy @stevendaprano, @bitdancer, @jab, @MatanyaStroh, @Stevoisiak, @remilapeyre, @websurfer5, @akulakov

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2018-02-20.10:28:53.338>
labels = ['type-feature', 'library', '3.9']
title = 'Adding the ability for getpass to print asterisks when password is typed'
updated_at = <Date 2021-08-10.01:27:06.609>
user = 'https://github.com/MatanyaStroh'

bugs.python.org fields:

activity = <Date 2021-08-10.01:27:06.609>
actor = 'andrei.avk'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2018-02-20.10:28:53.338>
creator = 'matanya.stroh'
dependencies = []
files = []
hgrepos = []
issue_num = 32884
keywords = []
message_count = 7.0
messages = ['312410', '312520', '312745', '339803', '344784', '375038', '399298']
nosy_count = 9.0
nosy_names = ['steven.daprano', 'r.david.murray', 'jab', 'matanya.stroh', 'stevoisiak', 'remi.lapeyre', 'Jeffrey.Kintscher', 'celal.sahin', 'andrei.avk']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue32884'
versions = ['Python 3.9']

Linked PRs

@MatanyaStroh
Copy link
Mannequin Author

MatanyaStroh mannequin commented Feb 20, 2018

I saw some questions about it in stackoverflow (links below), and also find it very useful to have the ability to print asterisks.
Some users, find it disturbing when they don't have any indication that password is typed, and it will be helpful to have it.

I know that it's have some risks exposing the number of chars to the password, but I think it's worth it.

When using Jupyter (notebook server is 4.3.1) the password does echoed as "*", but not in Python IDE in linux and Windows

  1. https://stackoverflow.com/questions/10990998/how-to-have-password-echoed-as-asterisks
  2. https://stackoverflow.com/questions/7838564/how-to-read-password-with-echo-in-python-console-program

@MatanyaStroh MatanyaStroh mannequin added 3.8 (EOL) end of life stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Feb 20, 2018
@MatanyaStroh
Copy link
Mannequin Author

MatanyaStroh mannequin commented Feb 22, 2018

for getpass.win_getpass() it can simply be done by adding this line
msvcrt.putch("*").
So the code will look like:

def win_getpass(prompt='Password: ', stream=None):
    """Prompt for password with echo off, using Windows getch()."""
    if sys.stdin is not sys.__stdin__:
        return fallback_getpass(prompt, stream)

    for c in prompt:
        msvcrt.putwch(c)
    pw = ""
    while 1:
        c = msvcrt.getwch()
        if c == '\r' or c == '\n':
            break
        if c == '\003':
            raise KeyboardInterrupt
        if c == '\b':
            pw = pw[:-1]
        else:
            pw = pw + c
            msvcrt.putch("*") #Line that was added
    msvcrt.putwch('\r')
    msvcrt.putwch('\n')
    return pw

@bitdancer
Copy link
Member

getpass is emulating the unix password prompt behavior. I'm not sure if the complication is worth it, especially since not echoing asterisks is, as you observe, fractionally more secure. So I guess I'm about -.5 on this feature.

@stevoisiak
Copy link
Mannequin

stevoisiak mannequin commented Apr 9, 2019

@matanya.stroh: Don't forget to erase the asterisks if the user hits backspace.

def win_getpass(prompt='Password: ', stream=None, show_asterisks=False):
    """Prompt for password with echo off, using Windows getch()."""
    if sys.stdin is not sys.__stdin__:
        return fallback_getpass(prompt, stream)

    for c in prompt:
        msvcrt.putwch(c)
    pw = ""
    while 1:
        c = msvcrt.getwch()
        if c == '\r' or c == '\n':
            break
        if c == '\003':
            raise KeyboardInterrupt
        if c == '\b':
            if len(pw) > 0:
                pw = pw[:-1]
                msvcrt.putwch('\b')
                msvcrt.putwch(' ')
                msvcrt.putwch('\b')
        else:
            pw = pw + c
            if show_asterisks:
                msvcrt.putwch('*')
    msvcrt.putwch('\r')
    msvcrt.putwch('\n')
    return pw

Alternatively, could let the user define the masking character, similar to Tkinter's Entry widget.

def win_getpass(prompt='Password: ', stream=None, mask=''):
    """Prompt for password with echo off, using Windows getch()."""
    if sys.stdin is not sys.__stdin__:
        return fallback_getpass(prompt, stream)
    if len(mask) > 1:
        raise TypeError('mask argument must be a zero- or one-character str')

    for c in prompt:
        msvcrt.putwch(c)
    pw = ""
    while 1:
        c = msvcrt.getwch()
        if c == '\r' or c == '\n':
            break
        if c == '\003':
            raise KeyboardInterrupt
        if c == '\b':
            if len(pw) > 0:
                pw = pw[:-1]
                msvcrt.putwch('\b')
                msvcrt.putwch(' ')
                msvcrt.putwch('\b')
        else:
            pw = pw + c
            if mask:
                msvcrt.putwch(mask)
    msvcrt.putwch('\r')
    msvcrt.putwch('\n')
    return pw

I'm in favor of supporting masking. While it does reveal the password length, it's an accessibility feature many users have come to expect.

I'd rather have this in the standard library than have developers implement their own custom, potentially insecure methods for password input.

@stevendaprano
Copy link
Member

See also bpo-36566. (Thanks Cheryl.)

I think the usability improvement for this far outweigh the decrease in security.

The days where somebody looking over your shoulder watching you type your password was the major threat are long gone. Hiding the length of the password against a shoulder-surfing adversary is so-1970s :-)

For old-school Unix types we ought to default to hiding the password. But I'm +1 in allowing developers to choose to trade off a tiny decrease in security against a major increase in usability.

The bottom line is that if you have a weak password, hiding the length won't save you; if you have a strong password, hiding the length doesn't add any appreciable difficulty to the attacker.

@stevendaprano stevendaprano added 3.9 only security fixes and removed 3.8 (EOL) end of life labels Jun 6, 2019
@serhiy-storchaka serhiy-storchaka changed the title Adding the ability for getpass to print asterisks when passowrd is typed Adding the ability for getpass to print asterisks when password is typed Jun 10, 2019
@websurfer5
Copy link
Mannequin

websurfer5 mannequin commented Aug 8, 2020

This is easy to implement for Windows (as shown), but the unix implementation uses io.TextIOWrapper.readline() to get the password input. The unix implementation would have to be rewritten to provide the same functionality.

@akulakov
Copy link
Contributor

Unfortunately modern laptop keyboards have almost no key travel and barely any tactile feedback [*]. Users on such keyboards really do need feedback for each key pressed. Not providing an option for such feedback is in effect forcing users to choose maximally weak password.

[*] worse, a large proportion of MBP keyboards produced in the last few years have the notoriously bad 'butterfly' key design that occasionally duplicates and swallows keypresses. Yes, a trillion dollar company can't make a functional keyboard.

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
@thibaudcolas
Copy link

I’m surprised to see this opened for so long! Is this waiting on a design decision or pull request? Looking at the contribution guidelines for standard library changes, it seems the recommended course of action would be to create a new thread in Discourse under Ideas?

My two cents on the issue – it’s one of those we run into at every single workshop / training for newcomers to open source like Django Girls. There‘s no feedback when typing. In the case of Django, there’s no indication not to expect any feedback either. Lots of people use Windows and will have never come across that kind of prompt ever. So as mentioned above – this is indeed encouraging people to choose a password that’s simple to type.

@Stevoisiak
Copy link
Contributor

Stevoisiak commented Feb 8, 2023

I’m surprised to see this opened for so long! Is this waiting on a design decision or pull request? Looking at the contribution guidelines for standard library changes, it seems the recommended course of action would be to create a new thread in Discourse under Ideas?

I don't see much opposition to this change, but somebody would need to write an implementation that works on Unix.

@thibaudcolas
Copy link

Thanks for looking into this @Stevoisiak. Would it be acceptable to fix this for Windows users to start with, and change it for Unix users later?

From my perspective I see this has been opened for close to 6 years now even though people seem to think it’s a simple change for Windows. As a regular Django Girls coach this has basically been an issue for Windows users at every event I’ve ever coached at, where we run into this when creating a user account’s password for Django.

@Stevoisiak
Copy link
Contributor

Stevoisiak commented Dec 3, 2023

Thanks for looking into this @Stevoisiak. Would it be acceptable to fix this for Windows users to start with, and change it for Unix users later?

From my perspective I see this has been opened for close to 6 years now even though people seem to think it’s a simple change for Windows. As a regular Django Girls coach this has basically been an issue for Windows users at every event I’ve ever coached at, where we run into this when creating a user account’s password for Django.

I've also wanted to see this feature for a while. (I proposed a Windows implementation in 2019, which itself may have been based on a post from 2013), but implementing it only on Windows would likely lead to confusion. If this were officially implemented and a Python script calls getpass.getpass(show_asterisks=True), most reasonable users would expect their script to show asterisks regardless of whether it's running on Windows, Linux/Unix, Mac, or any other officially supported platform.

@thibaudcolas
Copy link

thibaudcolas commented Dec 15, 2023

Isn’t it the current implementation that defies people’s expectations? The current win_getpass function implements the behavior of getpass from Unix (to log in?), which never shows passwords, so is "as-expected" for Unix users of Python. But on Windows – password prompts definitely show asterisks, hence why it’s confusing the ones implemented with Python don’t?

@mjbear
Copy link

mjbear commented Oct 21, 2024

@thibaudcolas
As of November 2020 a package called maskpass exists.
(It hasn't seen a release since November 2022 so maybe this is an issue or maybe it isn't.)

https://pypi.org/project/maskpass/
https://github.com/FuturisticGoo/maskpass

Certainly there are benefits for the standard library having this functionality though. 😉
Hope this helps.

@thibaudcolas
Copy link

omg! Yes please :)

@mjbear
Copy link

mjbear commented Nov 14, 2024

Thanks for looking into this @Stevoisiak. Would it be acceptable to fix this for Windows users to start with, and change it for Unix users later?
From my perspective I see this has been opened for close to 6 years now even though people seem to think it’s a simple change for Windows. As a regular Django Girls coach this has basically been an issue for Windows users at every event I’ve ever coached at, where we run into this when creating a user account’s password for Django.

I've also wanted to see this feature for a while. (I proposed a Windows implementation in 2019, which itself may have been based on a post from 2013), but implementing it only on Windows would likely lead to confusion. If this were officially implemented and a Python script calls getpass.getpass(show_asterisks=True), most reasonable users would expect their script to show asterisks regardless of whether it's running on Windows, Linux/Unix, Mac, or any other officially supported platform.

💯% agree with @Stevoisiak that if the asterisks masking feature is added it should be across all platforms.

Would it be unnecessary scope creep to allow the masking character to be user-defined?
(The default mask character wouldn't do anything unless the boolean is True.)
(Checking the mask character string length < 2 as well.)

getpass.getpass(show_mask=True, mask_character='*')

# or a Unicode bullet character
getpass.getpass(show_mask=True, mask_character='•')

# or even more creative with Unicode (ok, yes, getting silly here)
getpass.getpass(show_mask=True, mask_character='🐧')

The simplest road forward is likely to go with asterisks as a "static" mask character first.
If a configurable masking character is blessed/allowed then make that phase two of changes.

@donBarbos
Copy link
Contributor

donBarbos commented Feb 23, 2025

looks like a good idea, I'm ready to start working on it and I would also like to suggest an idea to replace:

getpass.getpass(show_mask=True, mask_character='*')

to:

getpass.getpass(mask='*')

with mask=None by default, and it will be displayed if bool(mask) == True (if mask: ...)

I also want to ask are you sure that we need a check for the length of mask, because some emoji may have a longer length or the user may want to use their own custom string. I don't insist, I just think this restriction is far-fetched.

@mjbear
Copy link

mjbear commented Feb 23, 2025

to:

getpass.getpass(mask_character='*')

with mask_character=None by default, and it will be displayed if bool(mask_character) == True (if mask_character: ...)

I like the idea to default to None.

And yes - it can simply be:

if mask_character:
    # display mask character to stdout

I also want to ask are you sure that we need a check for the length of mask_character, because some emoji may have a longer length or the user may want to use their own custom string. I don't insist, I just think this restriction is far-fetched.

@donBarbos I wasn't thinking about multi-character emojis. 😉

Either way, since you bring it up, it seems reasonable to allow for flexibility. 👍

@picnixz picnixz removed the 3.9 only security fixes label Feb 24, 2025
hugovk pushed a commit that referenced this issue May 6, 2025
@JelleZijlstra
Copy link
Member

Looks like a PR was merged for this, so this could be closed.

However, there's an issue: the PR added the new parameter only to unix_getpass and win_getpass but not to fallback_getpass. Let's add it there too for consistency.

@picnixz
Copy link
Member

picnixz commented May 10, 2025

Right, it's also needed at runtime as getpass is set to fallback_getpass in case msvcrt fails to be imported.

@donBarbos
Copy link
Contributor

donBarbos commented May 10, 2025

sorry, I can send PR soon.
note: I left a comment about this #130496 (comment)

donBarbos added a commit to donBarbos/cpython that referenced this issue May 10, 2025
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 15, 2025
…k_getpass` (pythonGH-133849)

(cherry picked from commit d029a1a)

Co-authored-by: Semyon Moroz <[email protected]>
picnixz pushed a commit that referenced this issue May 15, 2025
…ck_getpass` (GH-133849) (#134053)

gh-77065: add missing parameter `echo_char` in `getpass.fallback_getpass` (GH-133849)
(cherry picked from commit d029a1a)

Co-authored-by: Semyon Moroz <[email protected]>
@picnixz picnixz closed this as completed May 15, 2025
donBarbos added a commit to donBarbos/cpython that referenced this issue May 15, 2025
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 15, 2025
…ss` (pythonGH-134058)

(cherry picked from commit 52a7a22)

Co-authored-by: Semyon Moroz <[email protected]>
picnixz pushed a commit that referenced this issue May 15, 2025
…ass` (GH-134058) (#134059)

gh-77065: Use `putwch` instead of `putch` in `getpass.win_getpass` (GH-134058)
(cherry picked from commit 52a7a22)

Co-authored-by: Semyon Moroz <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

9 participants