How to hide password input from terminal in ruby script

I am new to ruby. I need to receive password as an input through gets command.

How do I hide the password input typed in the terminal, during gets call

36733 次浏览

有一个名为 高线的库,其工作原理如下:

require 'rubygems'
require 'highline/import'


password = ask("Enter password: ") { |q| q.echo = false }
# do stuff with password

来自@eclectic923的最佳答案:

require 'io/console'
password = STDIN.noecho(&:gets).chomp

对于1.9.3(及以上版本) ,这需要在代码中添加 require 'io/console'

原答案:

Ruby“ Password”是另一种选择。

也可以使用 core ruby。

$ ri IO.noecho


(from ruby core)
------------------------------------------------------------------------------
io.noecho {|io| }
------------------------------------------------------------------------------


Yields self with disabling echo back.


STDIN.noecho(&:gets)


will read and return a line without echo back.

For 1.9.3 (and above), this requires you adding require 'io/console' to your code.

require 'io/console'
text = STDIN.noecho(&:gets)

正如前面提到的,您可以使用 IO#noecho for Ruby > = 1.9。如果你想要支持1.8,你可以使用 read内置的 shell 函数:

begin
require 'io/console'
rescue LoadError
end


if STDIN.respond_to?(:noecho)
def get_password(prompt="Password: ")
print prompt
STDIN.noecho(&:gets).chomp
end
else
def get_password(prompt="Password: ")
`read -s -p "#{prompt}" password; echo $password`.chomp
end
end

现在获取密码就像下面这样简单:

@password = get_password("Enter your password here: ")

注意: 在上面使用 read的实现中,如果您(或 get_password的其他客户机)在提示符中传递特殊的 shell 字符(例如 $/"/'/etc) ,就会遇到麻烦。理想情况下,您应该在将提示字符串传递给 shell 之前对其进行转义。不幸的是,在 Ruby 1.8中 Shellwords不可用。幸运的是,自己很容易做到 backport the relevant bits(特别是 shellescape)。有了这个,你可以做这个小小的修改:

  def get_password(prompt="Password: ")
`read -s -p #{Shellwords.shellescape(prompt)} password; echo $password`.chomp
end

我在下面的评论中提到了使用 read -s -p的一些问题:

1.8的案子有点棘手,不允许 反斜杠,除非你按反斜杠两次: “反斜杠字符 “”可以用来去除下一个字符的任何特殊含义 的值中的字符 IFS 变量用于将该行拆分为单词。” 对于大多数小剧本来说可能没问题,但是你可能想要 对于更大的应用程序来说更加健壮的东西。

We can fix some of those problems by rolling up our sleeves and doing this the hard with stty(1). An outline of what we need to do:

  • 存储当前终端设置
  • 回声的转向
  • 打印提示并获取用户输入
  • 还原终端设置

当信号和/或异常中断时,我们还必须注意恢复终端设置。下面的代码将正确地处理作业控制信号(SIGINT/SIGTSTP/SIGCONT) ,同时仍然可以很好地处理任何当前的信号处理程序:

require 'shellwords'
def get_password(prompt="Password: ")
new_sigint = new_sigtstp = new_sigcont = nil
old_sigint = old_sigtstp = old_sigcont = nil


# save the current terminal configuration
term = `stty -g`.chomp
# turn of character echo
`stty -echo`


new_sigint = Proc.new do
`stty #{term.shellescape}`
trap("SIGINT",  old_sigint)
Process.kill("SIGINT", Process.pid)
end


new_sigtstp = Proc.new do
`stty #{term.shellescape}`
trap("SIGCONT", new_sigcont)
trap("SIGTSTP", old_sigtstp)
Process.kill("SIGTSTP", Process.pid)
end


new_sigcont = Proc.new do
`stty -echo`
trap("SIGCONT", old_sigcont)
trap("SIGTSTP", new_sigtstp)
Process.kill("SIGCONT", Process.pid)
end


# set all signal handlers
old_sigint  = trap("SIGINT",  new_sigint)  || "DEFAULT"
old_sigtstp = trap("SIGTSTP", new_sigtstp) || "DEFAULT"
old_sigcont = trap("SIGCONT", new_sigcont) || "DEFAULT"


print prompt
password = STDIN.gets.chomp
puts


password
ensure
# restore term and handlers
`stty #{term.shellescape}`


trap("SIGINT",  old_sigint)
trap("SIGTSTP", old_sigtstp)
trap("SIGCONT", old_sigcont)
end

对于 Ruby 版本1.8(或 Ruby < 1.9) ,我使用了@Charles 提到的 read shell 内建。

将代码放在刚好足以提示输入用户名和密码的位置,其中用户名将回显到屏幕上,而输入的密码将保持静音。

 userid = `read -p "User Name: " uid; echo $uid`.chomp
passwd = `read -s -p "Password: " password; echo $password`.chomp

Starting from Ruby version 2.3.0 you can use the IO#getpass method like this:

require 'io/console'
password = STDIN.getpass("Password:")

See the 通过 method in the Standard Library Documentation.