views:

3162

answers:

5

I have a Perl script that requires the user to enter a password. How can I echo only '*' in place of the character that the user types, as they type it?

I'm using Windows XP/Vista.

A: 

Have you tried storing the string (so that your program can still read it) and find out its length then create a string of the same length, but only use '*'?

The Sheek Geek
Replacing the character with * as they type it.
MatthieuF
+5  A: 

You should take a look at either Term::ReadKey or Win32::Console. You can use those modules to read the single key strokes and emit '*' or whathever.

innaM
+4  A: 

You can play with Term::ReadKey. Here is a very simple example, with some detection for backspace and delete key. I've tested it on Mac OS X 10.5 but according to the ReadKey manual it should work under Windows. The manual indicates that under Windows using non-blocking reads (ReadKey(-1)) will fail. That's why I'm using ReadKey(0) who's basically getc (more on getc in the libc manual).

#!/usr/bin/perl                                                                                                                                                                                                

use strict;                                                                                                                                                                                                    
use warnings;                                                                                                                                                                                                  
use Term::ReadKey;                                                                                                                                                                                             

my $key = 0;                                                                                                                                                                                                   
my $password = "";                                                                                                                                                                                             

print "\nPlease input your password: ";                                                                                                                                                                        

# Start reading the keys                                                                                                                                                                                       
ReadMode(4); #Disable the control keys                                                                                                                                                                         
while(ord($key = ReadKey(0)) != 10)                                                                                                                                                                            
# This will continue until the Enter key is pressed (decimal value of 10)                                                                                                                                      
{                                                                                                                                                                                                              
    # For all value of ord($key) see http://www.asciitable.com/                                                                                                                                                
    if(ord($key) == 127 || ord($key) == 8) {                                                                                                                                                                   
        # DEL/Backspace was pressed                                                                                                                                                                            
        #1. Remove the last char from the password                                                                                                                                                             
        chop($password);                                                                                                                                                                                       
        #2 move the cursor back by one, print a blank character, move the cursor back by one                                                                                                                   
        print "\b \b";                                                                                                                                                                                         
    } elsif(ord($key) < 32) {                                                                                                                                                                                  
        # Do nothing with these control characters                                                                                                                                                             
    } else {                                                                                                                                                                                                   
        $password = $password.$key;                                                                                                                                                                            
        print "*(".ord($key).")";                                                                                                                                                                              
    }                                                                                                                                                                                                          
}                                                                                                                                                                                                              
ReadMode(0); #Reset the terminal once we are done                                                                                                                                                              
print "\n\nYour super secret password is: $password\n";   
Pierre-Luc Simard
+1: Typo: 3th Line - non-bloging = non-blocking! .... cheers! ... I don't have enough reps to edit the post! :) requesting author/someone to modify it.
xk0der
@Manni - Cool! :) .. now fixing my own typo ... 3th = 3rd :D
xk0der
Thanks to both of you guys for helping making this answer better ;-)
Pierre-Luc Simard
This does not work under Windows. It works fine until you come to hit the enter key, when you have to press it four time for it to react. If you use ReadMode(2), then it works fine, but doesn't echo until you hit return. Not displaying the * may be an acceptable alternative
MatthieuF
+3  A: 

In the past I have used IO::Prompt for this.

use IO::Prompt;
my $password = prompt('Password:', -e => '*');
print "$password\n";
Peter Stuifzand
+2  A: 

If you don't want use any packages... Only for UNIX

system('stty','-echo');
chop($password=<STDIN>);
system('stty','echo');
jojo