Demander un mot de passe dans l'application de ligne de commande Haskell

Le programme Haskell suivant invite l'utilisateur à entrer un mot de passe dans le terminal et continue s'il a entré le bon:

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

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

Malheureusement, le mot de passe apparaîtra à l'écran lorsque l'utilisateur le Tapera, ce que je veux éviter.

Comment puis-je lire une séquence de caractères que les utilisateurs sans avoir à l'afficher sur l'écran? Quel est l'équivalent de getLine à cet effet?

Je suis sur MacOS X, mais je voudrais que cela fonctionne sur Windows et Linux, trop.

23
demandé sur Heinrich Apfelmus 2010-10-31 21:09:31

5 réponses

Essayez le suivant:

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
32
répondu Yuras 2010-11-01 07:08:10

, Il est un getPassword dans System.Console.Haskeline. C'est probablement un excès pour votre cas, mais quelqu'un peut le trouver utile.

Un exemple:

> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
pass:***
asd
13
répondu Daniel Velkov 2010-11-01 06:47:50

, Il est possible de désactiver l'écho dans le terminal avec le System.Posix.Terminal module. Cependant, cela nécessite un support POSIX, donc peut ne pas fonctionner sur Windows (je n'ai pas vérifié).

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

Notez que le stdin est mis en mémoire tampon, donc si vous utilisez putStr "Password:" au lieu de putStrLn, vous devez d'abord vider le tampon, sinon l'invite sera également inhibée.

9
répondu kennytm 2010-10-31 18:29:58

WithEcho peut être écrit avec un peu moins de noice:

withEcho :: Bool -> IO a -> IO a
withEcho echo action =
    bracket (hGetEcho stdin)
            (hSetEcho stdin)
            (const $ hSetEcho stdin echo >> action)
5
répondu 1chb 2012-11-15 23:31:01

Comme je l'ai commenté ci-dessus, je vous suggère d'utiliser haskeline, qui est un invite de la bibliothèque. Je l'ai utilisé heureusement pour LambdaCalculator sans se plaindre.

4
répondu Thomas M. DuBuisson 2010-11-01 17:06:10