Cabal: `cabal upload` reveals your password as you type it on MSYS2

Created on 23 Nov 2016  路  5Comments  路  Source: haskell/cabal

AFAICT, this is not only Windows-specific, but also MSYS2-specific, as I can't reproduce this on PowerShell. Steps to reproduce:

$ git clone https://github.com/RyanGlScott/code-page
$ cd code-page/
$ cabal configure --enable-tests
Resolving dependencies...
Configuring code-page-0.1.1...
$ cabal upload -d
No documentation tarball specified. Building documentation tarball...
Running Haddock for code-page-0.1.1...
Running hscolour for code-page-0.1.1...
Preprocessing library code-page-0.1.1...
Preprocessing test suite 'tests' for code-page-0.1.1...
Preprocessing library code-page-0.1.1...
Haddock coverage:
  42% (  8 / 19) in 'System.Win32.CodePage'
  Missing documentation for:
    CodePage
    getConsoleCP
    getConsoleOutputCP
    setConsoleCP
    setConsoleOutputCP
    getACP
    getOEMCP
    codePageEncoding
    mkCodePageEncoding
    isValidCodePage
    stringToUnicode
 100% ( 14 / 14) in 'System.IO.CodePage'
Documentation created: .\dist\doc\html\code-page-0.1.1-docs\.\index.html,
.\dist\doc\html\code-page-0.1.1-docs\.\code-page.txt
Preprocessing test suite 'tests' for code-page-0.1.1...
Documentation tarball created: dist\code-page-0.1.1-docs.tar.gz
Hackage username: me
Hackage password: hunter2

It shows my Hackage password (hunter2, in the fake example above) as I type it, which is a bit unsettling.

windows bug

Most helpful comment

@ezyang @RyanGlScott Fwiw, I consider an "OK to depend on" test whether the library follows the PVP, has a reasonably small dependency footprint (or at least not more than we already depend on), and has an API that's not going to change drastically in the foreseeable future (i.e. infrequent major version bumps), and looks written & documented reasonably well, as that gives us some confidence the library is stable and won't bitrot that easily...

PS: ...and there's also the Fairbairn threshold to consider...

All 5 comments

I did some digging, and it turns out that hGetEcho and hSetEcho don't work properly on MinTTY (which Cygwin/MSYS2 use). A workaround is to use the stty command. For example, here is a program which will hide your password as you type it on MinTTY:

module Main (main) where

import Control.Exception (bracket, throw)
import Control.Monad (void)
import System.Exit (ExitCode(..))
import System.IO (hGetContents, hFlush, stdin, stdout)
import System.Process (StdStream(..), createProcess, shell,
                       std_in, std_out, waitForProcess)

stty :: String -> IO String
stty arg = do
  let stty = (shell $ "stty " ++ arg) {
        std_in  = UseHandle stdin
      , std_out = CreatePipe
      }
  (_, mbStdout, _, rStty) <- createProcess stty
  exStty <- waitForProcess rStty
  case exStty of
    e@ExitFailure{} -> throw e
    ExitSuccess     -> maybe (return "") hGetContents mbStdout

getSTTYState :: IO String
getSTTYState = stty "-g"

setSTTYState :: String -> IO ()
setSTTYState = void . stty

promptPassword :: IO ()
promptPassword = do
  putStr "Password: "
  hFlush stdout
  passwd <- bracket getSTTYState setSTTYState $ \_ -> do
    void $ stty "-echo"
    getLine
  putStrLn $ "Your password is " ++ passwd

main :: IO ()
main = promptPassword

Of course, this isn't at all portable, since it won't even work on cmd.exe/PowerShell. Perhaps we could take a cue from terminal-size and default to the strategy above whenever we're not on a Windows console? It's easy enough to detect when you're _not_ on a Windows console (just use System.IO.hIsTerminalDevice System.IO.stdin), but I don't know a reliable way to test if you're on MinTTY (other than check for the presence of the _ environmental variable, as GHC does, but this is obviously fallible). It might be safe to assume that if you're not on a Windows console, then stty is present.

I don't think it is unreasonable to use the same strategy as GHC (although I know sometimes GHCi gets it wrong), but IMO, any strategy which does the right thing when you run cabal from (1) mintty, (2) PowerShell, and (3) cmd.exe is good enough for me. Perhaps we can turn this into a little library that eventually other people can use.

In short, go for it! (You have commit bits right? :)

Very well, I've implemented these ideas in the echo library on Hackage. Now you can implement a MinTTY-compatible password prompt like this:

import System.IO.Echo

main :: IO ()
main = do
  foo <- withoutInputEcho getLine
  putStrLn $ "Your password is " ++ foo

So now the question becomes: should cabal-install add echo as a dependency, or should we inline the code from echo into cabal-install?

I think echo passes the "OK to depend on" test (whatever that is haha)!

@ezyang @RyanGlScott Fwiw, I consider an "OK to depend on" test whether the library follows the PVP, has a reasonably small dependency footprint (or at least not more than we already depend on), and has an API that's not going to change drastically in the foreseeable future (i.e. infrequent major version bumps), and looks written & documented reasonably well, as that gives us some confidence the library is stable and won't bitrot that easily...

PS: ...and there's also the Fairbairn threshold to consider...

Was this page helpful?
0 / 5 - 0 ratings