Запрос пароля в приложении командной строки на Haskell - PullRequest
25 голосов
/ 31 октября 2010

Следующая программа на Haskell запрашивает у пользователя пароль в терминале и продолжает, если он ввел правильный пароль:

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

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

К сожалению, пароль будет отображаться на экране по мере того, как пользователь его вводит,чего я хочу избежать.

Как я могу прочитать последовательность символов, которые печатает пользователь, без отображения на экране?Что эквивалентно getLine для этой цели?

Я нахожусь на MacOS X, но я хотел бы, чтобы это работало и на Windows и Linux.

Ответы [ 5 ]

36 голосов
/ 31 октября 2010

Сделайте это:

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
15 голосов
/ 01 ноября 2010

В System.Console.Haskeline есть getPassword.Возможно, это излишнее для вашего случая, но кто-то может найти это полезным.

Пример:

> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
pass:***
asd
9 голосов
/ 31 октября 2010

Можно отключить эхо в терминале с помощью модуля System.Posix.Terminal . Однако это требует поддержки 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, вам сначала нужно очистить буфер, иначе приглашение также будет заблокировано.

5 голосов
/ 16 ноября 2012

withEcho можно написать с чуть меньшим шумом:

withEcho :: Bool -> IO a -> IO a
withEcho echo action =
    bracket (hGetEcho stdin)
            (hSetEcho stdin)
            (const $ hSetEcho stdin echo >> action)
4 голосов
/ 01 ноября 2010

Как я уже говорил выше, я предлагаю вам использовать haskeline , который является полной библиотекой подсказок. Я с радостью использовал его для LambdaCalculator без нареканий.

...