Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Perl prompt for a password without showing it in the terminal?

How can I prompt a terminal user for a password without showing the password in the terminal? There's a similar question for How can I enter a password using Perl and replace the characters with '*'?, but the answers appear to be out-of-date or broken.

I was looking for answers to this question and wasn't satisfied with the questions on later pages of results that had the answer tangentially to other concerns.

Also, perlfaq8 has an example that is incomplete (oh, and who used to maintain that ;).

 use Term::ReadKey;
 ReadMode('noecho');
 my $password = ReadLine(0);

When you do that without resetting the terminal, nothing else echos! Oops!

I'm also looking for newer answers or modules we can provide to people who want to do this.

like image 775
brian d foy Avatar asked Sep 30 '16 22:09

brian d foy


2 Answers

To use Term::ReadKey, this works:

sub prompt_for_password {
    require Term::ReadKey;

    # Tell the terminal not to show the typed chars
    Term::ReadKey::ReadMode('noecho');

    print "Type in your secret password: ";
    my $password = Term::ReadKey::ReadLine(0);

    # Rest the terminal to what it was previously doing
    Term::ReadKey::ReadMode('restore');

    # The one you typed didn't echo!
    print "\n";

    # get rid of that pesky line ending (and works on Windows)
    $password =~ s/\R\z//;

    # say "Password was <$password>"; # check what you are doing :)

    return $password;
}
like image 139
4 revs, 2 users 98% Avatar answered Sep 28 '22 09:09

4 revs, 2 users 98%


You can also use IO::Prompter:

$ perl -MIO::Prompter -wE '$pass = prompt("Password: ", -echo => "*"); $pass =~ s/\R\z//; say $pass'

It is probably overkill for just asking for the password, but it is useful if you need to elicit other types of user input as well. Note that you do need Term::ReadKey for the password masking function to work. Unfortunately, the module does not warn you about this at build time. You will know you are in this situation if the one-liner above generates the warning:

Warning: next input will be in plaintext

The prompt() subroutine was called with the -echo flag, but the Term::ReadKey module was not available to implement this feature. The input will proceed as normal, but this warning is issued to ensure that the user doesn't type in something secret, expecting it to remain hidden, which it won't.

How that warning message corresponds to the meaning given in the explanation is beyond me, but, oh well.

Note that on Windows the module leaves a CR at the end of the input string which chomp does not remove (because it is looking for a CRLF sequence). That's why I use \R in the example above. See RT #118255.

like image 30
Sinan Ünür Avatar answered Sep 28 '22 09:09

Sinan Ünür