2

I'm writing a CLI in elixir, how can I prompt the user for a password, without displaying the input in the terminal?

Baruch
  • 1,133
  • 10
  • 18

3 Answers3

2

You can accomplish this using the Erlang :io.get_password() function, e.g.

IO.write("What is your password?")

password = :io.get_password()
           |> List.to_string()

Note that IO.write/1 is preferable to using Mix.shell().info() for the prompt because the info function will add a newline, which is usually not what you want in a prompt.

Also be advised that :io.get_password() returns input as a charlist, so you will probably want to convert it to a binary as demonstrated above.

I wrote a package that utilizes the above technique: https://hex.pm/packages/cowrie

Everett
  • 8,746
  • 5
  • 35
  • 49
0

Apparently there are some problems with this. Currently the best solution seems to be to repeatedly clear the input in a loop, as implemented in the Hex package manager:

https://github.com/hexpm/hex/blob/1523f44e8966d77a2c71738629912ad59627b870/lib/mix/hex/utils.ex#L32-L58

Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • Fair enough. There might not be a good platform independent way to do it via the VM. – Baruch Jun 09 '16 at 11:03
  • 1
    You might also have some luck using `:io.get_password` from OTP, but I remember that I couldn't get it to work properly. I think it follows a similar approach. – Patrick Oscity Jun 09 '16 at 13:31
0

Just borrow the functionality directly from Mix.Tasks.Hex, by writing some code like the following,

some_pass = 
  Mix.Tasks.Hex.password_get("Password: ") 
  |> String.replace_trailing("\n","")

And if you are requesting the password in a task, and don't want to keep asking for it over and over, you can save it in an environment variable like this,

:os.putenv(String.to_charlist("SECRET_PASSWORD"), String.to_charlist(some_pass))

And, of course, retrieve it with:

System.get_env("SECRET_PASSWORD")
chava
  • 379
  • 4
  • 7