代码之家  ›  专栏  ›  技术社区  ›  Heinrich Apfelmus

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

  •  24
  • Heinrich Apfelmus  · 技术社区  · 15 年前

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

    main = do
        putStrLn "Password:"
        password <- getLine
    
        case hash password `member` database of
            False -> putStrLn "Unauthorized use!"
            True  -> do
                     ...
    

    不幸的是,当用户输入密码时,密码会出现在屏幕上,我想避免这样做。

    如何读取用户键入的字符序列而不在屏幕上显示?相当于 getLine 为了这个目的?

    我在MacOSX上,但我希望这个也能在Windows和Linux上工作。

    5 回复  |  直到 15 年前
        1
  •  38
  •   Aaron Hall    7 年前

    执行以下操作:

    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
    
        2
  •  15
  •   Daniel    15 年前

    有一个 getPassword 在里面 System.Console.Haskeline . 也许这对你的案子有点过分,但也许有人会觉得有用。

    > runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
    pass:***
    asd
    
        3
  •  9
  •   kennytm    15 年前

    可以使用 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 ,需要先刷新缓冲区,否则提示也会被禁止。

        4
  •  6
  •   castletheperson    6 年前

    withEcho可以用更小的噪音来写:

    withEcho :: Bool -> IO a -> IO a
    withEcho echo action =
        bracket (hGetEcho stdin)
                (hSetEcho stdin)
                (const $ hSetEcho stdin echo >> action)
    
        5
  •  4
  •   Thomas M. DuBuisson    15 年前

    如上所述,我建议您使用 haskeline LambdaCalculator 没有抱怨。