lewis
lewis

Reputation: 141

echo "*" for passwords input in crystal-lang

Is there a way to echo "*" or some other character when processing passwords? Using STDIN.noecho works but doesn't provide any user feedback. console.cr only provides raw and noecho.

Thanks. Still looking...

Upvotes: 2

Views: 319

Answers (1)

jaitaiwan
jaitaiwan

Reputation: 310

You're on the right path with STDIN.noecho! Effectively what you needed to do is read from STDIN in raw mode and echo out * every time a key is pressed. Then you'd listen for backspace so you can move the cursor back one and replace with a space, then replace that space with a * when the user typed another character. You also needed to check for the enter and Control+C being pressed as the terminal captures and gives that all to you in raw mode.

I've based this off the bash implementation found here in the second comment by user Alfe. Update: Changed the code to be inside blocks to hopefully eliminate possible terminal issues.

# Fix for crystal bug
STDIN.blocking = true

# STDIN chars without buffering
STDIN.raw do
    # Dont echo out to the terminal
    STDIN.noecho do
        final_password = ""
        while char = STDIN.read_char
            # If we have a backspace
            if char == '\u{7f}'
                # Move the cursor back 1 char
                if final_password != ""
                    STDOUT << "\b \b"
                    STDOUT.flush
                    final_password = final_password[0...-1]
                end
                next
            elsif char == '\r'
                # Enter was pressed we're finished!
                break
            elsif char == '\u{3}'
                # Control + C was pressed. Get outta here
                Process.exit 0
            elsif char.ascii_control?
                # A Control + [] char was pressed. Not valid for a password
                next
            end

            STDOUT << "*"
            STDOUT.flush
            final_password += char
        end

        puts final_password
    end
end

# Resetting when finished
STDIN.blocking = false

If this helps you please be sure to mark this as answered!

Upvotes: 3

Related Questions