Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a Perl script that prompts the user for a username and password. When the user types in the username, the name appears on the window, and that's ok. But when the user types the password, it too shows up on the window. I want to stop this to prevent shoulder surfing. How can I? Could I perhaps use Term::ReadKey? Thanks. Ideally, I would want the chars to show up as asterisks.

Replies are listed 'Best First'.
Re: Hiding password on commandline
by pg (Canon) on Jan 18, 2004 at 21:29 UTC

    You can use Term::ReadKey like this, and Term::ReadKey is portable.

    use Term::ReadKey; print "Password: "; ReadMode 'noecho'; my $line = <STDIN>; ReadMode 'original'; chomp($line);

    Or you can use Tk, if one of your future application is in Tk. Here is a demo:

    use strict; use Tk; use Tk::DialogBox; my $mw = new MainWindow(); my $dialog = $mw->DialogBox(-title => "Login", -buttons => ["OK", "Cancel"]); my $id = $dialog->add("Entry") ->pack(); my $passwd; my $password = $dialog->add("Entry", -show => "*", -textvariable => \$passwd) ->pack(); if ($dialog->Show() eq "OK") { print $passwd, "\n";#this line is only for demo } MainLoop;
Re: Hiding password on commandline
by fruiture (Curate) on Jan 18, 2004 at 19:56 UTC

    Term::ReadLine is what you're looking for.

    update: sorry, my fault, Term::ReadKey does what you want. I've even used it but confused it with Term::ReadLine. I'm lucky I didn't get downvoted for this post, although that would have been justified. So don't bother using ReadLine, use ReadKey!

    --
    http://fruiture.de
      Couldn't there be an easier way. Unfortunately, I've got to make due with the modules on the system and that's not one of them. I can't even install the module in my home directory. There's got to be an easier way.
        I can't even install the module in my home directory.
        How are you expected to develop programs that require passwords but yet you don't have authority enough in your own home directory to install the tools you need to program with? Seems really silly IMO.
        JamesNC
Re: Hiding password on commandline
by CountZero (Bishop) on Jan 18, 2004 at 20:27 UTC
    It is Term::InKey you are looking for. This is written in Perl (no compiled components) and only requires/imports Win32::Console. so if necessary, you could bodily include it in your script if you cannot install modules.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Hiding password on commandline
by JamesNC (Chaplain) on Jan 18, 2004 at 20:33 UTC
    Term::ReadKey is what you want to use. Please read my previous node here on PerlMonks 224221 for a code example of how to do this. The example handles backspaces and rubbing out the characters back to whatever promt you use.

    :-)
    JamesNC
      I like your code, but I am on solaris, not win32. I used your while loop, but I kept getting asterisks even after I pressed return. In other words, the while loop never ended. Here's what I am using:

      print " Enter your password:\n"; ReadMode 3; while($key = ReadKey()){ $val = ord $key; push @password, $key unless $val == 8 || $val == 13; last if $val == 13; print "*" unless $val == 8; }
      By the way, what does the 8 and 13 correspond to? I am sure that may have something to do with the problem.
        Have you tried to press the backspace key? You code works, sure, if your user never makes a typing mistake. I didn't see any handling of backspaces in your code.

        Okay, I've learned that ord returns the numeric ascii value of the first character of $key. But where can I find a listing of those values so I can figure out what 8 and 13 correspond to? Do ascii values remain the same across platforms?
Re: Hiding password on commandline
by Aragorn (Curate) on Jan 18, 2004 at 20:26 UTC
    Like you said, Term::ReadKey can be used for entering passwords. I think setting the terminal to cbreak mode and displaying the asterisks yourself can be easily done.

    Arjen

Re: Hiding password on commandline
by crabbdean (Pilgrim) on Jan 19, 2004 at 01:46 UTC
    Here is the code I use for such a purpose. It doesn't output asterisks, instead it outputs nothing at all to the screen and captures the keystrokes ... very similar to how Unix does it for logins.

    Enjoy!
    Dean

    use Term::ReadKey; print "\nEnter your password: "; ReadMode 'noecho'; $pass = ReadLine 0; chomp $pass; ReadMode 'normal'; print $pass,"\n";
      This is very similar to a question in perlfaq8, including the example code.

      However, reading the POD for Term::ReadKey, it says for ReadLine categorically:

      This call is currently not available under Windows.
      Curious... I wonder why not. Maybe it is and the POD is out of date. However, rolling some code to handle backspaces or <DEL>s by hand, or using Term::ReadLine to prompt and read the line, will give a truly portable solution.

      --
      I'm Not Just Another Perl Hacker

      Update: Corrected a typo. I was referring to the POD in Term::ReadKey, not Term::ReadLine - sorry for the confusion.

      Be sure to reverse the print and noecho:
      ReadMode 'noecho'; print "\nEnter your password: ";
      For typical uses, the difference isn't noticeable, but if you'd ever used Expect, you'd be quick to make that change. Don't prompt for the password until you've ensured it won't echo, or there's the possibility that the password will be entered (and echoed) before you disable echo.


      --isotope
Re: Hiding password on commandline
by ambrus (Abbot) on Jan 19, 2004 at 11:00 UTC

    If you're on a unix-derived system, you can turn off console echoing with system "stty", "-echo";, then read the string with <STDIN>=~/(.*)/ and $password= $1;, (this chops off newline, don't forget to do that) then turn back echoing with system "stty", "sane";. This won't print asterisks, however.

    Pity there's no &POSIX::getpass.

Re: Hiding password on commandline
by Sandy (Curate) on Jan 19, 2004 at 15:05 UTC
    I tried one of the perl modules, and it didn't work too well. Anyway, there was an example that I took from the camel book, plus stealing stuff from the module that didn't work the way I wanted it to. The result works on solaris. I think I tried it on Windows but I don't remember. (project put on hold temporarily.) I also haven't spent the time to make this particularly robust.