echo-0.1.4/0000755000000000000000000000000007346545000010623 5ustar0000000000000000echo-0.1.4/CHANGELOG.md0000644000000000000000000000067507346545000012444 0ustar0000000000000000### 0.1.4 [2021.02.17] * Use `Trustworthy`, not `Safe`, on GHC 7.2 to work around an old GHC bug. ### 0.1.3 [2017.01.30] * The MinTTY-detection portion of this library has been split off into `mintty`, on which `echo` now depends. ### 0.1.2 [2017.01.09] * Use more efficient implementation for `bracketInputEcho`. ### 0.1.1 [2017.01.07] * Use `System.Win32.MinTTY` from `Win32-2.5` or later if possible. ## 0.1 [2016.12.22] * First version. echo-0.1.4/LICENSE0000644000000000000000000000304707346545000011634 0ustar0000000000000000Copyright (c) 2016-2017, Ryan Scott All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Ryan Scott nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. echo-0.1.4/README.md0000644000000000000000000000313307346545000012102 0ustar0000000000000000# `echo` [![Hackage](https://img.shields.io/hackage/v/echo.svg)][Hackage: echo] [![Hackage Dependencies](https://img.shields.io/hackage-deps/v/echo.svg)](http://packdeps.haskellers.com/reverse/echo) [![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)][Haskell.org] [![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)][tl;dr Legal: BSD3] [![Linux build](https://github.com/RyanGlScott/echo/workflows/Haskell-CI/badge.svg)](https://github.com/RyanGlScott/echo/actions?query=workflow%3AHaskell-CI) [![Windows build](https://ci.appveyor.com/api/projects/status/a0dh9v7j995tjj2u?svg=true)](https://ci.appveyor.com/project/RyanGlScott/echo) [Hackage: echo]: http://hackage.haskell.org/package/echo "echo package on Hackage" [Haskell.org]: http://www.haskell.org "The Haskell Programming Language" [tl;dr Legal: BSD3]: https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29 "BSD 3-Clause License (Revised)" The `base` library exposes the `hGetEcho` and `hSetEcho` functions for querying and setting echo status, but unfortunately, neither function works with MinTTY consoles on Windows. This is a serious issue, since `hGetEcho` and `hSetEcho` are often used to disable input echoing when a program prompts for a password, so many programs will reveal your password as you type it on MinTTY! This library provides an alternative interface which works with both MinTTY and other consoles. An example is included which demonstrates how one might prompt for a password using this library. To build it, make sure to configure with the `-fexample` flag. echo-0.1.4/Setup.hs0000644000000000000000000000005607346545000012260 0ustar0000000000000000import Distribution.Simple main = defaultMain echo-0.1.4/echo.cabal0000644000000000000000000000542207346545000012530 0ustar0000000000000000name: echo version: 0.1.4 synopsis: A cross-platform, cross-console way to handle echoing terminal input description: The @base@ library exposes the @hGetEcho@ and @hSetEcho@ functions for querying and setting echo status, but unfortunately, neither function works with MinTTY consoles on Windows. This is a serious issue, since @hGetEcho@ and @hSetEcho@ are often used to disable input echoing when a program prompts for a password, so many programs will reveal your password as you type it on MinTTY! . This library provides an alternative interface which works with both MinTTY and other consoles. An example is included which demonstrates how one might prompt for a password using this library. To build it, make sure to configure with the @-fexample@ flag. homepage: https://github.com/RyanGlScott/echo bug-reports: https://github.com/RyanGlScott/echo/issues license: BSD3 license-file: LICENSE author: Ryan Scott maintainer: Ryan Scott stability: Provisional copyright: (C) 2016-2017 Ryan Scott category: System build-type: Simple extra-source-files: CHANGELOG.md, README.md cabal-version: >=1.10 tested-with: GHC == 7.0.4 , GHC == 7.2.2 , GHC == 7.4.2 , GHC == 7.6.3 , GHC == 7.8.4 , GHC == 7.10.3 , GHC == 8.0.2 , GHC == 8.2.2 , GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.2 source-repository head type: git location: https://github.com/RyanGlScott/echo flag example description: Build the bundled example program. default: False library exposed-modules: System.IO.Echo System.IO.Echo.Internal build-depends: base >= 4.3 && < 5 , process >= 1.0.1.1 && < 1.7 if os(windows) cpp-options: "-DWINDOWS" build-depends: mintty >= 0.1 && < 0.2 , Win32 >= 2 && < 3 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall executable password if !flag(example) buildable: False main-is: Password.hs build-depends: base >= 4.3 && < 5 , echo hs-source-dirs: example default-language: Haskell2010 ghc-options: -Wall echo-0.1.4/example/0000755000000000000000000000000007346545000012256 5ustar0000000000000000echo-0.1.4/example/Password.hs0000644000000000000000000000141507346545000014415 0ustar0000000000000000{-| Module: Password Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable A simple program which prompts you for your username and password (without leaking your password onto the screen as you type it). -} module Main (main) where import System.IO (hFlush, stdout) import System.IO.Echo (withoutInputEcho) main :: IO () main = do putLabel "Username: " username <- getLine putLabel "Password: " password <- withoutInputEcho getLine putStrLn "" putStrLn "-----------------------------------" putStrLn $ "Your username is: " ++ username putStrLn $ "Your password is: " ++ password where putLabel label = putStr label >> hFlush stdout echo-0.1.4/src/System/IO/0000755000000000000000000000000007346545000013205 5ustar0000000000000000echo-0.1.4/src/System/IO/Echo.hs0000644000000000000000000000137107346545000014421 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 704 {-# LANGUAGE Safe #-} #elif __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif {-| Module: System.IO.Echo Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable Exports functions that handle whether or not terminal input is handled in a way that should be portable across different platforms and consoles. -} module System.IO.Echo ( -- * Public interface withoutInputEcho, bracketInputEcho , getInputEchoState, setInputEchoState , EchoState, echoOff, echoOn -- * Alternative interface , getInputEcho, setInputEcho ) where import System.IO.Echo.Internal echo-0.1.4/src/System/IO/Echo/0000755000000000000000000000000007346545000014063 5ustar0000000000000000echo-0.1.4/src/System/IO/Echo/Internal.hs0000644000000000000000000001501707346545000016177 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 # if defined(WINDOWS) {-# LANGUAGE Trustworthy #-} # else # if __GLASGOW_HASKELL__ >= 704 {-# LANGUAGE Safe #-} # else {-# LANGUAGE Trustworthy #-} # endif # endif #endif {-| Module: System.IO.Echo.Internal Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable Exports functions that handle whether or not terminal input is handled in a way that should be portable across different platforms and consoles. Unlike "System.IO.Echo", this module exports internal functionality which, if used improperly, can lead to runtime errors. Make sure to read the documentation beforehand! -} module System.IO.Echo.Internal ( -- * Safe public interface withoutInputEcho, bracketInputEcho , getInputEchoState, setInputEchoState , echoOff, echoOn -- * Alternative (safe) interface , getInputEcho, setInputEcho -- * Unsafe STTY internals , EchoState(..), STTYSettings , getInputEchoSTTY, setInputEchoSTTY, sttyRaw -- * MinTTY , minTTY ) where import Control.Exception (bracket, throw) import Control.Monad (void) import Data.List (isInfixOf) import System.Exit (ExitCode(..)) import System.IO (hGetContents, hGetEcho, hSetEcho, stdin) import System.Process (StdStream(..), createProcess, shell, std_in, std_out, waitForProcess) #if defined(WINDOWS) import Graphics.Win32.Misc (getStdHandle, sTD_INPUT_HANDLE) import System.Console.MinTTY (isMinTTYHandle) import System.IO.Unsafe (unsafePerformIO) #endif -- | Return whether the terminal's echoing is on ('True') or off ('False'). -- -- Note that while this works on MinTTY, it is not as efficient as -- 'getInputEchoState', as it involves a somewhat expensive substring -- computation. getInputEcho :: IO Bool getInputEcho = if minTTY then do settings <- sttyRaw "-a" -- This assumes that other settings come after -- [-]echo in the output of `stty -a`. Luckily, this -- seems to be the case on every incarnation of -- MinTTY that I've tried. return $ not ("-echo " `isInfixOf` settings) else hGetEcho stdin -- | Return the terminal's current input 'EchoState'. getInputEchoState :: IO EchoState getInputEchoState = if minTTY then fmap MinTTY getInputEchoSTTY else fmap DefaultTTY $ hGetEcho stdin -- | Return all of @stty@'s current settings in a non-human-readable format. -- -- This function is not very useful on its own. Its greater purpose is to -- provide a compact 'STTYSettings' that can be fed back into -- 'setInputEchoState'. getInputEchoSTTY :: IO STTYSettings getInputEchoSTTY = sttyRaw "-g" -- | Set the terminal's echoing on ('True') or off ('False'). setInputEcho :: Bool -> IO () setInputEcho echo = if minTTY then setInputEchoSTTY $ ['-' | not echo] ++ "echo" else hSetEcho stdin echo -- | Set the terminal's input 'EchoState'. setInputEchoState :: EchoState -> IO () setInputEchoState (MinTTY settings) = setInputEchoSTTY settings setInputEchoState (DefaultTTY echo) = hSetEcho stdin echo -- | Create an @stty@ process and wait for it to complete. This is useful for -- changing @stty@'s settings, after which @stty@ does not output anything. -- -- @ -- setInputEchoSTTY = 'void' . 'sttyRaw' -- @ setInputEchoSTTY :: STTYSettings -> IO () setInputEchoSTTY = void . sttyRaw -- | Save the terminal's current input 'EchoState', perform a computation, -- restore the saved 'EchoState', and then return the result of the -- computation. -- -- @ -- bracketInputEcho action = 'bracket' 'getInputEchoState' 'setInputEchoState' (const action) -- @ bracketInputEcho :: IO a -> IO a bracketInputEcho action = bracket getInputEchoState setInputEchoState (const action) -- | Perform a computation with the terminal's input echoing disabled. Before -- running the computation, the terminal's input 'EchoState' is saved, and the -- saved 'EchoState' is restored after the computation finishes. -- -- @ -- withoutInputEcho action = 'bracketInputEcho' ('setInputEchoState' 'echoOff' >> action) -- @ withoutInputEcho :: IO a -> IO a withoutInputEcho action = bracketInputEcho (setInputEchoState echoOff >> action) -- | Create an @stty@ process, wait for it to complete, and return its output. sttyRaw :: String -> IO STTYSettings sttyRaw 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 -- | A representation of the terminal input's current echoing state. Example -- values include 'echoOff' and 'echoOn'. data EchoState = MinTTY STTYSettings -- ^ The argument to (or value returned from) an invocation of the @stty@ -- command-line utility. Most POSIX-like shells have @stty@, including -- MinTTY on Windows. Since neither 'hGetEcho' nor 'hSetEcho' work on -- MinTTY, when 'getInputEchoState' runs on MinTTY, it returns a value -- built with this constructor. -- -- However, native Windows consoles like @cmd.exe@ or PowerShell do not -- have @stty@, so if you construct an 'EchoState' with this constructor -- manually, take care not to use it with a native Windows console. | DefaultTTY Bool -- ^ A simple on ('True') or off ('False') toggle. This is returned by -- 'hGetEcho' and given as an argument to 'hSetEcho', which work on most -- consoles, with the notable exception of MinTTY on Windows. If you -- construct an 'EchoState' with this constructor manually, take care not -- to use it with MinTTY. deriving (Eq, Ord, Show) -- | Indicates that the terminal's input echoing is (or should be) off. echoOff :: EchoState echoOff = if minTTY then MinTTY "-echo" else DefaultTTY False -- | Indicates that the terminal's input echoing is (or should be) on. echoOn :: EchoState echoOn = if minTTY then MinTTY "echo" else DefaultTTY True -- | Settings used to configure the @stty@ command-line utility. type STTYSettings = String -- | Is the current process attached to a MinTTY console (e.g., Cygwin or MSYS)? minTTY :: Bool #if defined(WINDOWS) minTTY = unsafePerformIO $ do h <- getStdHandle sTD_INPUT_HANDLE isMinTTYHandle h {-# NOINLINE minTTY #-} #else minTTY = False #endif