在Haskell命令行应用程序中提示输入密码

时间:2010-10-31 18:09:32

标签: command-line haskell passwords terminal

以下Haskell程序会提示用户输入终端中的密码,如果他输入了正确的密码则继续:

main = do
    putStrLn "Password:"
    password <- getLine

    case hash password `member` database of
        False -> putStrLn "Unauthorized use!"
        True  -> do
                 ...

不幸的是,密码会在用户输入时显示在屏幕上,我想避免使用。

  

如何在不显示屏幕的情况下阅读用户输入的一系列字符?为此目的,getLine的等价物是什么?

我使用的是MacOS X,但我希望这也适用于Windows和Linux。

6 个答案:

答案 0 :(得分:34)

这样做:

module Main
where

import System.IO
import Control.Exception

main :: IO ()
main = getPassword >>= putStrLn . ("Entered: " ++)

getPassword :: IO String
getPassword = do
  putStr "Password: "
  hFlush stdout
  pass <- withEcho False getLine
  putChar '\n'
  return pass

withEcho :: Bool -> IO a -> IO a
withEcho echo action = do
  old <- hGetEcho stdin
  bracket_ (hSetEcho stdin echo) (hSetEcho stdin old) action

答案 1 :(得分:13)

System.Console.Haskeline中有一个getPassword。可能这对你的案子来说太过分了,但有人可能觉得它很有用。

一个例子:

> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
pass:***
asd

答案 2 :(得分:9)

可以使用the System.Posix.Terminal module禁用终端中的回显。但是,这需要POSIX支持,因此可能无法在Windows上运行(我没有检查)。

import System.Posix.Terminal 
import System.Posix.IO (stdInput)

getPassword :: IO String
getPassword = do
    tc <- getTerminalAttributes stdInput
    setTerminalAttributes stdInput (withoutMode tc EnableEcho) Immediately
    password <- getLine
    setTerminalAttributes stdInput tc Immediately
    return password

main = do
    putStrLn "Password:"
    password <- getPassword
    putStrLn "Name:"
    name <- getLine
    putStrLn $ "Your password is " ++ password ++ " and your name is " ++ name

请注意,stdin是行缓冲的,因此如果使用putStr "Password:"而不是putStrLn,则需要先刷新缓冲区,否则也会禁止提示。

答案 3 :(得分:5)

带有Echo的

可以用更少的噪音写出来:

withEcho :: Bool -> IO a -> IO a
withEcho echo action =
    bracket (hGetEcho stdin)
            (hSetEcho stdin)
            (const $ hSetEcho stdin echo >> action)

答案 4 :(得分:4)

正如我上面评论的那样,我建议您使用haskeline,这是一个完整的提示库。我很高兴地使用LambdaCalculator而没有任何抱怨。

答案 5 :(得分:0)

我发现在读取密码时这很有用:

import Control.Exception
import System.IO

withoutEcho :: IO a -> IO a
withoutEcho action =
  finally (hSetEcho stdin False >> action) (hSetEcho stdin True)